调用约定~

回顾一下

pop指令作用是弹栈,将栈顶的数据弹出到寄存器,然后栈顶指针向下移动一个单位。

具体来说:如pop rax,作用就是mov rax[rsp];add rsp 8

push指令的作用就是压栈,将栈顶指针向上移动一个单位的距离,然后将寄存器的值存放在栈顶。

具体来说:如push rax,其实际效果就是:sub rsp 8;mov [rsp] rax;

jmp:

立即跳转,不涉及函数调用,用于循环、ifelse这种场合。

具体来说:如jmp 1234h,效果就是:mov rip 1234h;

call:

函数调用,需要保存返回地址。

具体来说:如call 1234h,效果就是:push rip;mov rip 1234h;

Ret:

用于函数返回

具体来说,就是pop rip

函数调用流程

void func_a()
{
    //do sth
	return;
}
void func_b()
{
    func_a();
    int c=1;
	return;
}
int main()
{
    func_b();
    int a=2;
	return 0;
}

main调用func_b,func_b调用func_a。

一开始是

栈帧中存放一些main的局部变量

main函数要调用func_b,main只需要call func_b

也就是push rip;mov rip func_b;

此时跳转到func_b继续执行,func_b直接执行主逻辑吗?NO!!!

被调用函数还需要维护栈帧

具体来说是:

push rbp; 将调用函数的栈底指针保存。

mov rbp rsp;将栈底指针指向现在的栈顶。

sub rsp xxx; 开辟被调用函数的栈帧,此时上一步的rbp就指向栈帧的底。

func_b 执行完维护栈帧操作后的栈布局

所谓栈帧的维护就是维护rbp和rsp两个指针

Rsp永远指向栈顶

Rbp用来定位局部变量

func_b要调用func_a,调用流程与main函数调用func_b基本一致

不同在于返回地址、rbp和rsp指向的地址,以及开辟的栈空间不同。

func_b调用完func_a后的栈布局

至此,函数调用已经完毕

func_a执行完毕,要返回了

如何维护栈帧呢?

leave指令

作用是维护栈帧,通常出现在函数的结尾,与ret连用。

其实作用为:mov rsp rbp;pop rbp;

即:将栈顶指针指向栈帧的底部,然后在栈中弹出新的栈底指针

在一个函数执行结束返回时,会执行leave;ret;

实际效果就是:mov rsp rbp;pop rbp;pop rip;

func_a执行完毕返回后,栈布局如图:

一模一样,说明已经恢复了栈帧。

唯一不同的是rip已经指向了c=1

后面一条指令,说明func_a已经执行完毕

以此类推,func_b执行完毕返回后,栈布局如图:

在这之后,main函数继续执行,直到结束。

函数的调用返回执行流程结束。

参数是怎么传递?--调用约定

返回值:一般来说,一个函数的返回值会存储到RAX寄存器。

x86--64函数的调用约定为:

从左至右参数依次传递给rdi、rsi、rcx、r8、r9。

如果一个函数参数多于6个,则从右至左压入栈中传递

32位都是用栈传递

系统调用

syscall指令:

用于调用系统函数,调用时需要指明系统调用号

系统调用号存储rax寄存器中,然后布置好参数,执行syscall即可。

x64:

mmap:系统层面的分配内存

alarm:定时

exit:退出

kill:杀死子进程

execv:执行一个新程序

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值