gdb:检查堆栈和小端澄清
gdb: examine stack and little endian clarification
我正在研究一个程序的内存布局。我正在使用 gdb 检查小端 (intel x86_64) Linux(32 位)机器中的堆栈。但是,我无法理解big-endian和little-endian的概念w.r.t这个处理器和gdb。
我的示例程序是:
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
到底是0x41
还是0xa5
。所以我检查了从地址 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
然而,由于英特尔 x86_64 是小端,根据我的理解,字符数组的存储顺序(最小地址的 MSB)应该如下:-
0xbffff433: [0xbffff436][0xbffff435][0xbffff434][0xbffff433] [0xbffff43a][0xbffff439][0xbffff438][0xbffff437]
A B C D E F G H
问(a):有人能解释一下我错在哪里吗?
Q(b):此外,从上面的[code 2]
我们可以看出变量a
的值存储在地址0xbffff42c
。变量 a
的值为:0x00000005
。这里也将 LSB 存储在最小的内存地址。
问(c):但是,问(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个8位字节长,1字节对齐;没有字节顺序需要考虑。 x86 上 C 中的数组从低地址到高地址。 x/xw
中的 w
表示 "print 4-byte words",这适用于显示 32 位整数和(在 32 位系统上)指针,但不适用于字符或字符数组。使用 x/9xb b
或 x/9cb b
查看字符数组 b
的前 9 个元素,显示为字节。
我正在研究一个程序的内存布局。我正在使用 gdb 检查小端 (intel x86_64) Linux(32 位)机器中的堆栈。但是,我无法理解big-endian和little-endian的概念w.r.t这个处理器和gdb。
我的示例程序是:
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
到底是0x41
还是0xa5
。所以我检查了从地址 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
然而,由于英特尔 x86_64 是小端,根据我的理解,字符数组的存储顺序(最小地址的 MSB)应该如下:-
0xbffff433: [0xbffff436][0xbffff435][0xbffff434][0xbffff433] [0xbffff43a][0xbffff439][0xbffff438][0xbffff437]
A B C D E F G H
问(a):有人能解释一下我错在哪里吗?
Q(b):此外,从上面的[code 2]
我们可以看出变量a
的值存储在地址0xbffff42c
。变量 a
的值为:0x00000005
。这里也将 LSB 存储在最小的内存地址。
问(c):但是,问(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个8位字节长,1字节对齐;没有字节顺序需要考虑。 x86 上 C 中的数组从低地址到高地址。 x/xw
中的 w
表示 "print 4-byte words",这适用于显示 32 位整数和(在 32 位系统上)指针,但不适用于字符或字符数组。使用 x/9xb b
或 x/9cb b
查看字符数组 b
的前 9 个元素,显示为字节。