2.特殊的代码块(函数)是通过什么实现的

zha函数的调用是类似if-else,while,for的跳转,只不过方式不一样,这三个跳转完后就不会再回去了,但函数调用不同,他需要回到函数调用的地方把运算的结果带回去。

但回到最初位置却带来了问题:

1.不跳转直接回到开始的地方

具体:把调用的函数指令插入到函数调用位置进行替换,在编译器编译代码是把函数调用的代码换掉。但是有新问题,这如果只有一个函数确实没什么问题,但如果一个函数内部有另一个函数呢(A中有B,A需要调用A,B也需要调用A这就成了死循环)

2.像指令地址寄存器一样创建一个程序调用的寄存器,来存储要跳回来的指令地址,然后从寄存器中取出,在跳转到那。但还是一样的问题 如果是多重调用呢,调用A之后,A调B,B调C···在所有函数调用返回前都要记录每一次的地址值,但寄存器空间是有限的而且CPU内部的寄存器也是有限的,一旦调用的层数多了就存不下了。

最有便有了栈这种数据结构【开辟在内存中】(先进后出)

即函数调用是把函数指令输入栈中(压栈)

取得时候从后面取,后面的就是函数的返回地址因此便做到了函数调用(出栈)

多重调用的问题也是一样解决,看成塞球,返回地址便是球,栈是球桶,假如调用A中有B,那么先放A进去然后放B;取得时候先拿到B因此先跳转然后再拿A

{函数执行完了拿B进行跳转,然后再执行A再跳转}

**问题不是执行函数,而是函数执行后怎么跳转回调用位置

在现实中压栈的不只是返回地址还有一些类似要传输的数据等等(寄存器满了放不下了)这是函数A的所占用的内存空间就是函数A的栈帧(可以理解是函数A需要的内存空间被框起来放进栈里)

实际的程序栈布局的底在上面的(即从下往上压栈,这过程中栈顶(返回地址)的内存地址不断变小)

个人理解

栈的使用是通过维持rsp(记录栈顶),rbp(记录当前栈)来管理函数之前的跳转,例如A中有B,先压A再压B,然后rsp记录的就是B的跳转地址,接着吧指令赋给rbp,根据rbp进行跳转(在ret指令时会自动出栈【pc寄存器拿到出栈的B的跳转地址】,此时栈顶是B的地址),此时B已出栈,因此栈顶是A的地址,重复上面操作跳转回A的跳转地址。

栈的使用错误一般有Stack overflow

原理:栈的大小是有限的,不断调用函数压栈最后会溢出栈的内存大小,

除此之外还要一次在栈空间里创建过大变量(如一个超大的数组)也会栈溢出。

上述中有一个方法是吧函数产生的指令直接放到函数调用位置进行替换,前提是不能是多个函数调用,这种就是一个常见的编译器进行自动优化的场景,称为函数内联

优势:内联的优势就是CPU执行的指令少了,还不用压栈等操作,

缺点:一旦调用次数过多反而需要展开多次,得不偿失

总结:程序栈相当于记忆功能,给跳转后提供后路,实现了更灵活的指令执行流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值