深入理解計算機系統 第三版 讀書筆記三(函式呼叫)

2021-09-25 02:31:32 字數 2986 閱讀 9535

假設函式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個,超出的部分就要通過棧來傳遞。

p呼叫q時,通過棧傳遞引數時,所有的資料大小都向8的倍數對齊。引數到位以後,程式就可以執行call指令將控制轉移到函式q了。q可以通過暫存器訪問引數,也可以通過棧訪問。

例3.1:

上面兩圖是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...