问题描述
通常会找到以下形式的汇编代码行
xorq,%rdx,%rdx
此操作的一种用途是利用x ^ x = 0的事实将寄存器%rd设置为零。在C语言中,它与设置x = 0相同。
表达此操作的另一种更直接的方法是
movq $0,%rdx
我的问题是,我们如何计算对这两种不同实现进行编码所需的字节数?我相信第一个答案是3个字节,而第二个答案是7个字节。
解决方法
在过去,汇编程序会生成列出编码指令的清单文件,您可以看到每个指令占用了多少字节。失败的话,您可以将这段代码放在一些file.s
中:
a: xorq %rdx,%rdx
b: movq $0,%rdx
c:
然后用as -o file.o file.s
进行组装,并用nm file.o
查看符号,该符号显示为:
0000000000000000 t a 0000000000000003 t b 000000000000000a t c
其中您可以看到xorq %rdx,%rdx
要求3 16 −0 16 = 3个字节,而movq $0,%rdx
需要一个 16 -3 16 = 7个字节。
您还可以使用objdump -disassemble file.o
或otool -tv file.o
来反汇编目标文件。 (命令及其开关可能有所不同;这些是当前的Apple工具。)
您可以从x86参考手册中找到此类问题的答案,但是编写一个小型测试组装程序,组装然后反汇编它通常会更快,更容易。
$ cat > test.s <<EOF
.text
.globl x
x:
xorl %edx,%edx
xorq %rdx,%rdx
movl $0,%edx
movq $0,%rdx
EOF
$ as test.s -o test.o
$ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <x>:
0: 31 d2 xor %edx,%edx
2: 48 31 d2 xor %rdx,%rdx
5: ba 00 00 00 00 mov $0x0,%edx
a: 48 c7 c2 00 00 00 00 mov $0x0,%rdx
所有这四个指令清除RDX,因为x86-64自动将任何32位运算的结果零扩展到寄存器的全宽度。您可以从反汇编转储中看到,它们分别由两个,三个,五个和七个字节编码,因此您的原始推测是正确的。
使用更长指令的原因是XOR设置了条件代码(因此在xor %edx,%edx
之后,您将拥有ZF = 1,OF = SF = PF = CF = 0和AF未定义),但是MOV没有。如果您要微调某些手写程序集的计划,这可能很重要。