【学习记录】关于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
.align2
.globalget_gata3
.typeget_gata3, %function
get_gata3:
subsp, sp, #32
strx0, [sp, 24]
strx1, [sp, 16]
strx2, [sp, 8]
ldrx0, [sp, 24]
movw1, 1
strw1, [x0]
ldrx0, [sp, 16]
movw1, 2
strw1, [x0]
ldrx0, [sp, 8]
movw1, 3
strw1, [x0]
movw0, 0
addsp, sp, 32
ret
.sizeget_gata3, .-get_gata3
.align2
.globalget_gata2
.typeget_gata2, %function
get_gata2:
subsp, sp, #16
strx0, [sp, 8]
strx1, [sp]
ldrx0, [sp, 8]
movw1, 1
strw1, [x0]
ldrx0, [sp]
movw1, 2
strw1, [x0]
movw0, 0
addsp, sp, 16
ret
.sizeget_gata2, .-get_gata2
.align2
.globalmain
.typemain, %function
main:
stpx29, x30, [sp, -48]!
addx29, sp, 0
adrpx0, :got:__stack_chk_guard
ldrx0, [x0, #:got_lo12:__stack_chk_guard]
ldrx1, [x0]
strx1, [x29, 40]
movx1,0
adrpx0, get_gata2
addx0, x0, :lo12:get_gata2
strx0, [x29, 32]
movw0, 3
strw0, [x29, 20]
movw0, 4
strw0, [x29, 24]
movw0, 5
strw0, [x29, 28]
addx2, x29, 28
addx1, x29, 24
addx0, x29, 20
ldrx3, [x29, 32]
blrx3
movw0, 0
adrpx1, :got:__stack_chk_guard
ldrx1, [x1, #:got_lo12:__stack_chk_guard]
ldrx2, [x29, 40]
ldrx1, [x1]
eorx1, x2, x1
cmpx1, 0
beq.L7
bl__stack_chk_fail
.L7:
ldpx29, x30, [sp], 48
ret
.sizemain, .-main
.ident"GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
.section.note.GNU-stack,"",@progbits
我把其中重要的部分提取出来解释,首先主函数部分
adrpx0, get_gata2
addx0, x0, :lo12:get_gata2
strx0, [x29, 32]
此段将函数get_gata2的地址放如栈中偏移40的地址。
movw0, 3
strw0, [x29, 20]
movw0, 4
strw0, [x29, 24]
movw0, 5
strw0, [x29, 28]
addx2, x29, 28
addx1, x29, 24
addx0, x29, 20
ldrx3, [x29, 32]
blrx3
此段[x29, 20] [x29, 24] [x29, 28]三个分别是三个局部变量a,b,c在栈上的地址,这一步就是给局部变量赋初始值。
接下来
addx2, x29, 28
addx1, x29, 24
addx0, x29, 20
将局部变量的地址给x0 x1 x2,函数传递参数较少的情况下是使用寄存器传值的。这三个寄存器的值会在函数中使用
然后是
ldrx3, [x29, 32]
blrx3
拿到函数的地址,也就是get_gata2的地址然后跳转过去。
接下来看函数内部
get_gata2:
subsp, sp, #16
strx0, [sp, 8]
strx1, [sp]
ldrx0, [sp, 8]
movw1, 1
strw1, [x0]
ldrx0, [sp]
movw1, 2
strw1, [x0]
movw0, 0
addsp, sp, 16
ret
.sizeget_gata2, .-get_gata2
.align2
.globalmain
.typemain, %function
注意前三行,这里就是C语言传递参数为什么要指针才能把值带出来的原因了,
参数在传递过程中首先在栈上开了内存
然后将x0(a的地址) 存储在栈上 位置[sp, 8]
将x1(b的地址) 存储在栈上 位置[sp]
然后因为没有第三个参数,所有寄存器x2的地址被废弃,也不会被保存。
mov w0, 0 是返回值。
所以由此看来,可以多传参数(会被丢弃),但是不能少穿,少穿会导致不可预知的后果,因为多余参数的数值我们并不能知道,
就比如get_gata2只传递一个参数,那么在运行时 x1的值就不能确定,赋值时就会报错。
原文地址:https://blog.csdn.net/liarsup/article/details/143501700
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!