前言
最近准备学习汇编,然后在B站上看到叫iOS小贤的作者发的视频挺不错,打算跟着学,文章是看视频的笔记,最后有原视频链接,想看视频的可以看看通过链接查看视频。
bl和ret指令
bl标号
- 将下一条指令的地址放入lr(x30)寄存器
- 转到标号处执行指令
ret
- 默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址!
ARM64平台的特色指令,它面向硬件做了优化处理的
x30寄存器
x30寄存器存放的是函数的返回地址.当ret指令执行时刻,会寻找x30寄存器保存的地址值!
注意:在函数嵌套调用的时候.需要将x30入栈!
代码演练
写一个sum函数
然后在sum处打断点,run起来。
bl跳转到sum函数中去,跳到sum函数中后一旦返回,就要返回到0x102d16974 <+36>: mov w1, #0x0
处,需要需要把0x102d16974
存到lr(x30)中。
下面我们来改写lr(x30),先进入sun函数,然后走到add sp, sp, #0x10
处,然后输入
register write lr 0x102d16934
register read lr
然后继续往下走
果然走到我们改写的位置,没有出退出sum函数。ret指令其实就是找lr(x30)。
接下来再写一段汇编:
.text
.global _A,_B
_A:
mov x0, #0xaaaa
bl _B
mov x0, #0xbbbb
ret
_B:
mov x0, #0xcccc
ret
然后调用A(),我们发现只打印了A。
我们调试试试看
此时lr是
0x00000001025ba948
,bl下一个指令地址是0x1025ba950
,接下来输入s,进入A函数。
lr变成了0x00000001025ba950,也就是指令adrp x0, 1
的地址。
现在要进入B函数,那么lr要保存bl下一条指令的地址,也就是mov x0, #0xbbbb
的地址0x1025babe4
,接下来进入B函数。
然后不断往下走就又回到A函数,lr仍然是0x1025babe4
,我们一直单步往下走,会发现死循环。
接下来再写两个函数C和D:
然后打断点
此时不要s,按住control键,点击箭头进入D函数
stp x29, x30, [sp, #-0x10]!
这条指令是进过优化的简写,[sp, #-0x10]!
是sp减去0x10然后赋值给sp,这段代码相当于
sub sp, sp, #0x10
stp x29, x30, [sp]
我们可以看到现在sp是0x000000016d7eb8e0
,然后我们ni,发现sp确实是变成了0x000000016d7eb8d0
(0x000000016d7eb8e0
减去0x10)。
stp x29, x30, [sp, #-0x10]!
我们看到在函数最开始先把x29和写x30的值放入栈中。ldp x29, x30, [sp], #0x10
然后在函数在函数调用完毕之前把栈中数据又放入x29和x30中,这样就保护了x29和x30两个寄存器。
完善之前汇编代码
.text
.global _A,_B
_A:
mov x0, #0xaaaa
str x30, [sp, #-0x10]!
bl _B
mov x0, #0xbbbb
ldr x30, [sp], #0x10
ret
_B:
mov x0, #0xcccc
ret
注: 我们只需要保存x30,不需要保存x29。这里需要再次说明,0x10不能用0x8,8个字节,之前讲过对栈的操作是16个字节对齐,所以可以用0x20,0x30......
运行代码,打印AB,说明这次没有问题了。