小明同学正在学习笨叔的《arm64体系结构与编程》,发现简单的mov指令还真不简单。下面两条mov指令,为啥一条可以,另外一条不行呢?
下面这条指令,可以编译通过。
mov x0, 0xffff0000ffff
而这条指令,只是前面少了一个f,为啥就编译不过呢?
mov x0, 0xfff0000ffff
编译出错:
aarch64-linux-gnu-gcc -g -Iinclude -MMD -c src/asm_test.S -o build/asm_test_s.o
src/asm_test.S: Assembler messages:
src/asm_test.S:326: Error: immediate cannot be moved by a single instruction
小明同学百思不骑姐?
其实mov指令是arm64指令集最简单也是不简单的指令,简单的原因是它可以用来搬移16位的立即数,这是它最原始的设计。但是呢,它也可以搬移超过16位的立即数,只不过,这个操作16位的立即数必须是16位立即数左移0,16,32,48位而成。例如,下面这条指令。
mov,x0, 0x12340000
这条指令是可以编译的,因为他是16位立即数0x1234,左移了16位。
我们可以通过aarch64-linux-gnu-objdump命令来反汇编来查看上面的mov指令究竟是做了那些事情?
aarch64-linux-gnu-objdump -s -d -M no-aliases build/asm_test_s.o
下面是反汇编的代码。
000000000000020c <my_test1>:
20c: d2a24680 movz x0, #0x1234, lsl #16
210: d65f03c0 ret
我们可以看到上面的mov指令等同于一条movz指令,而且是把0x1234这个立即数,左移了16位,得到了0x12340000.
如果我们把上面的mov指令,去掉一个0.
mov,x0, 0x1234000
你会发现编译不过了,编译器告诉你“immediate cannot be moved by a single instruction”。
我们可以看一下armv8.6手册的第C6.2.187章里描述了mov指令,它内部使用movz指令来实现的。
MOV <Xd>, #<imm>
等同于:
MOVZ <Xd>, #<imm16>, LSL #<shift>
好,我们来反汇编小明同学遇到的问题。下面是反汇编的结果。
000000000000020c <my_test1>:
20c: b2003fe0 orr x0, xzr, #0xffff0000ffff
210: d65f03c0 ret
从反汇编结果,我们可以知道上述的mov指令等同于一条orr指令。
我们再来看armv8.6手册的第C6.2.188章,讲了mov指令用于bitmask立即数的情况。
MOV <Wd|WSP>, #<imm>
等同于:
ORR <Wd|WSP>, WZR, #<imm>
所以,我们可以看到,arm64指令集里的最简单的mov指令,是不是不简单呢?您会用mov指令了吗?笨叔总结一下mov指令的几个使用场景。
-
搬移16位立即数。
-
搬移16位立即数左移16,32,48位后形成的立即数。
-
可以搬移bitmask的立即数到寄存器里。
可能你会问了,如果我的汇编代码里想搬移一个大于16位的立即数,咋办呢?
其实,我们可以使用ldr伪指令。
ldr x0,=0x123456789
大家对arm64刚兴趣,或者工作中用到arm64,都欢迎大家来订阅笨叔最新录制的ARM64体系结构与编程的视频课程。全球原创的arm64实验,全球首个手把手解读armv8手册,笨叔带你一起玩树莓派,一起做实验,等你哟!
双十一订阅视频课程,有活动哟,还要抽奖活动,赢取正版JLINK edu仿真器,树莓派4b等精美礼品。
视频订阅地址:
淘宝:
http://shop115683645.taobao.com/