欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GoLang函數(shù)棧的使用詳細講解

 更新時間:2023年02月02日 11:54:54   作者:raoxiaoya  
這篇文章主要介紹了GoLang函數(shù)棧的使用,我們的代碼會被編譯成機器指令并寫入到可執(zhí)行文件,當程序執(zhí)行時,可執(zhí)行文件被加載到內存,這些機器指令會被存儲到虛擬地址空間中的代碼段,在代碼段內部,指令是低地址向高地址堆積的

函數(shù)棧幀

我們的代碼會被編譯成機器指令并寫入到可執(zhí)行文件,當程序執(zhí)行時,可執(zhí)行文件被加載到內存,這些機器指令會被存儲到虛擬地址空間中的代碼段,在代碼段內部,指令是低地址向高地址堆積的。堆區(qū)存儲的是需要程序員手動alloc并free的空間,需要自己來控制。

虛擬內存空間是對存儲器的一層抽象,是為了更好的來管理存儲器,虛擬內存和存儲器之間存在映射關系。

如果在一個函數(shù)中調用了另外一個函數(shù),編譯器就會對應生成一條call指令,當call指令被執(zhí)行時,就會跳轉到被調用函數(shù)入口處開始執(zhí)行,而每個函數(shù)的最后都有一條ret指令,負責在函數(shù)結束后跳回到調用處繼續(xù)執(zhí)行。

call 指令做了兩件事,將下一條指令的地址入棧,這就是IP寄存器中存儲的值,第二,跳轉到被調用函數(shù)入口處執(zhí)行。

函數(shù)執(zhí)行時需要有足夠的內存空間用來存儲參數(shù),局部變量,返回值,這塊空間對應的就是棧,棧區(qū)是從高地址向低地址生長的,且先進后出。分配給函數(shù)的棧空間被稱為函數(shù)棧幀。

C語言中,每個棧幀對應著一個未運行完的函數(shù)。棧幀中保存了該函數(shù)的返回地址和局部變量。

寄存器

ESP寄存器:ESP即 Extended stack pointer 的縮寫,直譯過來就是擴展的棧指針寄存器。SP是16位的,ESP是32位的,RSP是64位的,存放的都是棧頂?shù)刂贰?/p>

EBP寄存器:EBP即 Extended base pointer 的縮寫,直譯過來就是擴展的基址指針寄存器。該指針總是指向當前棧幀的底部。

IP寄存器:指令指針,它指向代碼段中的地址,是一個16位專用寄存器,它指向當前需要取出的指令字節(jié),也就是下一個將要執(zhí)行的指令在代碼段中的地址。

eax:累加(Accumulator)寄存器,常用于函數(shù)返回值

ebx:基址(Base)寄存器,以它為基址訪問內存

ecx:計數(shù)器(Counter)寄存器,常用作字符串和循環(huán)操作中的計數(shù)器

edx:數(shù)據(Data)寄存器,常用于乘除法和I/O指針

esi:源地址寄存器

edi:目的地址寄存器

esp:堆棧指針

ebp:棧指針寄存器

當然,以上功能并未限制寄存器的使用,特殊情況為了效率也可作其他用途。

這八個寄存器低16位分別有一個引用別名 ax, bx, cx, dx, bp, si, di, sp,

其中 ax, bx, cx, dx, 的高8位又引用至 ah, bh, ch, dh,低八位引用至 al, bl, cl, dl

在 64-bit 模式下,有16個通用寄存器,但是這16個寄存器是兼容32位模式的,

32位方式下寄存器名分別為 eax, ebx, ecx, edx, edi, esi, ebp, esp, r8d – r15d.

在64位模式下,他們被擴展為 rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp, r8 – r15.

其中 r8 – r15 這八個寄存器是64-bit模式下新加入的寄存器。

我們看到CPU在執(zhí)行代碼段中的指令,而這當中又伴隨著內存的分配,于是在函數(shù)棧幀上就會有相應的變化。

int add(int a, int b)
{
    int c = 4;
    c = a + b;
    return c;
}
int main()
{
    int a = 1;
    int b = 2;
    int sum = 3;
    sum = add(a, b);
    return 0;
}

生成的匯編代碼的方式

1、使用 gcc + objdump

gcc -save-temps -fverbose-asm -g -o b testasm.c
objdump -S --disassemble b > b.objdump

2、使用第三方網站來生成,進入 https://godbolt.org/,選擇語言為C,編譯器為x86-64 gcc 12.2,粘貼進你的代碼,就能看到匯編代碼,如下

add:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-20], edi
        mov     DWORD PTR [rbp-24], esi
        mov     DWORD PTR [rbp-4], 4
        mov     edx, DWORD PTR [rbp-20]
        mov     eax, DWORD PTR [rbp-24]
        add     eax, edx
        mov     DWORD PTR [rbp-4], eax
        mov     eax, DWORD PTR [rbp-4]
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 1
        mov     DWORD PTR [rbp-8], 2
        mov     DWORD PTR [rbp-12], 3
        mov     edx, DWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, edx
        mov     edi, eax
        call    add
        mov     DWORD PTR [rbp-12], eax
        mov     eax, 0
        leave
        ret

從main開始解讀

// 此時rbp存儲的還是上一層函數(shù)(調用者)的?;刂?,將rbp的值入棧保存起來,因為main函數(shù)也是被其他函
// 數(shù)調用的,運行完main之后還得回到那個函數(shù)體中去。這里的地址指的是指令的地址,是代碼段中的位置。
// push指令會使rsp下移。
push    rbp 
// 此時rbp存儲的還是上一個函數(shù)的基地址,而rsp則已經游走到了main函數(shù)這里,mov指令將rsp中存儲的地址傳遞
// 給rbp,也就意味著執(zhí)行完之后rbp和rsp都處于main函數(shù)的開始位置,稱為初始化操作。
mov     rbp, rsp
// rsp下移16,就是分配??臻g
sub     rsp, 16

