现在的位置: 首页 > 综合 > 正文

《coredump问题原理探究》Linux x86版5.7节C风格数据结构内存布局之结构体数组

2013年02月21日 ⁄ 综合 ⁄ 共 2568字 ⁄ 字号 评论关闭

在探究过数组和结构体这两种非原生的数据类型之后,可能会想知道这两种类型结合成结构体数组,会有什么特征。

先看一个例子:

  #include <stdlib.h>
  struct xuzhina_dump_c05_s3_3
  {
      short idx;
      int sq;
  };
  
  void init( struct xuzhina_dump_c05_s3_3* test, int n )
 {
     for ( int i = 0; i < n; i++ )
     {
         test[i].idx = i;
         test[i].sq = i*i;
     }
 }
 
 int sum( struct xuzhina_dump_c05_s3_3* test, int n )
 {
     int sum = 0;
     for ( int i = 0; i < n; i++ )
     {
         sum += test[i].sq;
     }
     return sum;
 }
 
 int main(int argc, char* argv[] )
 {
     if ( argc < 2 )
     {
         return 1;
     }

     int num = atoi( argv[1] );

     struct xuzhina_dump_c05_s3_3* test =
         (struct xuzhina_dump_c05_s3_3*)malloc( num * sizeof( struct xuzhina_dump_c05_s3_3 ) );
 
     init( test, num );
 
     return sum( test, num );
 }

汇编(只看init和sum即可)

(gdb) disassemble init
Dump of assembler code for function _Z4initP21xuzhina_dump_c05_s3_3i:
   0x080484d0 <+0>:     push   %ebp
   0x080484d1 <+1>:     mov    %esp,%ebp
   0x080484d3 <+3>:     sub    $0x10,%esp
   0x080484d6 <+6>:     movl   $0x0,-0x4(%ebp)		;i
   0x080484dd <+13>:    jmp    0x8048511 <_Z4initP21xuzhina_dump_c05_s3_3i+65>

   0x080484df <+15>:    mov    -0x4(%ebp),%eax
   0x080484e2 <+18>:    lea    0x0(,%eax,8),%edx		;edx = i*8
   0x080484e9 <+25>:    mov    0x8(%ebp),%eax		;eax = test
   0x080484ec <+28>:    add    %eax,%edx				;edx = test[i]
   0x080484ee <+30>:    mov    -0x4(%ebp),%eax		;i
   0x080484f1 <+33>:    mov    %ax,(%edx)			;test[i].idx = i
   0x080484f4 <+36>:    mov    -0x4(%ebp),%eax		;i
   0x080484f7 <+39>:    lea    0x0(,%eax,8),%edx		;edx = i*8
   0x080484fe <+46>:    mov    0x8(%ebp),%eax		;eax = test
   0x08048501 <+49>:    add    %eax,%edx				;edx = test[i]
   0x08048503 <+51>:    mov    -0x4(%ebp),%eax		;eax = i
   0x08048506 <+54>:    imul   -0x4(%ebp),%eax		;eax *= i
   0x0804850a <+58>:    mov    %eax,0x4(%edx)		;test[i].sq = eax
   0x0804850d <+61>:    addl   $0x1,-0x4(%ebp)			;i++
   0x08048511 <+65>:    mov    -0x4(%ebp),%eax
   0x08048514 <+68>:    cmp    0xc(%ebp),%eax
   0x08048517 <+71>:    setl   %al
   0x0804851a <+74>:    test   %al,%al
   0x0804851c <+76>:    jne    0x80484df <_Z4initP21xuzhina_dump_c05_s3_3i+15>

   0x0804851e <+78>:    leave  
   0x0804851f <+79>:    ret    
End of assembler dump.

(gdb) disassemble sum
Dump of assembler code for function _Z3sumP21xuzhina_dump_c05_s3_3i:
   0x08048520 <+0>:     push   %ebp
   0x08048521 <+1>:     mov    %esp,%ebp
   0x08048523 <+3>:     sub    $0x10,%esp
   0x08048526 <+6>:     movl   $0x0,-0x4(%ebp)		;sum
   0x0804852d <+13>:    movl   $0x0,-0x8(%ebp)		;i
   0x08048534 <+20>:    jmp    0x804854f <_Z3sumP21xuzhina_dump_c05_s3_3i+47>

   0x08048536 <+22>:    mov    -0x8(%ebp),%eax		;i
   0x08048539 <+25>:    lea    0x0(,%eax,8),%edx
   0x08048540 <+32>:    mov    0x8(%ebp),%eax		;test
   0x08048543 <+35>:    add    %edx,%eax
   0x08048545 <+37>:    mov    0x4(%eax),%eax		;test[i].sq
   0x08048548 <+40>:    add    %eax,-0x4(%ebp)
   0x0804854b <+43>:    addl   $0x1,-0x8(%ebp)			;i++
   0x0804854f <+47>:    mov    -0x8(%ebp),%eax
   0x08048552 <+50>:    cmp    0xc(%ebp),%eax		;i < n 
   0x08048555 <+53>:    setl   %al
   0x08048558 <+56>:    test   %al,%al
   0x0804855a <+58>:    jne    0x8048536 <_Z3sumP21xuzhina_dump_c05_s3_3i+22>

   0x0804855c <+60>:    mov    -0x4(%ebp),%eax
   0x0804855f <+63>:    leave  
   0x08048560 <+64>:    ret    
End of assembler dump.

从上面的汇编,结构体数组的特征如下:

1.        先是找到数组的首地址

2.        再根据索引找到每个元素,得到每个元素的地址。

3.        再以每个元素的地址作为结构体基址,再获取成员变量的地址。

抱歉!评论已关闭.