庖丁解牛Linux內(nèi)核-1

這個(gè)文集是用來記錄 庖丁解牛Linux內(nèi)核 這個(gè)課程的筆記和作業(yè).錯(cuò)誤之處,懇請指出.

實(shí)驗(yàn)?zāi)康?/h2>

通過這個(gè)實(shí)驗(yàn),主要了解到C函數(shù)的調(diào)用在匯編層面的邏輯.

實(shí)驗(yàn)內(nèi)容

C程序

首先我們準(zhǔn)備了一個(gè)簡單的函數(shù)調(diào)用的c程序

int g(int x)
{
  return x + 3;
}

int f(int x)
{
  return g(x);
}

int main(void)
{
  return f(8) + 1;
}

通過gcc -S -o main.S main,c -m32,可以獲得main.S也就是該段代碼的反匯編代碼.去掉其中以"."開頭的代碼,因?yàn)檫@是匯編語言中的偽指令,是寫給編譯器看的,并不是真正的機(jī)器會執(zhí)行的代碼.然后我們得到下面的匯編代碼:


g:
    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    addl            $3, %eax
    popl            %ebp
    ret
f:
    pushl   %ebp
    movl    %esp, %ebp
    subl           $4, %esp
    movl    8(%ebp), %eax  # 這里是要跳過call中入棧的eip,跳過前面看入棧的ebp,也就是4*2=8bytes,內(nèi)存單位是1byte,那么8(%ebp)就是在ebp的基礎(chǔ)上往前移8bytes,指向main里的立即數(shù)8.
    movl    %eax, (%esp)
    call    g
    leave
    ret
main:
    pushl   %ebp   #從這一句開始執(zhí)行, 把main函數(shù)的棧底地址入棧.
    movl    %esp, %ebp   # 更新棧底地址
    subl            $4, %esp     
    movl    $8, (%esp)   #相當(dāng)于push $8
    call    f    # push 下條指令eip到棧中,然后修改eip為f的地址,跳到f處開始執(zhí)行
    addl    $1, %eax
    leave
    ret

基本邏輯直接看我上面的注釋.下面是幾個(gè)注意的點(diǎn)

  1. 要注意的是除了最開始的初始化,esp指向的棧頂是當(dāng)前有效數(shù)據(jù)的最低地址,而不是指向null的地址.那么
subl            $4, %esp 
movl    $8, (%esp)

這兩句其實(shí)就是push $8,為什么要分成兩句我還不知道.

總結(jié)

  1. 計(jì)算機(jī)的工作原理其實(shí)就是講一些代碼放在連續(xù)的內(nèi)存里,然后同時(shí)開辟一段堆和棧. 堆用來存儲全局.
  2. 我們在調(diào)用函數(shù)時(shí),在匯編層面的處理是:
    1. 先把CS:IP壓入棧,以便函數(shù)結(jié)束后再接著當(dāng)前流程執(zhí)行
    2. 再把當(dāng)前函數(shù)的棧頂壓入
    3. 再從右到左壓入函數(shù)變量
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容