- 註冊時間
- 2006-10-8
- 最後登錄
- 2019-6-20
- 主題
- 查看
- 積分
- 1306
- 閱讀權限
- 110
- 文章
- 1393
- 相冊
- 0
- 日誌
- 1
![Rank: 11](static/image/common/star_level3.gif) ![Rank: 11](static/image/common/star_level3.gif) ![Rank: 11](static/image/common/star_level2.gif) ![Rank: 11](static/image/common/star_level1.gif)
狀態︰
離線
|
#include <stdio.h>
int main() {
int x = 1;
int y;
y = f1(x);
printf("y=%d\n", y);
return 1;
}
int f1(int t) {
int b = f2(&t);
return b+b;
}
int f2(int *p) {
int r= *p+5;
return r;
}
如果我們用gcc 編譯器將C 語言轉換為組合語言,就會發現其中有些難以理解的地方,這是因為 gcc 會將程式中的區域變數存放在堆疊當中,並且在進入函數前先將參數壓入堆疊。在進入
也就是要保存框架指標 ebp 與設定堆疊指標 esp,因此這兩個程式並不能再度呼叫下一層的函數,否則將會導致框架指標遺失,而產生堆疊錯誤的情況。
在 IA32 的處理器架構下,要進行多層次的副程式呼叫,必須在程式一進入時就保存 ebp 框架指標於堆疊中,然後設定 esp 堆疊指標,接著分配區域變數的空間。當函數呼叫結束,要返回上一層函數時,則必須先將傳回值存入 eax 當中,然後利用 leave 與 ret 等指令,完成返回動作。
為了觀察上述的過程,我們利用gcc將範例 3.13的 C 語言程式 f2.c,轉換成組合語言 f2.s,範例 3.19顯示了這兩個程式的對照情況,只要仔細觀察,您將會瞭解 C 語言函數呼叫機制的實作方式。
File:ch03/f2.s ; File:ch03/f2.c
.file "f2.c" ; #include <stdio.h>
.def ___main; .scl 2; .type 32; .endef ;
.section .rdata,"dr" ;
LC0: ;
.ascii "y=%d\12\0" ;
.text ;
.globl _main ;
.def _main; .scl 2; .type 32; .endef ;
_main: ; int main() {
pushl %ebp ; // 保存框架指標
movl %esp, %ebp ; // 設定堆疊指標
subl $24, %esp ; // 分配區域變數空間
andl $-16, %esp ;
movl $0, %eax ;
addl $15, %eax ;
addl $15, %eax ;
shrl $4, %eax ;
sall $4, %eax ;
movl %eax, -12(%ebp) ;
movl -12(%ebp), %eax ;
call __alloca ; // 分配堆積(heap)空間
call ___main ;
movl $1, -4(%ebp) ; int x = 1;
movl -4(%ebp), %eax ; int y;
movl %eax, (%esp) ;
call _f1 ; y = f1(x);
movl %eax, -8(%ebp) ; // y = eax
movl -8(%ebp), %eax ; // eax = y
movl %eax, 4(%esp) ; // 參數 y (推入堆疊)
movl $LC0, (%esp) ; // 參數 "y=%d\n"
call _printf ; printf("y=%d\n", y);
movl $1, %eax ; // 設定傳回值 eax=1
leave ;
ret ; return 1;
.globl _f1 ; }
.def _f1; .scl 2; .type 32; .endef ;
_f1: ; int f1(int t) {
pushl %ebp ; // 保存框架指標
movl %esp, %ebp ; // 設定堆疊指標
subl $8, %esp ; // 分配區域變數空間
leal 8(%ebp), %eax ; // eax = 8(%ebp) 的位址
movl %eax, (%esp) ; // esp 上移 8 byte
call _f2 ; int b = f2(&t);
movl %eax, -4(%ebp) ; // -4(%ebp) 就是 b
movl -4(%ebp), %eax ; // eax = b
addl -4(%ebp), %eax ; // eax = eax + b
leave ;
ret ; return b+b;
.globl _f2 ; }
.def _f2; .scl 2; .type 32; .endef ;
_f2: ; int f2(int *p) {
pushl %ebp ; // 保存框架指標
movl %esp, %ebp ; // 設定堆疊指標
subl $4, %esp ; // 分配區域變數空間
movl 8(%ebp), %eax ;
movl (%eax), %eax ;
addl $5, %eax ; int r= *p+5;
movl %eax, -4(%ebp) ; // 設定傳回值 eax=r
movl -4(%ebp), %eax ;
leave ;
ret ; return r;
.def _f2; .scl 3; .type 32; .endef ; }
.def _printf; .scl 3; .type 32; .endef ;
.def _f1; .scl 3; .type 32; .endef ;
|
|