【问题标题】:NASM assembler : How to align values using EQU, to get the next alignment boundary after a label without actually paddingNASM 汇编器:如何使用 EQU 对齐值,以获得标签后的下一个对齐边界而无需实际填充
【发布时间】:2021-12-30 16:47:21
【问题描述】:

我想计算对齐的地址。 'label' 应该对齐 4 字节边界。

        bits 32
        mov eax, label
end:    ; here is the end of program
        align 4
label:

这个 nasm 代码输出 8 个字节。

$ nasm -f bin test.nasm -o test.o
$ ndisasm -o 0x0 -b 32 test.o
00000000  B808000000        mov eax,0x8
00000005  90                nop
00000006  90                nop
00000007  90                nop

但实际上程序大小是 5 个字节。 是否可以在不扩展程序大小的情况下定义标签? 我希望将“标签”定义为值 8,并且 test.o 的文件大小将为 5。

我也尝试使用 '$' 变量来计算地址,如下所示。

        bits 32
        mov eax, label
end:    ; here is the end of program
label   equ ( ($+3) & ~3 )

但是 nasm 不接受这种表达方式。

$ nasm -f bin test.nasm -o test.o
test.nasm:4: error: `&' operator may only be applied to scalar values

【问题讨论】:

    标签: assembly x86 nasm memory-alignment


    【解决方案1】:

    这是意料之中的。 end 的绝对地址通常在链接之后才知道,因此地址的任何转换都必须由链接器计算。大多数系统上的链接器可以执行一些有限的算术运算(主要是加法和减法),汇编器通过在重定位表中插入适当的条目来请求这些算术。这就是为什么您可以执行mov eax, label+17mov eax, label2-label1 之类的操作。但它不像&那样做完全任意的算术,也没有重定位来编码这样的表达式。

    (我猜因为我们在这里输出二进制,所以汇编器对绝对地址有更多的了解;但它可能不是为了利用这种特殊情况而设计的。)

    所以我认为你在这里不走运。您可以在label 之前忍受额外的填充字节,也可以在运行时进行对齐,例如

    mov eax, label+3
    and eax, ~3
    

    【讨论】:

    • 请注意,and eax, ~3 是一个 3 字节的指令,因此在这种情况下,即使是最坏的对齐填充情况也等于机器码字节的额外成本。除非额外的 3 个字节只是缩小一些 other 填充,如果这实际上是更大程序的一部分。但是and al, ~3仍然只是清除了E/RAX的低2位,而且只是一个2字节的指令,可以节省一些。
    【解决方案2】:

    你应该只使用 align 4

    equ 在组装时进行评估。所以它在链接后无法知道 $ 在运行时的对齐方式。此外,它给你的错误,

    error: `&' operator may only be applied to scalar values
    

    那是因为 ($+3) 不是标量值。它甚至无法在装配时进行评估。

    另一方面,align 4 会将对齐要求传递到目标文件中,链接器将正确对齐 label。如果您想验证这是否正确,您可以检查最终可执行文件上的名称列表(符号表)。

    【讨论】:

      【解决方案3】:

      正如 Nate 所解释的,NASM 不会对地址进行任意数学运算,即使是在制作平面二进制而不是仅仅将重定位写入 ELF 或 COFF .o / .obj 时也是如此。

      NASM 在制作平面二进制文件时连接部分,但不会为.bss 发出任何字节
      这个程序汇编成你想要的 5 个字节的机器码:

              bits 32
              mov eax, label
      end:    ; here is the end of program
      
      section .bss
              align 4       ; in the BSS where they don't end up in the file
      label:
      
      $ nasm -fbin foo.asm
      $ ll foo
      -rwxr-xr-x 1 peter peter 5 Dec 30 15:16 foo
      $ ndisasm -b32 foo
      00000000  B808000000        mov eax,0x8
      

      我对它的工作感到有些惊讶; IDK 如果它得到官方支持或者我很幸运。
      它也适用于 YASM。

      在 FASM 中,即使没有 section .bss 指令,它似乎也只是跳过了在文件末尾写入对齐填充。 (所以我得到了一个 6 字节的文件,因为我没有为 32 位平面二进制输出查找正确的 FASM 指令,因此它使用 66 操作数大小前缀来编码 mov eax, 8 用于 16 位模式.)

      【讨论】:

      • 这对我来说似乎是完美的解决方案。感谢您的回答。
      • @AkihiroYoshikawa:干杯。您可以使用投票箭头下方的复选标记“接受”您认为最好的任何答案。
      • 啊!我推了它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-29
      • 1970-01-01
      • 1970-01-01
      • 2018-04-13
      • 1970-01-01
      • 2022-10-15
      相关资源
      最近更新 更多