ARM 汇编基础:函数和流程分支汇编
上一篇中,我们学习了 ,本篇我们继续看一下函数对应的汇编,从而了解函数的本质。
我们知道,调用函数的时候,汇编代码会首先开辟一段栈空间,用于存放参数、局部变量以及对寄存器进行保护,那么这些是怎么完成的呢?
先来看一段函数的代码:
运行工程,查看生成的汇编代码: 栈平衡(也就是回收函数所开辟的栈空间,这也就是我们在函数中声明的局部变量,出了这个函数就无法使用的原因)
上面的汇编代码,重要的都加了注释进行说明。从汇编代码可以清晰的看到,参数分别存储在 w0 和 w1 寄存器。
【函数 sum】的返回值存储在 w0 寄存器。
实际上,我们可以通过自己的代码,来验证一下:
叶子函数:函数中不再调用其他函数,就称为叶子函数,叶子函数不需要开辟栈空间。
经过上面的代码,我们总结一下:
- 函数的返回值,通常都放在 x0寄存器 中。
- 函数的参数,存放在 x0-x7 (w0-w7) 这 8 个寄存器里面。如果超过 8 个参数,则会入栈。
小示例:超过 8 个参数的函数
从汇编代码可以看到,【90】这个参数先放在了 w8 寄存器,然后入栈了:
在【函数 sumB】中求和的时候,是从栈中将参数【90】读取到 w1 寄存器,然后再相加的:
【思考】:在OC中,我们怎么知道调用的是哪个类的哪个方法?
在上面的代码演示过程中,我们可以看到,参数是保存在【x0】 -- 【x7】寄存器中的,OC 方法的调用,本质上是调用 objc_msgSend(id, SEL) 函数,第一个参数和第二个参数分别存放在 x0 和 x1 寄存器中,对应的就是具体的对象和具体的方法。因此我们查看 x0 和 x1 寄存器的值,就知道是哪个类的哪个方法了。
我们还是先上代码,从代码中来学习,比纯讲理论,要印象深刻:
运行工程,查看生成的汇编,下面的汇编代码,都添加了注释,方便大家理解:
从汇编代码可以看到,局部变量做了入栈操作,进行参数的保存。
上面的汇编代码,我们都是利用 Xcode 断点运行,开启【Debug】-【Debug Workflow】-【Always Show Disassembly】,通过 Xcode 调试中的信息查看到的。实际上,我们可以利用 IDA(神器,不解释)或者 Hopper,直接查看汇编代码。
打开 Xcode,新建一个示例工程,编写代码:
Xcode 直接编译工程,拷贝出生成的 .app 文件,显示包内容,拿到可执行文件,然后使用 IDA/Hopper 打开,如下图所示:
实际上,IDA/Hopper 会在汇编代码中,添加一些辅助的变量和其他内容,来更好的帮助我们还原和理解源码。我们来详细看一下示例代码的汇编,并尝试着进行高级代码的还原,过程直接通过注释解说了:
根据上面的逐句分析,然后优化整理:
可以看到和之前的代码基本一致。
第 3 小节中我们讲解了通过工具分析汇编,下面我们就直接用工具来进行汇编的讲解了。
62f8 cmp w0, w1 ;比较两个参数(cmp相当于做了一个减法 w0 - w1,结果不会影响 w0、w1,结果会影响 cpsr寄存器。cmp结果有三种:大于、等于、小于) ;得到全局变量的地址 并放入 x8 630c str w9, x8 ;w9寄存器中的值,放入 x8 所指向内存地址(也就是全局变量的地址) ;得到全局变量的地址 并放入 x8 str w9, x8 ;w9寄存器中的值,放入 x8 所指向内存地址(也就是全局变量的地址)
上一篇中,我们学习了 ,本篇我们继续看一下函数对应的汇编,从而了解函数的本质。
我们知道,调用函数的时候,汇编代码会首先开辟一段栈空间,用于存放参数、局部变量以及对寄存器进行保护,那么这些是怎么完成的呢?
先来看一段函数的代码:
运行工程,查看生成的汇编代码: 栈平衡(也就是回收函数所开辟的栈空间,这也就是我们在函数中声明的局部变量,出了这个函数就无法使用的原因)
上面的汇编代码,重要的都加了注释进行说明。从汇编代码可以清晰的看到,参数分别存储在 w0 和 w1 寄存器。
【函数 sum】的返回值存储在 w0 寄存器。
实际上,我们可以通过自己的代码,来验证一下:
叶子函数:函数中不再调用其他函数,就称为叶子函数,叶子函数不需要开辟栈空间。
经过上面的代码,我们总结一下:
- 函数的返回值,通常都放在 x0寄存器 中。
- 函数的参数,存放在 x0-x7 (w0-w7) 这 8 个寄存器里面。如果超过 8 个参数,则会入栈。
小示例:超过 8 个参数的函数
从汇编代码可以看到,【90】这个参数先放在了 w8 寄存器,然后入栈了:
在【函数 sumB】中求和的时候,是从栈中将参数【90】读取到 w1 寄存器,然后再相加的:
【思考】:在OC中,我们怎么知道调用的是哪个类的哪个方法?
在上面的代码演示过程中,我们可以看到,参数是保存在【x0】 -- 【x7】寄存器中的,OC 方法的调用,本质上是调用 objc_msgSend(id, SEL) 函数,第一个参数和第二个参数分别存放在 x0 和 x1 寄存器中,对应的就是具体的对象和具体的方法。因此我们查看 x0 和 x1 寄存器的值,就知道是哪个类的哪个方法了。
我们还是先上代码,从代码中来学习,比纯讲理论,要印象深刻:
运行工程,查看生成的汇编,下面的汇编代码,都添加了注释,方便大家理解:
从汇编代码可以看到,局部变量做了入栈操作,进行参数的保存。
上面的汇编代码,我们都是利用 Xcode 断点运行,开启【Debug】-【Debug Workflow】-【Always Show Disassembly】,通过 Xcode 调试中的信息查看到的。实际上,我们可以利用 IDA(神器,不解释)或者 Hopper,直接查看汇编代码。
打开 Xcode,新建一个示例工程,编写代码:
Xcode 直接编译工程,拷贝出生成的 .app 文件,显示包内容,拿到可执行文件,然后使用 IDA/Hopper 打开,如下图所示:
实际上,IDA/Hopper 会在汇编代码中,添加一些辅助的变量和其他内容,来更好的帮助我们还原和理解源码。我们来详细看一下示例代码的汇编,并尝试着进行高级代码的还原,过程直接通过注释解说了:
根据上面的逐句分析,然后优化整理:
可以看到和之前的代码基本一致。
第 3 小节中我们讲解了通过工具分析汇编,下面我们就直接用工具来进行汇编的讲解了。
62f8 cmp w0, w1 ;比较两个参数(cmp相当于做了一个减法 w0 - w1,结果不会影响 w0、w1,结果会影响 cpsr寄存器。cmp结果有三种:大于、等于、小于) ;得到全局变量的地址 并放入 x8 630c str w9, x8 ;w9寄存器中的值,放入 x8 所指向内存地址(也就是全局变量的地址) ;得到全局变量的地址 并放入 x8 str w9, x8 ;w9寄存器中的值,放入 x8 所指向内存地址(也就是全局变量的地址)
上一篇中,我们学习了 ,本篇我们继续看一下函数对应的汇编,从而了解函数的本质。
我们知道,调用函数的时候,汇编代码会首先开辟一段栈空间,用于存放参数、局部变量以及对寄存器进行保护,那么这些是怎么完成的呢?
先来看一段函数的代码:
运行工程,查看生成的汇编代码: 栈平衡(也就是回收函数所开辟的栈空间,这也就是我们在函数中声明的局部变量,出了这个函数就无法使用的原因)
上面的汇编代码,重要的都加了注释进行说明。从汇编代码可以清晰的看到,参数分别存储在 w0 和 w1 寄存器。
【函数 sum】的返回值存储在 w0 寄存器。
实际上,我们可以通过自己的代码,来验证一下:
叶子函数:函数中不再调用其他函数,就称为叶子函数,叶子函数不需要开辟栈空间。
经过上面的代码,我们总结一下:
- 函数的返回值,通常都放在 x0寄存器 中。
- 函数的参数,存放在 x0-x7 (w0-w7) 这 8 个寄存器里面。如果超过 8 个参数,则会入栈。
小示例:超过 8 个参数的函数
从汇编代码可以看到,【90】这个参数先放在了 w8 寄存器,然后入栈了:
在【函数 sumB】中求和的时候,是从栈中将参数【90】读取到 w1 寄存器,然后再相加的:
【思考】:在OC中,我们怎么知道调用的是哪个类的哪个方法?
在上面的代码演示过程中,我们可以看到,参数是保存在【x0】 -- 【x7】寄存器中的,OC 方法的调用,本质上是调用 objc_msgSend(id, SEL) 函数,第一个参数和第二个参数分别存放在 x0 和 x1 寄存器中,对应的就是具体的对象和具体的方法。因此我们查看 x0 和 x1 寄存器的值,就知道是哪个类的哪个方法了。
我们还是先上代码,从代码中来学习,比纯讲理论,要印象深刻:
运行工程,查看生成的汇编,下面的汇编代码,都添加了注释,方便大家理解:
从汇编代码可以看到,局部变量做了入栈操作,进行参数的保存。
上面的汇编代码,我们都是利用 Xcode 断点运行,开启【Debug】-【Debug Workflow】-【Always Show Disassembly】,通过 Xcode 调试中的信息查看到的。实际上,我们可以利用 IDA(神器,不解释)或者 Hopper,直接查看汇编代码。
打开 Xcode,新建一个示例工程,编写代码:
Xcode 直接编译工程,拷贝出生成的 .app 文件,显示包内容,拿到可执行文件,然后使用 IDA/Hopper 打开,如下图所示:
实际上,IDA/Hopper 会在汇编代码中,添加一些辅助的变量和其他内容,来更好的帮助我们还原和理解源码。我们来详细看一下示例代码的汇编,并尝试着进行高级代码的还原,过程直接通过注释解说了:
根据上面的逐句分析,然后优化整理:
可以看到和之前的代码基本一致。
第 3 小节中我们讲解了通过工具分析汇编,下面我们就直接用工具来进行汇编的讲解了。
62f8 cmp w0, w1 ;比较两个参数(cmp相当于做了一个减法 w0 - w1,结果不会影响 w0、w1,结果会影响 cpsr寄存器。cmp结果有三种:大于、等于、小于) ;得到全局变量的地址 并放入 x8 630c str w9, x8 ;w9寄存器中的值,放入 x8 所指向内存地址(也就是全局变量的地址) ;得到全局变量的地址 并放入 x8 str w9, x8 ;w9寄存器中的值,放入 x8 所指向内存地址(也就是全局变量的地址)剩余50%的内容订阅专栏后可查看
小专栏是一个专业人士的创作知识社区,在这里您可以看到各个领域最专业的专栏和观点。