对于Euroassembler,您可以将:后缀到名称上,以强制将其解释为符号,而不是寄存器,如call rdx:。(https://euroassembler.eu/eadoc/#SymbolName), 对于GAS .intel_syntax noprefix,您可以将符号名称放在引号中。这似乎很模糊;我不建议将GAS Intel语法用于生产环境。如果你更喜欢Intel而不是AT&T的语法,这对于阅读编译器输出是很好的,但是它有一些怪癖,包括这个和 * Distinguishing memory from constant in GNU as .intel_syntax *,这使得它比NASM更糟糕。
.intel_syntax noprefix
rdx:
call rdx # call reg
call "rdx" # call rel32
mov eax, [rip + "rdx"] # rip-relative load of that machine code
mov eax, ["rdx" + rdx] # use the register as an offset from the symbol
# mov eax, [rip + rdx] # error: RIP-relative doesn't work with other regs
由于符号是由同一文件中的标签定义的,因此RIP相关版本在组装时解析。disp32(%rdx)正在等待链接器填写绝对地址,即will only work in a non-PIE。 顺便说一句,重定位信息(由-r打印)只显示.text,而不是符号名称rdx,这与相对分支和RIP相对负载不同。相对寻址在汇编时完全解析,链接器没有实际的重定位来填充,所以打印<rdx>只是信息性的。但是[symbol + reg]的绝对地址有一个重定位条目,objdump可能正在打印它使用的符号名。如果我使用.globl rdx使该符号在符号表中完全可见,它将打印rdx-0x4而不是.text。 Intel语法是GNU工具链中AT&T语法背后的二等公民。GCC不使用引号,所以编译使用gcc -masm=intel全局变量的C将使它发出一个.s,GAS会阻塞它!(假设目标ABI(如i386或x86-64 System V)不使用前导下划线装饰C符号名称; _eax避免了问题,例如在macOS或32位Windows上。 理论上(也许只是几行)你可以使用.intel_syntax prefix,这样%rdx仍然需要在寄存器名称上,而裸rdx被解释为一个符号,但这是一个邪恶的突变混合体,当人们看到sub %ecx, %eax并假设它是AT&T语法时,会因为%装饰器而打破人们的大脑。而且,clang的汇编程序也不支持它:只有.att_syntax prefix和.intel_syntax noprefix。有很好的理由,因为没有人应该使用这种令人憎恶的语法。
2条答案
按热度按时间pbgvytdp1#
这取决于汇编程序。
我认为对于大多数情况,寄存器名称优先,所以
call rdx
将始终是RIP=RDX,而不检查是否存在同名的标签(或外部符号)。AT&T语法
call *%rdx
,而不是AT&Tcall rdx
。一些汇编器有语法来消除歧义,但是在不同的汇编器之间没有标准的语法。
例如对于NASM,这是Symbol name conflicts with new register names in new NASM versions?的副本,您可以使用
$eax
来引用名称为eax
的符号/标签,而不是寄存器。对于Euroassembler,您可以将
:
后缀到名称上,以强制将其解释为符号,而不是寄存器,如call rdx:
。(https://euroassembler.eu/eadoc/#SymbolName),对于GAS
.intel_syntax noprefix
,您可以将符号名称放在引号中。这似乎很模糊;我不建议将GAS Intel语法用于生产环境。如果你更喜欢Intel而不是AT&T的语法,这对于阅读编译器输出是很好的,但是它有一些怪癖,包括这个和 * Distinguishing memory from constant in GNU as .intel_syntax *,这使得它比NASM更糟糕。然后我们可以在AT&T语法中进行反汇编,以便对我们得到的内容更加清晰/明确。
由于符号是由同一文件中的标签定义的,因此RIP相关版本在组装时解析。
disp32(%rdx)
正在等待链接器填写绝对地址,即will only work in a non-PIE。顺便说一句,重定位信息(由
-r
打印)只显示.text
,而不是符号名称rdx
,这与相对分支和RIP相对负载不同。相对寻址在汇编时完全解析,链接器没有实际的重定位来填充,所以打印<rdx>
只是信息性的。但是[symbol + reg]
的绝对地址有一个重定位条目,objdump可能正在打印它使用的符号名。如果我使用.globl rdx
使该符号在符号表中完全可见,它将打印rdx-0x4
而不是.text
。Intel语法是GNU工具链中AT&T语法背后的二等公民。GCC不使用引号,所以编译使用
gcc -masm=intel
全局变量的C将使它发出一个.s
,GAS会阻塞它!(假设目标ABI(如i386或x86-64 System V)不使用前导下划线装饰C符号名称;_eax
避免了问题,例如在macOS或32位Windows上。理论上(也许只是几行)你可以使用
.intel_syntax prefix
,这样%rdx
仍然需要在寄存器名称上,而裸rdx
被解释为一个符号,但这是一个邪恶的突变混合体,当人们看到sub %ecx, %eax
并假设它是AT&T语法时,会因为%
装饰器而打破人们的大脑。而且,clang的汇编程序也不支持它:只有.att_syntax prefix
和.intel_syntax noprefix
。有很好的理由,因为没有人应该使用这种令人憎恶的语法。ajsxfq5m2#
有没有什么符号可以告诉汇编程序哪个是哪个?
这取决于你使用的汇编程序。没有通用的语法可以这样做。
然而,有些汇编器有区分标签和保留字的特性。例如,section "3.1 Layout of a NASM Source Line" in the nasm documentation声明,您可以将标签前缀为
$
,以将其与寄存器区分开来:一个标识符也可以前缀为
$
,以表明它是作为一个标识符而不是一个保留字来读的;因此,如果你链接的其他模块定义了一个名为eax的符号,你可以在NASM代码中引用$eax
来区分这个符号和寄存器