gdb:检查堆栈和小端澄清

Posted

技术标签:

【中文标题】gdb:检查堆栈和小端澄清【英文标题】:gdb: examine stack and little endian clarification 【发布时间】:2015-07-19 23:44:46 【问题描述】:

我正在研究程序的内存布局。我正在使用 gdb 检查小端(intel x86_64)Linux(32 位)机器中的堆栈。但是,对于这个处理器和 gdb,我无法理解 big-endian 和 little-endian 的概念。

我的示例程序是:

1   #include<stdio.h>
2   
3   int main(int argc, char **argv) 
4       int a = 5;
5       char b[] = "ABCDEFGH";
6   
7       return 0;
8   

                       [Code - 1]

以下指令序列在 gdb 中执行。

(gdb) b 7
Breakpoint 1 at 0x8048434: file args.c, line 7.
(gdb) r
Breakpoint 1, main (argc=1, argv=0xbffff4f4) at args.c:7
7       return 0;

(gdb) x/20xw $esp
0xbffff410: 0x0011e0c0  0x08049ff4  0xbffff448  0xbffff4f4
0xbffff420: 0x00284324  0x00283ff4  0x08048470  0x00000005
0xbffff430: 0x4115d4a5  0x45444342  0x00484746  0x6a078d00
0xbffff440: 0x08048470  0x00000000  0xbffff4c8  0x00144bd6
0xbffff450: 0x00000002  0xbffff4f4  0xbffff500  0xb7fff858


                            [Code - 2]

最初,我很困惑上面堆栈中的内存地址0xbffff430是否包含值0x410xa5。所以我检查了从地址0xbffff433开始的堆栈。

(gdb) x/8xw 0xbffff433
0xbffff433: 0x44434241  0x48474645  0x078d0000  0x0484706a
0xbffff443: 0x00000008  0xfff4c800  0x144bd6bf  0x00000200

                             [code - 3]

从上面的输出可以看出,地址0xbffff433 包含值0x41。因此,地址0xbffff430 包含值0xa5。因此我们可以得出结论,gcc中的内存地址按以下顺序显示:-

0xbffff433: [0xbffff436][0xbffff435][0xbffff434][0xbffff433]  [0xbffff43a] [0xbffff439][0xbffff438][0xbffff437]
                D           C          B           A             H              G              F          E

但是,由于 intel x86_64 是 little-endian,据我了解,字符数组的存储顺序(MSB 在最小地址)应该如下:-

0xbffff433: [0xbffff436][0xbffff435][0xbffff434][0xbffff433]  [0xbffff43a][0xbffff439][0xbffff438][0xbffff437]
                 A           B         C           D             E           F           G           H

Q (a):能否请大家解释一下我哪里错了?

Q(b):此外,从上面的[code 2]我们可以看到变量a的值存储在地址0xbffff42c。变量a 的值为:0x00000005。这里 LSB 也是存储在最小的内存地址。

Q (c):但是,Q (a) 和 (b) 的问题在存储地址时并未显现。例如,从下面的code - 4,我们可以检查在地址0xbffff448 处存储了EBP(0xbffff4c8

(gdb) x/4xw $ebp
0xbffff448: 0xbffff4c8  0x00144bd6  0x00000002  0xbffff4f4

清晰可见,地址按如下顺序存储:-

0xbffff448: [0xbffff44b][0xbffff44a][0xbffff449][0xbffff448]
                0xbf        0xff        0xf4        0xc8

注意:1)我在 ubuntu-10.04-desktop-i386 的虚拟机上尝试了上面的代码。我使用以下代码确认了我的机器的字节顺序:

#include <stdio.h>
int main() 

   unsigned int i = 1;
   char *c = (char*)&i;
   if (*c)    
       printf("Little endian");
   else
       printf("Big endian");
   getchar();
   return 0;

2)我也检查了以下线程Is GDB interpreting the memory address correctly?,但我仍然无法理解这个概念。

谢谢。

【问题讨论】:

x86 上 C 中的 char 类型为 1 字节长。无需考虑字节顺序。 x86 上的 C 中的数组从低地址到高地址。使用 x/9xb bx/9cb b 查看 char 数组的前 9 个元素 b。 x/xw 中的 w 表示“打印 4 字节字”。 感谢您的解释!您能否将其发布为答案,以便我接受? 一个好问题,我不太明白答案。您能否提供更多信息? 【参考方案1】:

x86 上 C 中的 char 类型为 1 个 8 位字节长,对齐为 1 个字节;无需考虑字节顺序。 x86 上的 C 中的数组从低地址到高地址。 wx/xw 中的意思是“打印 4 字节字”,这对于显示 32 位整数和(在 32 位系统上)指针来说很好,但对于 chars 或 char 数组来说不是很好。使用 x/9xb bx/9cb b 查看 char 数组 b 的前 9 个元素,显示为字节。

【讨论】:

以上是关于gdb:检查堆栈和小端澄清的主要内容,如果未能解决你的问题,请参考以下文章

网络编程中的大端和小端

单片机笔记关于MCU芯片大端模式和小端模式的问题

单片机笔记关于MCU芯片大端模式和小端模式的问题

寄存器值问题的小端表示

为什么在使用GDB检查时,某些局部变量未在相应的堆栈帧中列出?

GDB 调试器使用手冊