承接上文
go 函数调用规则(一)
我们试图改变这个源码
package main
func val(a, b, c, d, e, f int) (a1 int, b1 int, c1 int, d1 int, e1 int, f1 int) {
a1 = a + 2
b1 = b * 2
c1 = c + 3
d1 = d * 3
e1 = e + 4
f1 = f * 4
return
}
func vall(a, b, c, d, e int) (a1 int, b1 int, c1 int, d1 int, e1 int) {
a1 = a + 22
b1 = b * 22
c1 = c + 33
d1 = d * 33
e1 = e + 44
return
}
func test() {
a1, a2, a3, a4, a5, a6 := val(1, 2, 3, 4, 5, 6)
b1, b2, b3, b4, b5 := vall(11, 22, 33, 44, 55)
var c int = a1 + a2 + a3 + a4 + a5 + b1 + b2 + b3 + b4 + b5 + a6
c = c + 2
}
func main() {
test()
}
这个程序就要复杂一下了
我们慢慢看
main函数没啥可说的
就是正常的调用
sub rsp, 8
mov [rsp+8+var_8], rbp
lea rbp, [rsp+8+var_8]
call main_test
mov rbp, [rsp+8+var_8]
add rsp, 8
nop
retn
test
var_98= qword ptr -98h
var_90= qword ptr -90h
var_88= qword ptr -88h
var_80= qword ptr -80h
var_78= qword ptr -78h
var_70= qword ptr -70h
var_68= qword ptr -68h
var_60= qword ptr -60h
var_58= qword ptr -58h
var_50= qword ptr -50h
var_48= qword ptr -48h
var_40= qword ptr -40h
var_38= qword ptr -38h
var_30= qword ptr -30h
var_28= qword ptr -28h
var_20= qword ptr -20h
var_18= qword ptr -18h
var_10= qword ptr -10h
var_8= qword ptr -8
sub rsp, 0C8h #栈直接拉了0xc8
mov [rsp+0C8h+var_8], rbp #栈底当然还是rbp栈底指针
lea rbp, [rsp+0C8h+var_8]
mov eax, 1 #这次把六个参数分别放在了eax ebx ecx edi esi r8d
mov ebx, 2
mov ecx, 3
mov edi, 4
mov esi, 5
mov r8d, 6
call main_val #然后调函数
#rax rbx rcx rdi rsi r8这六个寄存器里面是返回值
#调用函数的时候栈顶六个直接是参数
mov [rsp+0C8h+var_10], rax #然后这六个返回值先放在栈指针上面六个
mov [rsp+0C8h+var_18], rbx #紧接着又往上再复制了一次
mov [rsp+0C8h+var_20], rcx
mov [rsp+0C8h+var_28], rdi
mov [rsp+0C8h+var_30], rsi
mov [rsp+0C8h+var_38], r8
mov rdx, [rsp+0C8h+var_10]
mov [rsp+0C8h+var_40], rdx
mov rdx, [rsp+0C8h+var_18]
mov [rsp+0C8h+var_48], rdx
mov rdx, [rsp+0C8h+var_20]
mov [rsp+0C8h+var_50], rdx
mov rdx, [rsp+0C8h+var_28]
mov [rsp+0C8h+var_58], rdx
mov rdx, [rsp+0C8h+var_30]
mov [rsp+0C8h+var_60], rdx
mov rdx, [rsp+0C8h+var_38]
mov [rsp+0C8h+var_68], rdx
mov eax, 0Bh #调用另一个函数的时候直接传参
mov ebx, 16h
mov ecx, 21h ; '!'
mov edi, 2Ch ; ','
mov esi, 37h ; '7'
call main_vall #调用vall
mov [rsp+0C8h+var_38], rax #用的是离栈进的五个 这没关系 之前的数据复制在了上面
mov [rsp+0C8h+var_30], rbx
mov [rsp+0C8h+var_28], rcx
mov [rsp+0C8h+var_20], rdi
mov [rsp+0C8h+var_18], rsi
mov rdx, [rsp+0C8h+var_38]
mov [rsp+0C8h+var_70], rdx #他也把数据复制过来
mov rdx, [rsp+0C8h+var_30]
mov [rsp+0C8h+var_78], rdx
mov rdx, [rsp+0C8h+var_28]
mov [rsp+0C8h+var_80], rdx
mov rdx, [rsp+0C8h+var_20]
mov [rsp+0C8h+var_88], rdx
mov rdx, [rsp+0C8h+var_18]
mov [rsp+0C8h+var_90], rdx
mov rdx, [rsp+0C8h+var_40]
add rdx, [rsp+0C8h+var_48]
add rdx, [rsp+0C8h+var_50]
add rdx, [rsp+0C8h+var_58]
add rdx, [rsp+0C8h+var_60]
add rdx, [rsp+0C8h+var_70]
add rdx, [rsp+0C8h+var_78]
add rdx, [rsp+0C8h+var_80]
add rdx, [rsp+0C8h+var_88]
add rdx, [rsp+0C8h+var_90]
add rdx, [rsp+0C8h+var_68]
mov [rsp+0C8h+var_98], rdx
add rdx, 2
mov [rsp+0C8h+var_98], rdx
mov rbp, [rsp+0C8h+var_8]
add rsp, 0C8h
retn
val
public main_val
main_val proc near
var_38= qword ptr -38h #其实从这上面就能看得出来六个参数六个返回地址
var_30= qword ptr -30h
var_28= qword ptr -28h
var_20= qword ptr -20h
var_18= qword ptr -18h
var_10= qword ptr -10h
var_8= qword ptr -8
arg_0= qword ptr 8
arg_8= qword ptr 10h
arg_10= qword ptr 18h
arg_18= qword ptr 20h
arg_20= qword ptr 28h
arg_28= qword ptr 30h
sub rsp, 38h #栈
mov [rsp+38h+var_8], rbp
lea rbp, [rsp+38h+var_8]
mov [rsp+38h+arg_0], rax #六个参数分别归为
mov [rsp+38h+arg_8], rbx #顺序还是stdcall从右往左压栈顺序
mov [rsp+38h+arg_10], rcx
mov [rsp+38h+arg_18], rdi
mov [rsp+38h+arg_20], rsi
mov [rsp+38h+arg_28], r8
mov [rsp+38h+var_10], 0 #六个临时变量清零
mov [rsp+38h+var_18], 0
mov [rsp+38h+var_20], 0
mov [rsp+38h+var_28], 0
mov [rsp+38h+var_30], 0
mov [rsp+38h+var_38], 0
mov rdx, [rsp+38h+arg_0] #下面又是计算过程 可以不看
add rdx, 2
mov [rsp+38h+var_10], rdx
mov rdx, [rsp+38h+arg_8]
shl rdx, 1
mov [rsp+38h+var_18], rdx
mov rdx, [rsp+38h+arg_10]
add rdx, 3
mov [rsp+38h+var_20], rdx
mov rdx, [rsp+38h+arg_18]
lea rdx, [rdx+rdx*2]
mov [rsp+38h+var_28], rdx
mov rdx, [rsp+38h+arg_20]
add rdx, 4
mov [rsp+38h+var_30], rdx
mov r8, [rsp+38h+arg_28]
shl r8, 2
mov [rsp+38h+var_38], r8
mov rax, [rsp+38h+var_10] #返回也是这六个寄存器返回的
mov rbx, [rsp+38h+var_18]
mov rcx, [rsp+38h+var_20]
mov rdi, [rsp+38h+var_28]
mov rsi, [rsp+38h+var_30]
mov rbp, [rsp+38h+var_8]
add rsp, 38h
retn
main_val endp
vall
public main_vall
main_vall proc near
var_30= qword ptr -30h
var_28= qword ptr -28h
var_20= qword ptr -20h
var_18= qword ptr -18h
var_10= qword ptr -10h
var_8= qword ptr -8
arg_0= qword ptr 8
arg_8= qword ptr 10h
arg_10= qword ptr 18h
arg_18= qword ptr 20h
arg_20= qword ptr 28h
sub rsp, 30h
mov [rsp+30h+var_8], rbp
lea rbp, [rsp+30h+var_8] #其他的没啥 重点是关注它的参数还是放在了栈下面
mov [rsp+30h+arg_0], rax
mov [rsp+30h+arg_8], rbx
mov [rsp+30h+arg_10], rcx
mov [rsp+30h+arg_18], rdi
mov [rsp+30h+arg_20], rsi
mov [rsp+30h+var_10], 0
mov [rsp+30h+var_18], 0
mov [rsp+30h+var_20], 0
mov [rsp+30h+var_28], 0
mov [rsp+30h+var_30], 0
mov rdx, [rsp+30h+arg_0]
add rdx, 16h
mov [rsp+30h+var_10], rdx
mov rdx, [rsp+30h+arg_8]
imul rdx, 16h
mov [rsp+30h+var_18], rdx
mov rdx, [rsp+30h+arg_10]
add rdx, 21h ; '!'
mov [rsp+30h+var_20], rdx
mov rdx, [rsp+30h+arg_18]
mov r8, rdx
shl rdx, 5
add rdx, r8
mov [rsp+30h+var_28], rdx
mov rdx, [rsp+30h+arg_20]
lea rsi, [rdx+2Ch]
mov [rsp+30h+var_30], rsi
mov rax, [rsp+30h+var_10]
mov rbx, [rsp+30h+var_18]
mov rcx, [rsp+30h+var_20]
mov rdi, [rsp+30h+var_28]
mov rbp, [rsp+30h+var_8]
add rsp, 30h
retn
main_vall endp
总结一下
我们这次实验重点就是想解决两个问题
第一个传参 返回值使用寄存器是啥?
现在的结果是 rax rbx rcx rdi rsi r8
第二个问题是当一个函数调用两个参数不同返回值不同的函数时候函数的栈会怎么分布?
我们的结论是:栈顶是传参的参数 栈底是返回值
多个函数的时候这两块地方就是复用 取最大的来开空间
还有一个问题,我们现在函数的参数 返回值都是六个,那如果我们再多呢?