最简函数与汇编

指令清单 C/C++ 代码


int f()
{
    return 123;
}
1. x86

在开启优化功能之后,GCC编译器产生的汇编指令,如下所示
Optimizing GCC/MSVC(汇编输出)

mov eax. 123
ret

MSVC编译的程序和上述指令完全一致
这个函数仅由两条指令构成:第一条指令把数值123存放在EAX寄存器里;根据函数调用约定,后面一条指令会把EAX的指当作返回值传递给调用者函数,而调用者函数(caller)会从EAX寄存器里取值,把它当作返回结果。

2. ARM

Optimizing Keil 6/2013(ARM模式)

PROC
    MOV  r0, #0x7b ;123
    BX     lr
    ENDP

ARM程序使用R0寄存器传递函数返回值,所以指令把数值123赋值给R0.
ARM程序使用LR寄存器(Link Register)存储函数结束之后的返回地址(RA/Return Address).x86程序使用“栈”结构存储上述返回地址。可见, BX lr指令作用是跳转到返回地址,即返回到调用者函数,然后继续执行调用体caller的后续指令。

x86和ARM指令集的MOV指令确实和对应单词“move”没有什么瓜葛。它的作用是复制copy,而非移动move。

3. MIPS

在MIPS指令集里,寄存器有两种命名方式。一种是以数字命名($0$31),另一种则是以伪名称(pseudoname)命名($V0VA0,依次类推)。在GCC编译器生成的汇编指令中,寄存器都采用数字方式命名。
Optimizing GCC 4.45(汇编输出)

j  $31
li $2, 123   #0x7b

然而IDA会显示寄存器的伪名称。

Optimizing GCC 4.45 (IDA)

jr  $ra
li $v0, 0x7B

根据伪名称和寄存器数字编号的关系可知,存储函数返回值的寄存器都是 2 即 ( 2即( 2(V0).此处LI指令是英文词组“Load Immediate(加载立即数)”的缩写。
其中,j和jr指令都属跳转指令,它们把执行流递交给调用者函数,跳转到 31 即 31即 31RA寄存器中的地址。这个寄存器相当于ARM平台的LR寄存器。
此外,为什么复制指令LI和转移指令J/JR的位置反过来了?这属于RISC精简指令集的特性之一 — 分支(转移)延迟槽(Branch delay slot)的现象。简单地说,不管分支(转移)发生与否,位于分支指令的一条指令(在延迟槽里的指令),总是被先于分支指令提交。这是RISC精简指令集的一种特例。我们不必在此处深究。总之,转移指令后面的这条复制指令。实际上是在转移指令之前运行的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值