計組 i386呼叫約定

2021-10-25 15:18:22 字數 3660 閱讀 5959

x64呼叫約定是由硬體的彙編指令call和ret的微指令和軟體的彙編指令規範共同完成的

一般為如下順序

父函式引數入棧(軟體彙編**)

父函式call(硬體微指令)

子函式棧建立(軟體彙編**)

子函式棧清理(軟體彙編**)

子函式ret(硬體微指令)

父函式棧清理(軟體彙編**)

下文中將演示**f(a1, a2, a3, a4, ..., an-1, an)a.f(a1, a2, a3, a4, ..., an-1, an)在不同的呼叫約定下, 棧的變化過程

其中, 用數字表示以上的6個階段, 其後緊接著的是該階段結束後的棧的狀態和暫存器引數的示意

"["表示棧底, 處於位址高部, 由ebp/rbp暫存器的值直接決定, 其左邊緊貼著的值的位址為ebp+0/rbp+0, 每往右乙個引數位址遞減4/8

最右邊的引數由esp/rsp暫存器的值直接決定, 其位址為esp+0/rsp+0, 每往左乙個引數位址遞增4/8

"_"表示任意值

call指令只有一種, 因此1到2的變化都是一樣的

ret指令有兩種, 一種只出棧eip, 另一種不僅出棧eip, 還令esp增加乙個數(即清理棧)

每個引數大小為4b

傳參暫存器: 無

[, …, an, an-1, …, a4, a3, a2, a1

[, …, an, an-1, …, a4, a3, a2, a1, 上級eip

…, an, an-1, …, a4, a3, a2, a1, 上級eip, 上級ebp [

[, …, an, an-1, …, a4, a3, a2, a1, 上級eip

[, …

[, …

返回值暫存器: eax

傳參暫存器: 無

[, …, an, an-1, …, a4, a3, a2, a1

[, …, an, an-1, …, a4, a3, a2, a1, 上級eip

…, an, an-1, …, a4, a3, a2, a1, 上級eip, 上級ebp [

[, …, an, an-1, …, a4, a3, a2, a1, 上級eip

[, …, an, an-1, …, a4, a3, a2, a1

[, …

返回值暫存器: eax

傳參暫存器: edx=a2, ecx=a1

[, …, an, an-1, …, a4, a3

[, …, an, an-1, …, a4, a3, 上級eip

…, an, an-1, …, a4, a3, 上級eip, 上級ebp [, a2, a1

[, …, an, an-1, …, a4, a3, 上級eip

[, …

[, …

返回值暫存器: eax

略(用到時再補充試驗)

傳參暫存器: ecx=this

[, …, an, an-1, …, a4, a3, a2, a1

[, …, an, an-1, …, a4, a3, a2, a1, 上級eip

…, an, an-1, …, a4, a3, a2, a1, 上級eip, 上級ebp [, this

[, …, an, an-1, …, a4, a3, a2, a1, 上級eip

[, …

[, …

返回值暫存器: eax

每個引數大小為8b

傳參暫存器: r9d=a4, r8d=a3, rdx=a2, rcx=a1

[, …, an, an-1, …, a6, a5, _, _, _, _

[, …, an, an-1, …, a6, a5, _, _, _, _, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, a2, a1, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, a2, a1, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, a2, a1

[, …, an, an-1, …, a6, a5, _, _, _, _

返回值暫存器: eax

父函式不能假定子函式一定給a1到a4在記憶體中預留的空間賦了值, 故應為任意值

注: 當引數數少於4時, 依然要在呼叫棧留下32b的空間, 即

[, …, _, _, _, _

[, …, _, _, _, _, 上級eip

[, …, _, a3, a2, a1, 上級eip

[, …, _, a3, a2, a1, 上級eip

[, …, _, a3, a2, a1

[, …, _, _, _, _

當引數含__m128型資料時, 使用對應的xmm暫存器傳參, 同時應將呼叫約定改為__vectorcall

傳參暫存器: r9d/xmm3=a4, r8d/xmm2=a3, rdx/xmm1=a2, rcx/xmm0=a1

[, …, an, an-1, …, a6, a5, _, _, _, _

[, …, an, an-1, …, a6, a5, _, _, _, _, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, a2, a1, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, a2, a1, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, a2, a1

[, …, an, an-1, …, a6, a5, _, _, _, _

返回值暫存器: eax/xmm0

視具體情況, 第3步可能會騰出空間在記憶體中暫存資料, 如

傳參暫存器: r9d=a4, r8d=a3, xmm1=a2, xmm0=a1

[, …, an, an-1, …, a6, a5, _, _, _, _

[, …, an, an-1, …, a6, a5, _, _, _, _, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, &a2, &a1, 上級eip, _, a2(高位), a2(低位), a1(高位), a1(低位)

[, …, an, an-1, …, a6, a5, a4, a3, &a2, &a1, 上級eip

[, …, an, an-1, …, a6, a5, a4, a3, _, _

[, …, an, an-1, …, a6, a5, _, _, _, _

傳參暫存器: r9d/xmm3=a3, r8d/xmm2=a2, rdx/xmm1=a1, rcx/xmm0=this

[, …, an, an-1, …, a5, a4 _, _, _, _

[, …, an, an-1, …, a5, a4, _, _, _, _, 上級eip

[, …, an, an-1, …, a5, a4, a3, a2, a1, this, 上級eip

[, …, an, an-1, …, a5, a4, a3, a2, a1, this, 上級eip

[, …, an, an-1, …, a5, a4, a3, a2, a1, this

[, …, an, an-1, …, a5, a4, _, _, _, _

返回值暫存器: eax/xmm0

相當於this成了原第乙個引數的__fastcall或__vectorcall

i386的頁機制

i386cpu不僅有段機制,而且支援頁機制。乙個32位的邏輯位址經過段機制對映成線性位址後,還要經過頁機制對映成32位的邏輯位址。與頁機制有關的暫存器有 cr3,cr0 cr0的最高位pg是頁對映機制的總開關,如果pg位是1則開啟頁對映機制。cr3暫存器用來存放頁面目錄的首位址。頁面目錄dir,10...

i386和i686的區別

i386和i686 現在所有的intel 32位體系 包括amd等相容cpu 都叫i386體系,包括p4。i686仍然屬於i386體系,不過對cpu 相對於386 的特性作了指令優化。gnu linux分為alpha powerpc sun等各個不同版本,所有從intel386 p4都用i386版本...

i386段式記憶體管理

1 intel x86 cpu段式記憶體管理 1 在保護模式下改變段暫存器的功能,使其從乙個單純的基位址變成向這樣乙個資料結構的指標。這樣,當一條訪問記憶體的指令發出乙個記憶體位址時,cpu就可以這樣來歸納出實際應該放上資料 a.根據指令的性質來確定應該使用哪乙個段暫存器,例如轉移指令中的位址在 段...