標籤:linux 調試技術 x86 彙編 程式崩潰
在C語言中,聯合體(union)有點像結構體那樣,把不同類型的資料群組織起來,但和結構體不大一樣,在結構體各成員有各自的記憶體空間,一個結構體對象的總長度是各成員長度之和。而在聯合體中,各成員共用一段記憶體空間,一個聯合體對象的長度等於各成員中最長的長度。
由上面描述可知,聯合體應該具備多面性,即在彙編層面上,有時候會顯示結構體的特徵,或數組特徵,或其它基礎資料型別 (Elementary Data Type)特徵。
先看一下例子:
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 mainDump 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 <[email protected]> 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 <[email protected]> 0x080485c0 <+80>: mov $0x0,%eax 0x080485c5 <+85>: jmp 0x80485cf <main+95> 0x080485c7 <+87>: mov %eax,(%esp) 0x080485ca <+90>: call 0x8048460 <[email protected]> 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。
《coredump問題原理探究》Linux x86版5.8節C風格資料結構記憶體布局之聯合體