前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《coredump问题原理探究》Linux x86版5.5节C风格数据结构内存布局之基本数据类型构成的结构体

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

作者头像
血狼debugeeker
发布2018-09-20 14:38:31
4290
发布2018-09-20 14:38:31
举报
文章被收录于专栏:debugeeker的专栏debugeeker的专栏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344509

在C语言里,结构体是不同类型数据结构的集合。由于结构体比较复杂,分为几种情况来讨论:

1. 成员全是由基本数据类型构成

2. 成员有基本数据类型,也有其它结构体构成,构成成员的结构体是1,2两种情况。

3. 结构体构成的数组

这一节先讨论第一种情况.要了解这种类型结构体的内存布局,首先要知道成员在内存里是如何排序,及各个成员在内存占的大小。先看一个例子

代码语言:javascript
复制
 #include <stdio.h>
 struct xuzhina_dump_c05_s3_stru
 {
     char a;
     short b;
     int c;
     long d;
     float e;
     double f;
     void* g;
 };
 
 int main()
 {
     struct xuzhina_dump_c05_s3_stru test;
     printf( "addr:%x, 1st:%x, 2nd:%x, 3rd:%x, 4th:%x, 5th:%x, 6th:%x, 7th:%x
    ",
             &test, &test.a, &test.b, &test.c, &test.d, &test.e, &test.f, &te
    st.g );
     return 0;
 }

运行结果:

代码语言:javascript
复制
addr:bf909eb4, 1st:bf909eb4, 2nd:bf909eb6, 3rd:bf909eb8, 4th:bf909ebc, 5th:bf909ec0, 6th:bf909ec4, 7th:bf909ecc

可得这样的结论:

1.        结构体对象的地址和第一个成员地址一样。也就是所谓的基地址

2.        第一个成员a和第二个成员b分别是char,short,不足dword大小,为了内存对齐,挤一个dword里。int, long, float, double,指针由于大小分别是4,4,4,8,4,直接按照4字节进行内存对齐,也分别占4,4,4,8,4个字节的空间.

3.        各个成员还是按照结构体的声明顺序由低到高排列。

4.        每个成员的地址都是它前面所有成员的大小(包括内存对齐)和基地址的累加。像test.d的地址就是bf909eb4+0x8 = bf909ebc.它前面的成员a ,b在一个dword, c占一个dword,刚好是8.

可能成员类型会由于内存对齐而分辨不出来。其实,用5.1节的方法是可以分辨得出来。有兴趣可以尝试一下。

那么一个结构体如何从汇编里识别出来呢,它究竟有什么特征?

先看一下这个例子。

代码语言:javascript
复制
 struct xuzhina_dump_c05_s3_stru
 {
     char a;
     short b;
     int c;
 };
 
 bool equal( struct xuzhina_dump_c05_s3_stru* first,
         struct xuzhina_dump_c05_s3_stru* second )
 {
     if ( first->a != second->a )
     {
         return false;
     }
     if ( first->b != second->b )
     {
         return false;
     }
     if ( first->c != second->c )
     {
         return false;
     }
     return true;
 }
 
 int main()
 {
     struct xuzhina_dump_c05_s3_stru first = { 'a', 10, 20 };
     struct xuzhina_dump_c05_s3_stru second = {'a', 10, 21 };

     if ( equal( &first, &second ) )
     {
         return 0;
     }
 
     return 1;
 }

汇编代码

代码语言:javascript
复制
(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 main
Dump 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.        每个成员与基址的偏移量,不是构成一个等差数列。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013年03月31日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档