具有此:
.text
.globl main
str:
.string "hello world"
len = .-str #a strange assignment
main:
mov $1, %eax
mov $1, %edi
movabs $str, %rsi
mov $len, %rdx
syscall
call exit
1]这里是带有冒号的str
(正如我通常看到的),但是len
由=
分配。我不认为这是因为str
是地址,而len
是数字(因此是不同的类型),但是为什么可以分配不同的方式呢?还是两个标签?
2)当我可以使用mov str(%rip), %rsi
时为何使用movabs $str, %rsi
?
标签后跟:
=
不是标签,它以.set
或.equ
的方式将符号定义为汇编时间常数。这使汇编程序可以在汇编时为您计算字符串的长度。
.
是当前位置。将.
视为此行开头的隐式标签。您可以等效地在字符串后放置str_end:
标签并完成len = str_end - str
。
为什么可以使用
mov str(%rip), %rsi
,何时可以使用movabs $str, %rsi
?
这些不相等! mov str(%rip), %rsi
将从该地址加载8个字节,并将字符串数据保存到寄存器中。但是您需要对寄存器中的字符串使用pointer作为write(int fd, void *buf, size_t len)
系统调用的arg。在调试器和/或strace
中进行尝试,然后观察失败。
这就是为什么此代码中的movabs
使用$str
将地址作为64位立即数获取的原因。
但是,这是the worst way to put a label/symbol address into a register。 movabs
的立即数为8个字节,总共等于10个字节的指令,并且绝对是当加载程序选择可执行文件的实际基址时,它需要在PIE可执行文件或库(ELF共享对象)中进行运行时修复。
您实际上想要LEA str(%rip), %rsi
(7个字节),或在non-PIE Linux executable where static addresses fit in the low 31 bits of address space, mov $str, %esi
中。