我有以下代码,正在macOS上与clang一起使用:
.intel_syntax noprefix
.data
hello: .ascii "Hello world\n"
hello_len = . - hello
.text
.globl _main
_main:
mov rax, 0x2000004
mov rdi, 1
lea rsi, [rip + hello]
mov rdx, hello_len # <-------
syscall
mov rax, 0x2000001
syscall
虽然看起来它应该打印“ Hello World”并退出,但实际上是段错误。原来是因为mov rdx, hello_len
实际上试图移动地址hello_len
上的值,而不是hello_len
本身的值。
如果我使用AT&T语法,则该行将为movq $hello_len, %rdx
,可以正常工作。 clang的GAS intel语法版本等效于什么?
使用真实的GAS(在Linux上,您的代码可以随意组合为mov rdx, sign_extended_imm32
。
但是,很遗憾,c将其组装为mov rdx, [0xc]
。那可能是bug,也可能不是bug,但这绝对是不兼容的。 (MacOS的gcc
命令根本不是GNU编译器集合,它是Apple Clang(LLVM后端,clang前端。))
OFFSET hello_len
似乎不起作用。 (我错误地认为它会在最初的猜测中出现,但是只是尝试了一下。)
尽管clang -S
会打印mov edi, offset hello
,但不会使用clang的内置汇编器进行汇编! https://godbolt.org/z/x7vmm4。我不确定如何获取clang intel语法以使用符号的值(地址)作为立即数。
// hello.c
char hello[] = "abcdef";
char *foo() { return hello; }
$ clang -fno-pie -O1 -S -masm=intel hello.c
$ clang -c hello.s
hello.s:10:18: error: cannot use more than one symbol in memory operand
mov eax, offset hello
^
$ clang --version
clang version 8.0.1 (tags/RELEASE_801/final)
Target: x86_64-pc-linux-gnu
...
Clang甚至无法组装自己的.intel_syntax noprefix
输出。可能没有解决方案:(
IMO这是一个错误,您应该在铛的https://bugs.llvm.org]中报告它mov r32, imm32而不是相对于RIP的LEA来利用静态地址位于虚拟地址空间的低32位中。当然不是mov r64, imm64
。]