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

在C语言中,联合体(union)有点像结构体那样,把不同类型的数据组织起来,但和结构体不大一样,在结构体各成员有各自的内存空间,一个结构体对象的总长度是各成员长度之和。而在联合体中,各成员共享一段内存空间,一个联合体对象的长度等于各成员中最长的长度。

由上面描述可知,联合体应该具备多面性,即在汇编层面上,有时候会显示结构体的特征,或数组特征,或其它基本数据类型特征。

先看一下例子:


1	 #include <stdio.h>
  2	 union xuzhina_dump_c05_s4
  3	 {
  4	     int i;
  5	     char hello[4];
  6	 };
  7 
  8	 int main()
  9	 {
 10	     union xuzhina_dump_c05_s4 test;
 11	     test.i = 0x656463;
 12	     for ( int i = 0; i < 4; i++ )
 13	     {
 14	         printf( "%c", test.hello[i] );
 15	     }
 16	 
 17	     printf( "\n" );
 18	     return 0;
 19	 }


汇编代码:

(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>:     movl   $0x656463,0x18(%esp)
   0x08048581 <+17>:    movl   $0x0,0x1c(%esp)
   0x08048589 <+25>:    jmp    0x80485a8 <main+56>
   0x0804858b <+27>:    lea    0x18(%esp),%edx
   0x0804858f <+31>:    mov    0x1c(%esp),%eax
   0x08048593 <+35>:    add    %edx,%eax
   0x08048595 <+37>:    movzbl (%eax),%eax
   0x08048598 <+40>:    movsbl %al,%eax
   0x0804859b <+43>:    mov    %eax,(%esp)
   0x0804859e <+46>:    call   0x8048430 <putchar@plt>
   0x080485a3 <+51>:    addl   $0x1,0x1c(%esp)
   0x080485a8 <+56>:    cmpl   $0x3,0x1c(%esp)
   0x080485ad <+61>:    setle  %al
   0x080485b0 <+64>:    test   %al,%al
   0x080485b2 <+66>:    jne    0x804858b <main+27>
   0x080485b4 <+68>:    movl   $0xa,(%esp)
   0x080485bb <+75>:    call   0x8048430 <putchar@plt>
   0x080485c0 <+80>:    mov    $0x0,%eax
   0x080485c5 <+85>:    jmp    0x80485cf <main+95>
   0x080485c7 <+87>:    mov    %eax,(%esp)
   0x080485ca <+90>:    call   0x8048460 <_Unwind_Resume@plt>
   0x080485cf <+95>:    leave  
   0x080485d0 <+96>:    ret    
End of assembler dump.

从上面汇编代码来看,unionxuzhina_dump_c05_s4确实以int和char数组进行访问。见下面这两组指令

   0x08048579 <+9>:     movl   $0x656463,0x18(%esp)

   0x0804858b <+27>:    lea    0x18(%esp),%edx
   0x0804858f <+31>:    mov    0x1c(%esp),%eax
   0x08048593 <+35>:    add    %edx,%eax
   0x08048595 <+37>:    movzbl (%eax),%eax


由上面的探讨,union成员类型最好避免是指针类型。因为指针容易被覆盖,会发生“Accessviolation”的错误。假设指针是函数指针,则会出现上一节的coredump。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。