之前在用C語言編程的時候,有些時候會利用stack的布局做一些操作.我之前在 實現(xiàn)垃圾收集器算法的時候就會使用函數(shù)參數(shù)的地址嫂丙,用這個地址作為基址在 stack上尋找我想要的數(shù)據(jù). 這篇文章 里面詳細介紹了stack的布局娘赴,以及編譯器在編譯函數(shù)時自動產生的前言和結語等問題. 對這個垃圾收集算法感興趣的可以看 這里. 我在寫這個算法的時候就發(fā)現(xiàn)當使用clang編譯器編譯后,函數(shù)參數(shù)在stack中的布局 跟預期的不一樣.這是 sf上提出的一個問題.
后來在工作中涉及到了不少關于stack balance的問題奢入,其中有些需求讓我不得不 讀反編譯后的代碼.
對于這樣一個函數(shù)
int add(int a, int b)
{
return a + b;
}
其用clang編譯后乙漓,反編譯結果如下
080483c0 <add>:
80483c0: 55 push %ebp
80483c1: 89 e5 mov %esp,%ebp
80483c3: 83 ec 08 sub $0x8,%esp
80483c6: 8b 45 0c mov 0xc(%ebp),%eax
80483c9: 8b 4d 08 mov 0x8(%ebp),%ecx
80483cc: 89 4d fc mov %ecx,-0x4(%ebp)
80483cf: 89 45 f8 mov %eax,-0x8(%ebp)
80483d2: 8b 45 fc mov -0x4(%ebp),%eax
80483d5: 03 45 f8 add -0x8(%ebp),%eax
80483d8: 83 c4 08 add $0x8,%esp
80483db: 5d pop %ebp
80483dc: c3 ret
80483dd: 0f 1f 00 nopl (%eax)
可以看到中間有4句mov指令做了stack拷貝操作.拷貝后stack布局變成
+---------+
|high |
+---------+
|101 |<-arg2
+---------+
|99 |<-arg1
+---------+
|ret |
+---------+
|ebp |
+---------+
|99 |<-a
+---------+
|101 |<-b
+---------+
|low |
+---------+
這一步拷貝操作導致用參數(shù)的地址作為地址來尋址會遇出錯.當時在實現(xiàn)垃圾收集 算法的時候還以為clang的參數(shù)計算順序問題,或者是ABI的問題万牺,現(xiàn)在看來還是圖 樣.
回過頭來看這個問題阳掐,clang這么做在效率上會有損失,但是的確是符合邏輯的. 這樣的一個參數(shù)拷貝操作之后武福,使得函數(shù)的參數(shù)都在自己的frame當中议双,而不像之 前一樣,函數(shù)的參數(shù)在其caller的frame中. 這個問題也說明捉片,利用函數(shù)參數(shù)地址來進行stack上的尋址操作是有潛在風險的.