假設函式p呼叫函式q,q執行後返回到p。這個呼叫包括下面乙個或多個機制:
傳遞資料:p必須能夠向q提供乙個或多個引數,q必須能夠向p返回乙個值。
分配和釋放記憶體:q可能需要為區域性變數分配空間,返回前又必須釋放這些空間。
執行時棧的結構如下圖:
其中x86-64的棧向低位址方向增長,而棧指標%rsp指向棧頂元素。可以用pushq和popq將資料入棧或者出棧。
呼叫指令是:
指令描述
call label
過程呼叫
call *operand
過程呼叫
ret從過程中返回
例項說明:
main函式使用call呼叫了multstore函式
multstore函式呼叫ret返回到main函式
// beginning of function multstore
1 0000000000400540 2 400540: 53 push %rbx
3 400541: 48 89 d3 mov %rdx, %rbx
...// return from function multstore
4 40054d: c3 retq
//beginning of function main
5 400563: e8 d8 ff ff ff call 400540 6 400568: 48 8b 54 24 08 mov 0x8(%rsp), %rdx
在指令執行到第5行時,所對應的pc指標(%rip)和%rsp的狀態如下圖(a)。
執行完call指令後將0x400568壓入棧中,並將pc指標設定為0x400540,如下圖(b)所示。
在multstore呼叫完ret時,將0x400568從棧中彈出,將pb指標設定為0x400568,繼續執行。
在x86-64中,大部分過程間的資料傳送是通過暫存器實現的,函式的返回值存放在%rax中。可以通過暫存器最多傳遞6個整型引數。
假設q函式的引數大於6個,超出的部分就要通過棧來傳遞。例3.1:p呼叫q時,通過棧傳遞引數時,所有的資料大小都向8的倍數對齊。引數到位以後,程式就可以執行call指令將控制轉移到函式q了。q可以通過暫存器訪問引數,也可以通過棧訪問。
上面兩圖是c語言以及對應的彙編實現。
後面兩個引數通過棧傳遞。
注意:這時的%rsp暫存器裡面存的是呼叫proc中的函式的下乙個指令位址。
例3.2:
1 void func(void)
在執行第3行時,過程func的棧幀如下圖:
所以在例3.1的彙編實現中獲取a4和a4p的值會是%rsp指標分別加8和加16。
一般情況下函式的區域性變數都是優先放到暫存器中的,以下幾種情況必須放到記憶體中:
暫存器數量不足時
對乙個變數使用"&"操作符時
變數是陣列或者結構體時
例如3.2的c**呼叫編譯成彙編如下:
void func()
1 func:
2 subq $32, %rsp alloc 32-byte stack frame
3 movq $1, 24(%rsp) long a1=1
4 movl $2, 20(%rsp) int a2=2
5 movw $3, 18(%rsp) short a3=3
6 movb $4, 17(%rsp) char a4=4
7 leadq 17(%rsp), %rax &a4-->%rax
8 movq %rax, 8(%rsp) store &a4 as argument 8
9 movl $4, (%rsp) store 4 as argument 7
10 leadq 18(%rsp), %r9 store &a3 as argument 6
11 movl $3, %r8d store a3 as argument 5
12 leadq 20(%rsp), %rcx store &a2 as argument 4
13 movl $2, %edx store 2 as argument 3
14 leadq 24(%rsp), %rsi store &a1 as argument 2
15 movl $1, %edi store 1 as argument 1
call proc
16 call proc
詳細說明可以參考:該書172頁,pdf(208頁)。
暫存器組是唯一被所有過程共享的資源。當乙個函式呼叫另乙個函式時,被呼叫函式不能覆蓋呼叫者稍後會使用的暫存器。因此暫存器的使用必須要遵循以下規則:
%rbx,%rbg和%12~%15被劃分為被呼叫者儲存。當p呼叫q時,q必須儲存這些暫存器的值,保證他們的值在q返回到p時與q被呼叫時是一樣的。當q被呼叫時,為了儲存暫存器的值不會再離開時還是之前的值,要麼不去改變它,要麼就是把原始值壓棧然後再返回前從棧中彈出舊值。壓入暫存器的值會在q的棧幀中建立標號為「儲存的暫存器」的一部分,如上圖:執行時棧的結構所示。
其他暫存器除了%rsp以外,都是呼叫者儲存。
速讀《深入理解計算機系統(第三版)》問題及解決
p13 使用者棧和執行時堆有什麼區別?資料結構中經常說堆疊,這裡的堆和棧一樣嗎?和作業系統的堆 棧有什麼區別?參考 堆和棧的區別 記憶體和資料結構 作業系統 p31 c格式化指令 2x 表明整數必須用至少兩個數字的十六進製制格式輸出。之前學過 7.2f 點後的2指的是小數點後兩位,那麼 2x 中的點...
《深入理解計算機系統(第三版)》第一章
1 計算機提供不同層次的抽象表示,來隱藏實際實現的複雜性 2 程式設計師必須知道編譯系統是如何工作的原因 3 執行hello程式 4 併發是乙個通用的概念,指乙個同時具有多個活動的系統 並行指的是用併發使乙個系統執行的更快 5 意識到快取記憶體的存在,可以利用快取記憶體將程式的效能提高乙個數量級。執...
深入理解計算機系統(第三版)第2章 家庭作業
include include includetypedef unsigned char byte pointer void show bytes byte pointer start,size t len void show int int x void show float float x vo...