go 函数调用规则(二)

承接上文
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

第二个问题是当一个函数调用两个参数不同返回值不同的函数时候函数的栈会怎么分布?
我们的结论是:栈顶是传参的参数 栈底是返回值
多个函数的时候这两块地方就是复用 取最大的来开空间

还有一个问题,我们现在函数的参数 返回值都是六个,那如果我们再多呢?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值