日期:2014-05-16  浏览次数:20832 次

《coredump问题原理探究》Linux x86版5.2节C风格数据结构内存布局之基本数据类型

在C语言中,基本的数据类型无非是char, short, int,long, float, double及相应的指针。那么它们在内存里是怎样存放的,在汇编指令里显示怎么样的特征呢?在这里就分别来探究一下char, short, int, long, float, double的特征。

先用一个例子来看一下char的特征:

 #include <stdio.h>
 int main()
 {
     char c1 = 'a';
     char c2 = 'b';
     char c3 = 'c';
	 
     printf( "addresses of c1 to c3 are (%x, %x, %x)\n",
             &c1, &c2, &c3 );
	 
     char* p = &c1;
     *p++;
     p = &c2;
     (*p) += 2;
     p = &c3;
     (*p) += 3;
	 
     printf( "address and value of p is ( %x, %c )\n", &p, *p );
 
     return 0;
 }                               

编译它:

g++ -o xuzhina_dump_c5_s1 xuzhina_dump_c5_s1.cpp

用gdb打开它,反汇编这个函数:

(gdb) disassemble main
Dump of assembler code for function main:
   0x08048570 <+0>:     push   %ebp
   0x08048571 <+1>:     mov    %esp,%ebp
   0x08048573 <+3>:     and    $0xfffffff0,%esp
   0x08048576 <+6>:     sub    $0x20,%esp
   0x08048579 <+9>:     movb   $0x61,0x1f(%esp)
   0x0804857e <+14>:    movb   $0x62,0x1e(%esp)
   0x08048583 <+19>:    movb   $0x63,0x1d(%esp)
   0x08048588 <+24>:    lea    0x1d(%esp),%eax
   0x0804858c <+28>:    mov    %eax,0xc(%esp)
   0x08048590 <+32>:    lea    0x1e(%esp),%eax
   0x08048594 <+36>:    mov    %eax,0x8(%esp)
   0x08048598 <+40>:    lea    0x1f(%esp),%eax
   0x0804859c <+44>:    mov    %eax,0x4(%esp)
   0x080485a0 <+48>:    movl   $0x80486c4,(%esp)
   0x080485a7 <+55>:    call   0x8048440 <printf@plt>

   0x080485ac <+60>:    lea    0x1f(%esp),%eax

   0x080485b0 <+64>:    mov    %eax,0x18(%esp)
   0x080485b4 <+68>:    mov    0x18(%esp),%eax
   0x080485b8 <+72>:    add    $0x1,%eax
   0x080485bb <+75>:    mov    %eax,0x18(%esp)
   0x080485bf <+79>:    lea    0x1e(%esp),%eax
   0x080485c3 <+83>:    mov    %eax,0x18(%esp)
   0x080485c7 <+87>:    mov    0x18(%esp),%eax
   0x080485cb <+91>:    mov    0x18(%esp),%edx
   0x080485cf <+95>:    movzbl (%edx),%edx
   0x080485d2 <+98>:    add    $0x2,%edx
   0x080485d5 <+101>:   mov    %dl,(%eax)
   0x080485d7 <+103>:   lea    0x1d(%esp),%eax
   0x080485db <+107>:   mov    %eax,0x18(%esp)
   0x080485df <+111>:   mov    0x18(%esp),%eax
   0x080485e3 <+115>:   mov    0x18(%esp),%edx
   0x080485e7 <+119>:   movzbl (%edx),%edx
   0x080485ea <+122>:   add    $0x3,%edx
   0x080485ed <+125>:   mov    %dl,(%eax)
   0x080485ef <+127>:   mov    0x18(%esp),%eax
   0x080485f3 <+131>:   movzbl (%eax),%eax
   0x080485f6 <+134>:   movsbl %al,%eax
   0x080485f9 <+137>:   mov    %eax,0x8(%esp)
   0x080485fd <+141>:   lea    0x18(%esp),%eax
   0x08048601 <+145>:   mov    %eax,0x4(%esp)
   0x08048605 <+149>:   movl   $0x80486ec,(%esp)
   0x0804860c <+156>:   call   0x8048440 <printf@plt>

   0x08048611 <+161>:   mov    $0x0,%eax

   0x08048616 <+166>:   jmp    0x8048620 <main+176>
   0x08048618 <+168>:   mov    %eax,(%esp)
   0x0804861b <+171>:   call   0x8048460 <_Unwind_Resume@plt>
   0x08048620 <+176>:   leave  
   0x08048621 <+177>:   ret    
End of assembler dump.

在第一次 printf的调用后打断点,即:

   0x080485ac <+60>:    lea    0x1f(%esp),%eax

然后运行一下,看程序的输出:

(gdb) tbreak *0x080485ac
Temporary breakpoint 1 at 0x80485ac
(gdb) r
Starting program: /home/buckxu/work/5/1/xuzhina_dump_c5_s1 
addresses of c1 to c3 are (bffff47f, bffff47e, bffff47d)

Temporary breakpoint 1, 0x080485ac in main ()
(gdb) i r ebp esp
ebp            0xbffff488       0xbffff488
esp            0xbffff460       0xbffff460 
(gdb