C/C++ 函數(shù)原理傳參示例詳解
x84-64的寄存器
本文所用gcc
為 x86-64 gcc 10.1
wiki.cdot.senecacollege.ca/wiki/X86_64…
rax - register a extended
rbx - register b extended
rcx - register c extended
rdx - register d extended
rbp - register base pointer (start of stack)
rsp - register stack pointer (current location in stack, growing downwards)
rsi - register source index (source for data copies)
rdi - register destination index (destination for data copies)
其他寄存器: r8 r9 r10 r11 r12 r13 r14 r15
函數(shù)是個什么東西?
一個簡單的函數(shù)
int func(){} int main() { int x = 2; func(); }
main: pushq %rbp movq %rsp, %rbp subq $16, %rsp movl $2, -4(%rbp) call func() movl $0, %eax leave ret
分配空間動作如下所示:
這里加了個函數(shù)調(diào)用是因為在有些時候,沒有函數(shù)調(diào)用,就不會使用subq $16, %rsp
這一條指令,我的猜想是既然你都是棧頂?shù)模⑶也粫儆衦bp的變化,那么棧頂以上的元素我都可以隨便用。
并且我們觀察可以得知,分配棧空間時,他是分配的16個字節(jié),也就是說,有對齊
返回時,彈出棧頂,就可以恢復(fù)到上一個棧幀的狀態(tài)了。
傳參姿勢
入棧規(guī)則
c/c++ 中規(guī)定的函數(shù)壓棧順序是從右到左,當(dāng)然,如果你是 Visual C/C++的話,它們有更多的玩法 比如:
template<typename T> T val(T t) { cout << t << endl; return t; } signed main() { printf("%d%d%d", val(1), val(2), val(3)); return 0; }
結(jié)果
3
2
1
123
看看匯編
int func(int x, int y, int z) { return 0; } int main() { func(1, 2, 3); }
生成的匯編
func(int, int, int): pushq %rbp movq %rsp, %rbp movl %edi, -4(%rbp) movl %esi, -8(%rbp) movl %edx, -12(%rbp) movl $0, %eax popq %rbp ret main: pushq %rbp movq %rsp, %rbp movl $3, %edx movl $2, %esi movl $1, %edi call func(int, int, int) movl $0, %eax popq %rbp ret
上文中可以看出,也證實了我們所觀察到的,首先把3傳給了edx,2傳給了esi,1傳給了edi
全都存寄存器嗎?
寄存器畢竟少,當(dāng)然,還可以存在棧上嘛
int fun() {return 0;} int func(int x, int y, int z, int a, int b, int c, int d, int e, int f){ fun(); return e; } int main() { func(1, 2, 3, 4, 5, 6, 7, 8, 9); return 0; }
fun(): pushq %rbp movq %rsp, %rbp movl $0, %eax popq %rbp ret func(int, int, int, int, int, int, int, int, int): pushq %rbp movq %rsp, %rbp subq $24, %rsp movl %edi, -4(%rbp) movl %esi, -8(%rbp) movl %edx, -12(%rbp) movl %ecx, -16(%rbp) movl %r8d, -20(%rbp) movl %r9d, -24(%rbp) call fun() movl 24(%rbp), %eax leave ret main: pushq %rbp movq %rsp, %rbp pushq $9 // 24+%rbp pushq $8 // 16+%rbp pushq $7 // 8 +%rbp movl $6, %r9d movl $5, %r8d movl $4, %ecx movl $3, %edx movl $2, %esi movl $1, %edi call func(int, int, int, int, int, int, int, int, int) addq $24, %rsp movl $0, %eax leave ret
主函數(shù)中的這三條語句
pushq $9 pushq $8 pushq $7
說明了,當(dāng)函數(shù)入棧放寄存器放不下時,會放在棧上,放在棧頂之上,等函數(shù)調(diào)用執(zhí)行完成后,rbp取出回到當(dāng)前位置之后,再去addq $24, %rsp
把棧彈出這些元素。
并且func函數(shù)中的movl 24(%rbp), %eax
也證明了,傳的參數(shù)是在棧頂?shù)纳厦妫ㄗ陨舷蛳略鲩L) 24 + %rbp
剛好是 $9
, 也就是局部變量f的位置
傳對象呢?
在這里,暫且不談內(nèi)存布局,把一個對象看成一塊內(nèi)存對于的位置
這里用一個結(jié)構(gòu)體做示例
struct E {int x, y, z;}; E func(E e){ e.x = 2; return e; } int main() { E e = {.x = 1, .y = 2, .z = 3}; e = func(e); return 0; }
func(E): pushq %rbp movq %rsp, %rbp // 將rdi 和 esi 取出來 放到 rdx 和 eax 中 movq %rdi, %rdx movl %esi, %eax // 存放到開辟好的空間中 {x = rbp - 32, y = rbp - 28, z = rbp - 24} movq %rdx, -32(%rbp) movl %eax, -24(%rbp) // 更改 x movl $2, -32(%rbp) // 將值移動到寄存器上,從返回寄存器上移動到局部返回出去的變量 movq -32(%rbp), %rax movq %rax, -12(%rbp) movl -24(%rbp), %eax movl %eax, -4(%rbp) // 將返回值值移動到寄存器上 rax rdx 上 movq -12(%rbp), %rax movl -4(%rbp), %ecx movq %rcx, %rdx popq %rbp ret main: // 壓棧保存現(xiàn)場 沒什么好說的 pushq %rbp movq %rsp, %rbp subq $16, %rsp // 內(nèi)存布局 rbp | z rbp - 4 | y rbp - 8 | x rbp - 12 movl $1, -12(%rbp) movl $2, -8(%rbp) movl $3, -4(%rbp) // 移動 x 和 y 到 rdx 寄存器中 movq -12(%rbp), %rdx // 移動 z 到 eax中 movl -4(%rbp), %eax // 再將 rdx 和 eax 分別移動到rdi 和 esi中 movq %rdx, %rdi movl %eax, %esi call func(E) // 從rax 中取出x y movq %rax, -12(%rbp) // 從rdx中取出z movl -4(%rbp), %eax andl $0, %eax orl %edx, %eax // movl %eax, -4(%rbp) movl $0, %eax leave ret
以上就是C/C++ 函數(shù)原理傳參示例詳解的詳細(xì)內(nèi)容,更多關(guān)于C/C++ 函數(shù)原理傳參的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++基礎(chǔ)學(xué)習(xí)之函數(shù)重載的簡單介紹
函數(shù)重載是一種特殊情況,C++允許在同一作用域中聲明幾個類似的同名函數(shù),這些同名函數(shù)的形參列表(參數(shù)個數(shù),類型,順序)必須不同,常用來處理實現(xiàn)功能類似數(shù)據(jù)類型不同的問題。這篇文章主要給大家介紹了關(guān)于C++基礎(chǔ)學(xué)習(xí)之函數(shù)重載的相關(guān)資料,需要的朋友可以參考下2019-01-01C++實現(xiàn)LeetCode(132.拆分回文串之二)
這篇文章主要介紹了C++實現(xiàn)LeetCode(132.拆分回文串之二),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07