指令清单 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)命名($V0~VA0,依次类推)。在GCC编译器生成的汇编指令中,寄存器都采用数字方式命名。
Optimizing GCC 4.45(汇编输出)
j $31
li $2, 123 #0x7b
然而IDA会显示寄存器的伪名称。
Optimizing GCC 4.45 (IDA)
jr $ra
li $v0, 0x7B
根据伪名称和寄存器数字编号的关系可知,存储函数返回值的寄存器都是$2即($V0).此处LI指令是英文词组“Load Immediate(加载立即数)”的缩写。
其中,j和jr指令都属跳转指令,它们把执行流递交给调用者函数,跳转到$31即$RA寄存器中的地址。这个寄存器相当于ARM平台的LR寄存器。
此外,为什么复制指令LI和转移指令J/JR的位置反过来了?这属于RISC精简指令集的特性之一 --- 分支(转移)延迟槽(Branch delay slot)的现象。简单地说,不管分支(转移)发生与否,位于分支指令的一条指令(在延迟槽里的指令),总是被先于分支指令提交。这是RISC精简指令集的一种特例。我们不必在此处深究。总之,转移指令后面的这条复制指令。实际上是在转移指令之前运行的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。