【学习记录】关于C语言使用函数指针参数传递过程中参数数量变多的情况

直接看代码

int get_gata3(int* da1,int* da2,int *da3){
    *da1=1;
    *da2=2;
    *da3=3;
    return 0;
}
int get_gata2(int* da1,int* da2){
    *da1=1;
    *da2=2;
    return 0;
}
int main(){
    // sum(1,2);
    int (*get_data)(int*,int*,int*);
    get_data=(int (*)(int *, int *, int *))get_gata2;
    int a=3,b=4,c=5;
    get_data(&a,&b,&c);
}

首先这里是通过函数进行对a b c三个变量重新赋值,正常的只传递参数也是相同的效果。示例中给函数get_gata2传递了三个参数,但实际上这个函数只有两个参数。接下来看汇编代码

	.arch armv8-a
	.file	"main.c"
	.text
	.align	2
	.global	get_gata3
	.type	get_gata3, %function
get_gata3:
	sub	sp, sp, #32
	str	x0, [sp, 24]
	str	x1, [sp, 16]
	str	x2, [sp, 8]
	ldr	x0, [sp, 24]
	mov	w1, 1
	str	w1, [x0]
	ldr	x0, [sp, 16]
	mov	w1, 2
	str	w1, [x0]
	ldr	x0, [sp, 8]
	mov	w1, 3
	str	w1, [x0]
	mov	w0, 0
	add	sp, sp, 32
	ret
	.size	get_gata3, .-get_gata3
	.align	2
	.global	get_gata2
	.type	get_gata2, %function
get_gata2:
	sub	sp, sp, #16
	str	x0, [sp, 8]
	str	x1, [sp]
	ldr	x0, [sp, 8]
	mov	w1, 1
	str	w1, [x0]
	ldr	x0, [sp]
	mov	w1, 2
	str	w1, [x0]
	mov	w0, 0
	add	sp, sp, 16
	ret
	.size	get_gata2, .-get_gata2
	.align	2
	.global	main
	.type	main, %function
main:
	stp	x29, x30, [sp, -48]!
	add	x29, sp, 0
	adrp	x0, :got:__stack_chk_guard
	ldr	x0, [x0, #:got_lo12:__stack_chk_guard]
	ldr	x1, [x0]
	str	x1, [x29, 40]
	mov	x1,0
	adrp	x0, get_gata2
	add	x0, x0, :lo12:get_gata2
	str	x0, [x29, 32]
	mov	w0, 3
	str	w0, [x29, 20]
	mov	w0, 4
	str	w0, [x29, 24]
	mov	w0, 5
	str	w0, [x29, 28]
	add	x2, x29, 28
	add	x1, x29, 24
	add	x0, x29, 20
	ldr	x3, [x29, 32]
	blr	x3
	mov	w0, 0
	adrp	x1, :got:__stack_chk_guard
	ldr	x1, [x1, #:got_lo12:__stack_chk_guard]
	ldr	x2, [x29, 40]
	ldr	x1, [x1]
	eor	x1, x2, x1
	cmp	x1, 0
	beq	.L7
	bl	__stack_chk_fail
.L7:
	ldp	x29, x30, [sp], 48
	ret
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
	.section	.note.GNU-stack,"",@progbits

我把其中重要的部分提取出来解释,首先主函数部分

	adrp	x0, get_gata2
	add	x0, x0, :lo12:get_gata2
	str	x0, [x29, 32]

此段将函数get_gata2的地址放如栈中偏移40的地址。

	mov	w0, 3
	str	w0, [x29, 20]
	mov	w0, 4
	str	w0, [x29, 24]
	mov	w0, 5
	str	w0, [x29, 28]
	add	x2, x29, 28
	add	x1, x29, 24
	add	x0, x29, 20
	ldr	x3, [x29, 32]
	blr	x3

此段[x29, 20] [x29, 24] [x29, 28]三个分别是三个局部变量a,b,c在栈上的地址,这一步就是给局部变量赋初始值。
接下来

	add	x2, x29, 28
	add	x1, x29, 24
	add	x0, x29, 20

将局部变量的地址给x0 x1 x2,函数传递参数较少的情况下是使用寄存器传值的。这三个寄存器的值会在函数中使用
然后是

	ldr	x3, [x29, 32]
	blr	x3

拿到函数的地址,也就是get_gata2的地址然后跳转过去。
接下来看函数内部

get_gata2:
	sub	sp, sp, #16
	str	x0, [sp, 8]
	str	x1, [sp]
	ldr	x0, [sp, 8]
	mov	w1, 1
	str	w1, [x0]
	ldr	x0, [sp]
	mov	w1, 2
	str	w1, [x0]
	mov	w0, 0
	add	sp, sp, 16
	ret
	.size	get_gata2, .-get_gata2
	.align	2
	.global	main
	.type	main, %function

注意前三行,这里就是C语言传递参数为什么要指针才能把值带出来的原因了,
参数在传递过程中首先在栈上开了内存
然后将x0(a的地址) 存储在栈上 位置[sp, 8]
将x1(b的地址) 存储在栈上 位置[sp]
然后因为没有第三个参数,所有寄存器x2的地址被废弃,也不会被保存。
mov w0, 0 是返回值。
所以由此看来,可以多传参数(会被丢弃),但是不能少穿,少穿会导致不可预知的后果,因为多余参数的数值我们并不能知道,
就比如get_gata2只传递一个参数,那么在运行时 x1的值就不能确定,赋值时就会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值