// DWORD 為雙字,即四個字節(jié),PTR為指針的意思,此句意為在rbp向下偏移4個字節(jié)的這段棧內存中存儲0
// a
mov     DWORD PTR [rbp-4], 1
// b
mov     DWORD PTR [rbp-8], 2
// sum
mov     DWORD PTR [rbp-12], 3
// 將參數(shù)從右到左,依次存起來,此處存到了 edx和eax,并拷貝了一份到esi和edi。
mov     edx, DWORD PTR [rbp-8]`
mov     eax, DWORD PTR [rbp-4]`
mov     esi, edx`
mov     edi, eax`

 // 執(zhí)行call指令
// 注意,call會使CPU跳入到add的棧幀中去,那么執(zhí)行完之后,我們需要跳回到被調用處繼續(xù)向下執(zhí)行,由
// 最前面的push指令我們已經把調用者的棧基存了下來,可是我們還要精確到具體是回到哪個指令,這就是call
// 指令的額外工作,它會先將IP入棧(push ip),因為IP中存的就是下一條指令(mov DWORD PTR [rbp-12], eax)
// 的地址,然后再去跳轉(jmp),將add函數(shù)的第一條指令寫入IP,此后就進入add函數(shù)棧幀。
call    add

// cpu執(zhí)行完運算后會將結果存儲在寄存器中,至于它會把結果存儲在那個寄存器,這個由編譯器編譯出的指令
// 決定的,由add函數(shù)的指令來看,它選擇了eax
// rbp-12 為sum的位置,這條指令將eax寄存器的值賦值給sum
mov     DWORD PTR [rbp-12], eax
// 將eax置0,也就是main的返回值
mov     eax, 0
// 意為 mov rsp, rbp 和 pop rbp 的組合
// 此時rbp為main函數(shù)的?;?,rsp為main函數(shù)的末尾了,將rbp賦值給rsp,于是它們都指向main函數(shù)的棧基,上
// 面解釋過,rbp寄存器存儲的地址指向的棧上的空間存儲的還是一個地址,此地址指向調用者的棧基,
// pop rbp 將棧頂rsp的數(shù)據送入rbp,就意味著之后就回到了調用者的棧幀了,同時pop會伴隨著rsp的上移,
// 于是rsp來到了EIP的位置。
leave
// 相當于 pop ip
// 此函數(shù)執(zhí)行完需要跳回到調用者并繼續(xù)執(zhí)行下一條指令,由于call的時候已經將下一條指令的地址入棧了,所以
// 此處值需要將其彈出即可。
ret

到此這篇關于GoLang函數(shù)棧的使用詳細講解的文章就介紹到這了,更多相關Go函數(shù)棧內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 通過Golang實現(xiàn)linux命令ls命令(命令行工具構建)

    通過Golang實現(xiàn)linux命令ls命令(命令行工具構建)

    這篇文章主要為大家詳細介紹了如何通過Golang實現(xiàn)一個linux命令ls命令(命令行工具構建),文中的示例代碼講解詳細,具有一定的學習價值,感興趣的可以了解一下
    2023-01-01
  • Golang JSON的進階用法實例講解

    Golang JSON的進階用法實例講解

    這篇文章主要給大家介紹了關于Golang JSON進階用法的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用golang具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-09-09
  • golang的匿名函數(shù)和普通函數(shù)的區(qū)別解析

    golang的匿名函數(shù)和普通函數(shù)的區(qū)別解析

    匿名函數(shù)是不具名的函數(shù),可以在不定義函數(shù)名的情況下直接使用,通常用于函數(shù)內部的局部作用域中,這篇文章主要介紹了golang的匿名函數(shù)和普通函數(shù)的區(qū)別,需要的朋友可以參考下
    2023-03-03
  • gin自定義中間件解決requestBody不可重讀(請求體取值)

    gin自定義中間件解決requestBody不可重讀(請求體取值)

    這篇文章主要介紹了gin自定義中間件解決requestBody不可重讀,確??刂破髂軌颢@取請求體值,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Go語言單元測試基礎從入門到放棄

    Go語言單元測試基礎從入門到放棄

    這篇文章主要介紹了Go單元測試基礎從入門到放棄為大家開啟Go語言單元測試第一篇章,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • go slice 數(shù)組和切片使用區(qū)別示例解析

    go slice 數(shù)組和切片使用區(qū)別示例解析

    這篇文章主要為大家介紹了go slice 數(shù)組和切片使用區(qū)別示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Go語言的JSON處理詳解

    Go語言的JSON處理詳解

    json格式可以算我們日常最常用的序列化格式之一了,Go語言作為一個由Google開發(fā),號稱互聯(lián)網的C語言的語言,自然也對JSON格式支持很好。
    2018-10-10
  • golang中連接mysql數(shù)據庫

    golang中連接mysql數(shù)據庫

    這篇文章主要介紹了golang中連接mysql數(shù)據庫的步驟,幫助大家更好的理解和學習go語言,感興趣的朋友可以了解下
    2020-12-12
  • 使用GO操作MongoDB的方法

    使用GO操作MongoDB的方法

    這篇文章主要介紹了使用GO操作MongoDB,包括安裝MongoDB驅動程序連接mongodb的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • Go 自定義package包設置與導入操作

    Go 自定義package包設置與導入操作

    這篇文章主要介紹了Go 自定義package包設置與導入操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05

最新評論