test env: x86/linux
這是 func.c 的某部份反組譯, 透過反組譯來查看 c 如何使用 stack 來傳遞參數, 如何存取傳進來的參數。
34   func('a', 9, (char*)(0x1234));        
從 L5, 10, 11 可以看到, 用 %epb 存取 func 傳入的 'a', 9, (char*)0x1234,
%epb + 8 -> 'a'
%epb + 0xc -> 9
%epb + 0x10 -> 0x1234
參考以下的 stack 位址 (這是我用 gdb 印出的位址, 每個系統可能會不同) 可以更清楚。
綠色是 main(), 藍色是 func()。
執行  func('a', 9, (char*)(0x1234));
'a', 9,  (char*)(0x1234) 分別被複製到 stack 位址 (這就是所謂的 call by value) 
0xffffd6e0 + 8
0xffffd6e0 + 4
0xffffd6e0 
func('a', 9, (char*)(0x1234)); 的下一個指令會被 push 到 stack, 就是圖中的 ret addr, 而 main() 的 %epb 會被 push, func() epb 會被指定為 0xffffd6d8, 所以這就是
%epb + 8 -> 'a'
%epb + 0xc -> 9
%epb + 0x10 -> 0x1234
可以存取到傳進來的參數的方法。
20   c+=2;
21   i+=3;
22   ++ptr;
 
 5  8048440:       8b 45 08                mov    0x8(%ebp),%eax   // 'a'
 6  8048443:       88 45 f4                mov    %al,-0xc(%ebp)
 7  8048446:       0f b6 45 f4             movzbl -0xc(%ebp),%eax
 8  804844a:       83 c0 02                add    $0x2,%eax 
10  8048450:       83 45 0c 03             addl   $0x3,0xc(%ebp)   // 9 + 3
11  8048454:       83 45 10 01             addl   $0x1,0x10(%ebp)  // 0x1234 + 1
 
不過 'a' /* c+=2 */ 的處理方式比較複雜, 不像 
%epb + 0xc 直接加 3 (9+3) /* i+=3) */
%epb + 0x10 直接加 1 (0x1234+1)  /* ++ptr */
而是很複雜的方式, 也許是長度為 1byte 的關係。 
我也不知道為什麼 %esp 要減掉 0x28 
 4  804843d:       83 ec 28                sub    $0x28,%esp
下圖是我自己得到的結果可能有些錯誤, 我還不是很懂組合語言, 不過和主題無關, 是我自己想觀察的部份。
我要描述的主題應該是正確的。這不是很好懂, 得花腦力看一下組合語言, 也要思考一下。因為我被這部份困惑很久了, 決心用自己的方法來理解, 我已經儘量將東西簡化了, 一次只討論一個小部份。
 stack frame 
 | (main esp) 0xffffd6e0 + 8  |  0x1234  |  
 | (main esp) 0xffffd6e0 + 4  |  9  |  
 | (main esp) 0xffffd6e0  |  'a'  |  
 | 0xffffd6dc calll func |  ret addr |  
 | 0xffffd6d8 push %ebp; mov %esp,%ebp |  caller ebp |  
 | 0xffffd6d4 |   |  
 | 0xffffd6d0 |   |  
 | 0xffffd6cc |  'a'+2 |  
 | 0xffffd6c8 |   |  
 | 0xffffd6c4 |   |  
 | 0xffffd6c0 |   |  
 | 0xffffd6bc |  0x1234 + 1 |  
 | 0xffffd6b8 |  9+3 | 
 | 0xffffd6b4 |  'a'+2 | 
 | (func esp)0xffffd6b0 |  "%c %d %p\n" |  
callee (func) epb = 0xffffd6d8
 
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。