《coredump问题原理探究》Linux x86版5.5节C风格数据结构内存布局之基本数据类型构成的结构体
在C语言里,结构体是不同类型数据结构的集合。由于结构体比较复杂,分为几种情况来讨论:
1. 成员全是由基本数据类型构成
2. 成员有基本数据类型,也有其它结构体构成,构成成员的结构体是1,2两种情况。
3. 结构体构成的数组
这一节先讨论第一种情况.要了解这种类型结构体的内存布局,首先要知道成员在内存里是如何排序,及各个成员在内存占的大小。先看一个例子
(gdb) disassemble equal Dump of assembler code for function _Z5equalP24xuzhina_dump_c05_s3_struS0_: 0x08048470 <+0>: push %ebp 0x08048471 <+1>: mov %esp,%ebp 0x08048473 <+3>: mov 0x8(%ebp),%eax 0x08048476 <+6>: movzbl (%eax),%edx 0x08048479 <+9>: mov 0xc(%ebp),%eax 0x0804847c <+12>: movzbl (%eax),%eax 0x0804847f <+15>: cmp %al,%dl 0x08048481 <+17>: je 0x804848a <_Z5equalP24xuzhina_dump_c05_s3_struS0_+26> 0x08048483 <+19>: mov $0x0,%eax 0x08048488 <+24>: jmp 0x80484c0 <_Z5equalP24xuzhina_dump_c05_s3_struS0_+80> 0x0804848a <+26>: mov 0x8(%ebp),%eax 0x0804848d <+29>: movzwl 0x2(%eax),%edx 0x08048491 <+33>: mov 0xc(%ebp),%eax 0x08048494 <+36>: movzwl 0x2(%eax),%eax 0x08048498 <+40>: cmp %ax,%dx 0x0804849b <+43>: je 0x80484a4 <_Z5equalP24xuzhina_dump_c05_s3_struS0_+52> 0x0804849d <+45>: mov $0x0,%eax 0x080484a2 <+50>: jmp 0x80484c0 <_Z5equalP24xuzhina_dump_c05_s3_struS0_+80> 0x080484a4 <+52>: mov 0x8(%ebp),%eax 0x080484a7 <+55>: mov 0x4(%eax),%edx 0x080484aa <+58>: mov 0xc(%ebp),%eax 0x080484ad <+61>: mov 0x4(%eax),%eax 0x080484b0 <+64>: cmp %eax,%edx 0x080484b2 <+66>: je 0x80484bb <_Z5equalP24xuzhina_dump_c05_s3_struS0_+75> 0x080484b4 <+68>: mov $0x0,%eax 0x080484b9 <+73>: jmp 0x80484c0 <_Z5equalP24xuzhina_dump_c05_s3_struS0_+80> 0x080484bb <+75>: mov $0x1,%eax 0x080484c0 <+80>: pop %ebp 0x080484c1 <+81>: ret End of assembler dump.(gdb) disassemble mainDump of assembler code for function main: 0x080484c2 <+0>: push %ebp 0x080484c3 <+1>: mov %esp,%ebp 0x080484c5 <+3>: sub $0x18,%esp 0x080484c8 <+6>: movb $0x61,-0x8(%ebp) 0x080484cc <+10>: movw $0xa,-0x6(%ebp) 0x080484d2 <+16>: movl $0x14,-0x4(%ebp) 0x080484d9 <+23>: movb $0x61,-0x10(%ebp) 0x080484dd <+27>: movw $0xa,-0xe(%ebp) 0x080484e3 <+33>: movl $0x15,-0xc(%ebp) 0x080484ea <+40>: lea -0x10(%ebp),%eax 0x080484ed <+43>: mov %eax,0x4(%esp) 0x080484f1 <+47>: lea -0x8(%ebp),%eax 0x080484f4 <+50>: mov %eax,(%esp) 0x080484f7 <+53>: call 0x8048470 <_Z5equalP24xuzhina_dump_c05_s3_struS0_> 0x080484fc <+58>: test %al,%al 0x080484fe <+60>: je 0x8048507 <main+69> 0x08048500 <+62>: mov $0x0,%eax 0x08048505 <+67>: jmp 0x804850c <main+74> 0x08048507 <+69>: mov $0x1,%eax 0x0804850c <+74>: leave 0x0804850d <+75>: ret End of assembler dump.
从equal函数的汇编代码可以看到,
1. 结构体都是一个基地址,从它三个成员的寻址看到,都是先把基地址放到某寄存器里。如mov 0x8(%ebp),%eax
2. 结构体成员的访问,都在基址基础上加上前面所有成员的大小。如成员c,前面a和b占四个字节,所以就有“mov 0x8(%ebp),%eax”, “mov 0x4(%eax),%edx”.
3. 每个成员与基址的偏移量,不是构成一个等差数列。