指令和伪指令的区别:
伪指令不是指令,伪指令和指令的根本区别是伪指令经过编译后不会生成机器码。伪指令的意义在于指导编译过程。伪指令是和具体的编译器相关的,下面介绍的是gnu环境下的汇编伪指令。
gnu汇编中的一些符号:
@: 用***做注释。可以在行首也可以在代码后面同一行直接跟,和C语言中//类似
#:做注释,一般放在行首,表示这一行都是注释而不是代码。
:以冒号结尾的是标号
. 点号在gnu汇编中表示当前指令的地址
#和$ :立即数前面要加#或$,表示这是个立即数
常用gnu伪指令:
.global _start @ 给_start外部链接属性
.sec
tion .text @ 指定当前段为代码段
.ascii .byte .short .long .word .quad .float .string @ 定义数据
.align 4 @ 以16字节对齐
.balignl 16 0xabcdefgh @ 16字节对齐填充
.equ @ 类似于C中宏定义
重要的几个伪指令:
ldr 大范围的地址加载指令
adr 小范围的地址加载指令
adrl 中等范围的地址加载指令
nop 空操作
ARM中有一个ldr指令,还有一个ldr伪指令
一般都使用ldr伪指令而不用ldr指令
ldr指令和ldr伪指令:
1.ARM中有一条ldr指令和ldr伪指令,一般都使用ldr伪指令而不用ldr指令,主要是因为ldr指令要受到合法立即数和非法立即数的限制。具体区别的方法如下:
ldr r0, =0xFFF0 @伪指令
ldr r0, 0xFFFF @指令
有等号的是伪指令,上面的ldr编译时会报错,因为0xFFFF是非法立即数(一条32位指令由指令码+数据组成,所以用***表示数据的位是有限的(8位),超过8位的数据就不能直接表示)。ldr伪指令不会出错,是因为编译器会替我们进行处理非法立即数的问题。ldr伪指令会用文字池的方式***解决非法立即数的问题,详解解释请看我的另一篇博客《ldr指令和ldr伪指令详解》。
ldr和adr的区别:
adr总是以PC为基准***表示地址,因此指令本身和运行地址有关,可以用***检测程序当前的运行地址在哪里。ldr加载的地址和链接时给定的地址有关,由链接脚本决定。
例如:在代码重定位中,就会运行到adr和ldr的特性。_start是标号,相当于C语言的函数名。假设程序被下载到0x0地址,而链接脚本里指令链接地址为0x200000400
adr r0, ***载的是运行时地址,r0=0x0
ldr r1, =***载的是链接时地址,r0=0x20000400
cmp r0, r1 @比较两个地址是否相等
解析:通过上面三条语句,可以判断运行地址和链接地址是否相当,如果相等则不需要代码重定位,不相等就需要代码重定位。***有关码运行前,将代码从运行地址复制一份到链接地址,然后长跳转到链接地址处的那份代码进行执行。
原作者:正在起飞的蜗牛