【问题标题】:Memory addressing with GNU Assember Intel Syntax使用 GNU Assembler Intel 语法进行内存寻址
【发布时间】:2012-04-30 04:42:18
【问题描述】:

我阅读了this page,其中包含一个很好的列表,其中列出了英特尔和 AT&T 的 GAS 语法之间的差异,但它没有涵盖仅指定具有位移的地址的情况。

这里我用 AT&T 语法组装了四行代码:

                         .text
0000 48C7C008000000      mov    $8, %rax
0007 488B042508000000    mov    (8), %rax
000f 4889F0              mov    %rsi, %rax
0012 488B06              mov    (%rsi), %rax

正如预期的那样,前两行是不同的。第一个将立即值 8 移动到 rax 中,第二个将地址 8 的内容移动到 rax 中。但使用英特尔语法,我得到以下奇怪的行为:

                         .text
                         .intel_syntax
0000 48C7C008000000      mov    %rax, 8
0007 48C7C008000000      mov    %rax, [8]
000e 4889F0              mov    %rax, %rsi
0011 488B06              mov    %rax, [%rsi]

这里第一行和第二行汇编成相同的机器码!首先我认为方括号是错误的,所以我在测试中添加了第三和第四行,至少在涉及寄存器时方括号确实可以用于内存寻址。

我读过的所有文档都显示了内存寻址示例,其中至少有一个基址或索引寄存器,有时还有比例和位移,但绝不是只有位移。

我确实有使用 NASM 汇编器的英特尔语法的经验,它确实区分mov rax, 8mov rax, [8]

这是 GAS 中的错误吗?或者如果不是,我如何指定 NASM 的 mov rax, [8] 的等价物?

我意识到指定仅位移地址可能并不常见,但我想全面了解使用此语法的所有内存寻址形式。

【问题讨论】:

  • 当我使用 Intel 语法组装您的示例时,我 确实 得到了预期的行为。对我来说,生成的机器代码与您显示的完全相同,除了第二行,对我来说是48 8b 04 25 08 00 00
  • 如果在上面的 GAS Intel Syntax 示例中,您得到了显示的输出,那么是的,您的版本 GAS 为 mov %rax, 8 创建了不正确的代码(初始化 rax 常数 8,与 AT&T mov $8, %rax 相同)。目前的所有寻址操作都使用正确的操作码。

标签: assembly gnu-assembler intel-syntax


【解决方案1】:

您在这里看到了 AT&T 语法的一个非常特殊的极端情况。通常,对于地址操作数,您有:

<op> [ src, ] displacement(base,index,scale) [, tgt ]

AT&T 语法中地址操作数的任何组成部分都是可选的,因此您可以编写 mov (%rax, %rbx), ...mov 0(%rax, %rbx, 1), ... 或任何其他此类组合。

() 括号内,您通常可以拥有的唯一数字是比例因子(如果存在)。

但汇编器也接受(并为其创建相同的代码):

mov <absolute>, ...
mov (<absolute>), ...

这仅在() 中的操作数是简单数字/绝对地址时才有效,否则汇编程序会抱怨您提供的不是有效的比例因子。这种等价是 AT&T 语法中的一个特殊情况 - 我不知道为什么允许/被允许。

尽管在 AT&T 语法中使用$,但始终指定一个常量,而不是地址操作数,这与英特尔语法中的裸数相同.

以下说明了等价关系:

$ cat t.s
        mov     (8), %rax
        mov     $8, %rax
        mov     8, %rax
.intel_syntax
        mov %rax, [ 8 ]
        mov %rax, 8
        mov %rax, %ds:8

$ objdump -w -d t.o

t.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
   8:   48 c7 c0 08 00 00 00            mov    $0x8,%rax
   f:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
  17:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
  1f:   48 c7 c0 08 00 00 00            mov    $0x8,%rax
  26:   48 8b 04 25 08 00 00 00         mov    0x8,%rax

$ objdump -w -M intel -d t.o

t.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 :
   0:   48 8b 04 25 08 00 00 00         mov    rax,ds:0x8
   8:   48 c7 c0 08 00 00 00            mov    rax,0x8
   f:   48 8b 04 25 08 00 00 00         mov    rax,ds:0x8
  17:   48 8b 04 25 08 00 00 00         mov    0x8,%rax
  1f:   48 c7 c0 08 00 00 00            mov    rax,0x8
  26:   48 8b 04 25 08 00 00 00         mov    rax,ds:0x8

【讨论】:

  • 问题是关于英特尔语法的奇怪行为;但是......我不认为这里的 AT&T 语法是一个特例——我怀疑它只是将 (8) 评估为一个表达式,因为它不匹配任何 is 特殊语法.例如mov 8, %raxmov (8), %raxmov 4+4, %raxmov (4+4), %rax 都做同样的事情。
【解决方案2】:

gas 中确实存在这样的错误——参见http://sourceware.org/bugzilla/show_bug.cgi?id=10637

它似乎已在(或之前)binutils 2.21.51 中修复。

【讨论】:

  • 哇,我在搜索中没有找到。事实上gcc -v 给出了“GNU assembler version 2.20.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.20.1-system.20100303”所以我将更新到 2.21.x 并试一试。
  • 在新的 binutils 上验证。谢谢@Matthew。
猜你喜欢
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 2011-03-12
  • 2017-06-26
  • 1970-01-01
相关资源
最近更新 更多