在GNU中以.intel_syntax区分内存与常量

Ale*_*ing 2 assembly gnu-assembler intel-syntax

我有一条用Intel语法编写的指令(使用gas作为汇编程序),看起来像这样:

mov rdx, msg_size
...
msg: .ascii "Hello, world!\n"
     .set msg_size, . - msg
Run Code Online (Sandbox Code Playgroud)

但是该mov指令正在汇编到mov 0xe,%rdx,而不是mov $0xe,%rdx我期望的那样。我应该如何编写第一条指令(或的定义msg_size)以获得预期的行为?

Pet*_*des 5

在GAS .intel_syntax noprefix模式下:

  • OFFSET symbol像AT&T一样工作$symbol。这有点像MASM。
  • symbol类似于AT&T symbol(即取消引用)。
  • [symbol]在GAS和NASM / YASM中始终是有效的地址,而不是立即的地址。 LEA不会从地址加载,但仍使用内存操作数机器编码。(这就是为什么它使用相同的语法)。

提示:如果您了解AT&T语法或NASM语法,请使用该语法生成​​所需的编码,然后反汇编objdump -Mintel以找到适用于的正确语法.intel_syntax noprefx

顺便说一句,据我了解,没有开源项目包含GAS intel_syntax源代码。如果使用天然气,则使用AT&T语法。否则,他们使用NASM / YASM。(有时您还会在开放源代码项目中看到MSVC内联汇编)。


GNU as .intel_syntax noprefixmode有点像MASM,除了没有魔术取决于符号的定义方式。

mov rdx, symbol永远是负担。符号的值是其地址。也就是说,使用.set创建(或修改)符号的行为与将标签贴在某物上的行为完全相同。

(除非symbol使用symbol=123或定义为汇编时间常数,否则.equ symbol, 123它是立即移动的。)


mov rdx, OFFSET symbol将组装到mov r/m64, imm32。我忘记了intel-syntax模式是否可以使用大操作数进行mov组装movabs r64, imm64,但这无关紧要,因为静态数据/代码地址始终位于虚拟地址空间的低2GiB中,因此它们适合32位符号扩展的立即数。

(这样可以安全地编写代码mov edx, OFFSET symbol,实际上,您应该始终这样做或使用lea rdx, [rip + symbol],切勿对符号进行32位立即数扩展,除非要编写的代码将加载到2GB的虚拟地址空间中。)

  • @CodyGray:当我第一次自学x86 asm时,我习惯于AT&T语法,因为那是gcc / objdump所使用的。直接操作数上显式的`$`是一个很大的优点。但是一旦我意识到唯一真正的insn set引用是使用Intel语法,并且对此有所适应之后,我就开始意识到它似乎更容易阅读。目标位于左侧,并且内存操作数语法更好。我总是在Godbolt和类似的东西上使用Intel语法模式。在编写gcc错过优化错误报告时,我仅使用AT&T语法,因为这似乎是编译器开发人员选择的。 (3认同)
  • *“据我所知,没有任何开源项目包含 GAS intel_syntax 源代码。”* 哇,真的吗?也许这就是你所习惯的,但我讨厌 AT&T 语法。如果我要花费大量精力编写/维护 GAS 内联汇编,我*肯定*更喜欢使用英特尔语法。人们不这样做有什么技术原因吗?比如,在英特尔语法方面,GAS 是否存在重大限制?(我主要是一个 MSVC 人。MASM 语法很棒,但是无法为内联汇编指定输入参数使得它很难用于*优化*。) (2认同)
  • @CodyGray:您根本不能使用 YASM/NASM 进行内联汇编。像 x264 和 x265 这样使用 NASM/YASM 的项目将 asm 放在单独的文件中(并广泛使用汇编器宏)。 (2认同)