两条mov指令,为啥一条可以,另外一条不行呢?
奔跑吧Linux社区 2023-06-07

小明同学正在学习笨叔的《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:326Error: 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指令的几个使用场景。

  1. 搬移16位立即数。

  2. 搬移16位立即数左移16,32,48位后形成的立即数。

  3. 可以搬移bitmask的立即数到寄存器里。

可能你会问了,如果我的汇编代码里想搬移一个大于16位的立即数,咋办呢?
其实,我们可以使用ldr伪指令。

ldr x0,=0x123456789 



声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 相关技术文库
  • 硬件
  • 原理图
  • 信号完整性
  • EMI
下载排行榜
更多
评测报告
更多
广告