汇编(四) -- bl&ret

1,577 阅读3分钟

前言

最近准备学习汇编,然后在B站上看到叫iOS小贤的作者发的视频挺不错,打算跟着学,文章是看视频的笔记,最后有原视频链接,想看视频的可以看看通过链接查看视频。

bl和ret指令

bl标号

  • 将下一条指令的地址放入lr(x30)寄存器
  • 转到标号处执行指令

ret

  • 默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址!

ARM64平台的特色指令,它面向硬件做了优化处理的

x30寄存器

x30寄存器存放的是函数的返回地址.当ret指令执行时刻,会寻找x30寄存器保存的地址值!

注意:在函数嵌套调用的时候.需要将x30入栈!

代码演练

写一个sum函数

屏幕快照 2019-08-04 下午6.12.47.png

然后在sum处打断点,run起来。

屏幕快照 2019-08-04 下午6.12.25.png

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

屏幕快照 2019-08-04 下午6.18.54.png

然后继续往下走

屏幕快照 2019-08-04 下午6.20.07.png

果然走到我们改写的位置,没有出退出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。

屏幕快照 2019-08-04 下午6.29.50.png

我们调试试试看

屏幕快照 2019-08-04 下午6.38.41.png
此时lr是0x00000001025ba948,bl下一个指令地址是0x1025ba950,接下来输入s,进入A函数。

屏幕快照 2019-08-04 下午6.41.16.png

lr变成了0x00000001025ba950,也就是指令adrp x0, 1的地址。 现在要进入B函数,那么lr要保存bl下一条指令的地址,也就是mov x0, #0xbbbb的地址0x1025babe4,接下来进入B函数。

屏幕快照 2019-08-04 下午6.45.51.png

然后不断往下走就又回到A函数,lr仍然是0x1025babe4,我们一直单步往下走,会发现死循环。

屏幕快照 2019-08-04 下午6.49.17.png

接下来再写两个函数C和D:

屏幕快照 2019-08-04 下午6.56.08.png

然后打断点

屏幕快照 2019-08-04 下午6.58.21.png

此时不要s,按住control键,点击箭头进入D函数

屏幕快照 2019-08-04 下午6.59.11.png

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)。

屏幕快照 2019-08-04 下午7.08.38.png

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,说明这次没有问题了。

屏幕快照 2019-08-04 下午7.24.59.png

###参考: bl&ret
汇编(五)