平时,绝大部分时间我们都基本是使用C语言进行程序的编写。而在C语言中,函数的调用是很简单:只需要把函数名写好,参数填好,然后放在需要调用的地方就行了。但是如果用汇编来写的话就不会这么简单了。下面我们从汇编的方式上对函数的调用进行一下理解。
- 我们知道PC寄存器的值是指向当前执行指令的地址,但往往调用函数和被调用函数他们的地址是不相连的,这里就引出了第一点--需要将PC的值进行更改,让其指向被调用函数的地址,一般使用BL或BLX指令。
- 当PC指向被调用函数后,我们就可以愉快的进行函数的执行了吗?这里就需要了解另一个知识点了:内核在执行每个指令时,具体执行的各种数据都是依靠内核上的寄存器的,也就是说内核上的寄存器往往保存了当前函数所需要的信息。问题来了,如果我们在PC指向被调用函数后,直接执行函数,那么当前函数的信息就会覆盖掉之前函数放在内核寄存器上的值,当我们重新回到调用函数时,会发现信息全变了,本来放1的寄存器现在放0,全乱套了。所以我们需要把那些存放了关键信息的寄存器数据给保存起来。这里保存的机制就是压栈:将需要保存的数据PUSH到内存里。
- PUSH好数据后就可以开始正常执行函数,但函数执行过程中往往会有新变量创建,新变量在哪创建?栈中啊!你就会突然发现:你之前保存好的数据上方在函数执行过程中被一些数据给压在下面了,而SP指针只能指向栈顶,你看不到保存的数据了。这就意味着,但函数执行完毕后,我们想回去了,但是之前保存好的数据取不出来了。虽然我们把数据给放进保险箱里保护起来了,但是保险箱被土给埋起来了。那我们该如何把他们给取出来呢?最方便的方法:这个函数占用了多大的栈,我们用当前的SP值减去它就行了,SP就可以指向我们保存数据的位置,然后使用POP指令打卡保险箱就行了,之前保存好的信息就会回到原位。
- 通过将保存再LR寄存器内的地址复制到PC中,就可以回到当初调用函数时的位置了,一般为BX或BXL指令或将保存好的lr都值push到pc。