伪指令,就是“伪”的指令,是针对“真”的指令而言的。 真的指令就是那些常见的指令,比如上面说的arm的ldr,bic,msr等等指令,是arm体系架构中真正存在的指令,你在arm汇编指令集中找得到对应的含义。 而伪指令是写出来给汇编程序看的,汇编程序能看的伪指令具体表示的是啥意思,然后将其翻译成真正的指令或者进行相应的处理。 伪指令ldr语法和含义: 只不过mov指令后面的立即数是有限制的,这个立即数,能够必须由一个8位的二进制数,即属于0x00-0xFF内的某个值,经过偶数次右移后得到,这样才是合法数据,而ldr伪指令没有这个限制。 那为何ldr伪指令的操作数没有限制呢,那是因为其是伪指令,写出来的伪指令,最终会被编译器解释成为真正的,合法的指令的,一般都是对应的mov指令。 这样的话,写汇编程序的时候,使用MOV指令是比较麻烦的,因为有些简单的数据比较容易看出来,有些数据即不容易看出来是否是合法数据。所以,对此,ldr伪指令的出现,就是为了解决这个问题的,你只管放心用ldr伪指令,不用关心操作数,而写出的ldr伪指令,编译器会帮你翻译成对应的真正的汇编指令的。 而关于编译器是如何将这些ldr伪指令翻译成为真正的汇编指令的,我的理解是,其自动会去算出来对应的操作数,是否是合法的mov 的操作数,如果是,就将该ldr伪指令翻译成mov指令,否则就用别的方式处理,我所观察到的,其中一种方式就是,单独申请一个4字节的空间用于存放操作数,然后用ldr指令实现。 在uboot中,最后make完毕之后,会生产u-boot, 通过: arm-linux-objdump –d u-boot > dump_u-boot.txt 就可以把对应的汇编代码输出到该txt文件了,其中就能找到伪指令: ldr r0, =0x53000000 所对应的,真正的汇编代码: 33d00068: e3a00453 mov r0, #1392508928 ; 0x53000000 所以被翻译成了mov指令。 而经过我的尝试,故意将0x53000000改为0x53000010,对应的生产的汇编代码为:
33d00068: e59f0408 ldr r0, [pc, #1032] ; 33d00478 <fiq+0x58>
......
33d00478: 53000010 .word 0x53000010
其中可以看到,由于0x53000010不是有效的mov的操作数,没法找到合适的0x00-0Xff去通过偶数次循环右移而得到,所以只能换成此处这种方式,即在另外申请一个word的空间用于存放这个值: 33d00478: 53000010 .word 0x53000010 然后通过计算出相对当前PC的偏移,得到的地址,用ldr指令去除该地址中的值,即0x53000010,送给r0,比起mov指令,要复杂的多,也多消耗了一个word的空间。 对应地,其他的方式,个人理解,好像也可以通过MVN指令来实现,具体细节,有待进一步探索。 |