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ù)?,并且不會再有rbp的變化,那么棧頂以上的元素我都可以隨便用。
并且我們觀察可以得知,分配??臻g時,他是分配的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ù)原理傳參示例詳解的詳細內(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-01
C++實現(xiàn)LeetCode(132.拆分回文串之二)
這篇文章主要介紹了C++實現(xiàn)LeetCode(132.拆分回文串之二),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07

