36
len:  equ  2
len:  db   2

它们是否相同,产生一个可以用来代替的标签2?如果不是,那么每个申报表的优点或缺点是什么?它们可以互换使用吗?

4

3 回答 3

60

第一个是equate,类似于 C 的:

#define len 2

因为它实际上并没有在最终代码中分配任何空间,它只是将len符号设置为等于 2。然后,当您len稍后在源代码中使用时,它就像您使用常量一样2

第二个是define byte,类似于 C 的:

int len = 2;

确实分配了空间,一个字节在内存中,在2那里存储一个,并设置为该字节len地址

这是一些显示区别的伪汇编代码:

line   addr   code       label   instruction
----   ----   --------   -----   -----------
   1   0000                      org    1234h
   2   1234              elen    equ    2
   3   1234   02         dlen    db     2
   4   1235   44 02 00           mov    ax,     elen
   5   1238   44 34 12           mov    ax,     dlen

第 1 行简单地将程序集地址设置为1234h,以便更容易解释正在发生的事情。

在第 2 行中,没有生成任何代码,汇编器只是将elen值加载到符号表中2。由于没有生成代码,因此地址不会改变。

然后,当您在第 4 行使用它时,它会将该值加载到寄存器中。

第 3 行显示db不同,它实际上分配了一些空间(一个字节)并将值存储在该空间中。然后它加载dlen到符号表中,但给它该地址的值1234h而不是常量值2

当您稍后dlen在第 5 行使用时,您将获得地址,您必须取消引用才能获得实际值2

于 2011-11-04T08:44:25.717 回答
8

概括

NASM 2.10.09 ELF 输出:

  • db没有任何神奇的效果:它只是将字节直接输出到输出目标文件。

    如果这些字节恰好位于符号前面,则该符号将在程序启动时指向该值。

    如果您在文本部分,您的字节将被执行。

    您使用的天气dbdw等未指定符号大小的:st_size符号表条目的字段不受影响。

  • equ使当前行st_shndx == SHN_ABS中的符号在其符号表条目中具有魔法值。

    它不是将字节输出到当前目标文件位置,而是将其输出到st_value符号表条目的字段。

其他一切都由此而来。

要了解它的真正含义,您应该首先了解ELF 标准重定位的基础知识。

SHN_ABS理论

SHN_ABS告诉链接器:

  • 不得在此符号上进行搬迁
  • 符号条目的st_value字段将直接用作值

将此与“常规”符号进行对比,其中符号的值是内存地址,因此必须经过重定位。

由于它不指向内存,SHN_ABS因此链接器可以通过内联符号从可执行文件中有效地删除它们。

但是它们仍然是目标文件上的常规符号,并且确实占用了那里的内存,并且如果是全局的,则可以在多个文件之间共享。

示例使用

section .data
    x: equ 1
    y: db 2
section .text
global _start
_start:
    mov al, x
    ; al == 1
    mov al, [y]
    ; al == 2

请注意,由于符号x包含文字值,因此不必[]像 for 那样对它进行取消引用y

如果我们想x从 C 程序中使用,我们需要类似的东西:

extern char x;
printf("%d", &x);

并在 asm 上设置:

global x

生成输出的经验观察

我们可以观察我们之前所说的:

nasm -felf32 -o equ.o equ.asm
ld -melf_i386 -o equ equ.o

现在:

readelf -s equ.o

包含:

Num:    Value  Size Type    Bind   Vis      Ndx Name
  4: 00000001     0 NOTYPE  LOCAL  DEFAULT  ABS x
  5: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 y

Ndxst_shndx,所以我们看到xSHN_ABSy不是。

另请参阅这Size0for y:db绝不会告诉y它是单字节宽。我们可以简单地添加两个db指令来在那里分配 2 个字节。

进而:

objdump -dr equ

给出:

08048080 <_start>:
 8048080:       b0 01                   mov    $0x1,%al
 8048082:       a0 88 90 04 08          mov    0x8049088,%al

所以我们看到它0x1被内联到指令中,同时y获得了重定位地址的值0x8049088

在 Ubuntu 14.04 AMD64 上测试。

文档

http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4

EQU 为给定的常量值定义了一个符号:当使用 EQU 时,源代码行必须包含一个标签。EQU 的作用是将给定的标签名称定义为其(唯一)操作数的值。这个定义是绝对的,以后不能改变。所以,例如,

message         db      'hello, world' 
msglen          equ     $-message

将 msglen 定义为常量 12。msglen 以后可能不会重新定义。这也不是预处理器定义:msglen 的值被评估一次,在定义点使用 $ 的值(参见第 3.5 节对 $ 的解释),而不是在任何引用它的地方进行评估并使用$ 在参考点。

也可以看看

GAS 的类似问题:ARM 汇编中 .equ 和 .word 之间的区别? .equiv似乎是关闭的 GAS 等价物。

于 2015-10-15T12:12:26.163 回答
7

equ:预处理器时间。类似于#define,但大多数汇编程序都缺少#undef,并且除了右侧的固定字节数的原子常数之外什么都没有,因此大多数汇编程序的 equ 指令不支持浮点数、双精度数、列表。

db:编译时间。存储在 db 中的值由汇编器以特定偏移量存储在二进制输出中。equ 允许您定义通常需要硬编码或需要 mov 操作才能获取的常量。db 允许您在程序启动之前就在内存中拥有可用的数据。

这是一个演示 db 的 nasm:

; I am a 16 byte object at offset 0.
    db '----------------'

; I am a 14 byte object at offset 16
; the label foo makes the assembler remember the current 'tell' of the 
; binary being written.
foo:
    db 'Hello, World!', 0

; I am a 2 byte filler at offset 30 to help readability in hex editor.
    db ' .'

; I am a 4 byte object at offset 16 that the offset of foo, which is 16(0x10).
    dd foo

在此处输入图像描述

equ 只能定义一个常量,直到汇编器支持的最大值

equ 的示例,以及它的一些常见限制。

; OK
ZERO equ 0

; OK(some assemblers won't recognize \r and will need to look up the ascii table to get the value of it).
CR equ 0xD
; OK(some assemblers won't recognize \n and will need to look up the ascii table to get the value of it).
LF equ 0xA

; error: bar.asm:2: warning: numeric constant 102919291299129192919293122 -
; does not fit in 64 bits
; LARGE_INTEGER equ 102919291299129192919293122

; bar.asm:5: error: expression syntax error
; assemblers often don't support float constants, despite fitting in
; reasonable number of bytes. This is one of the many things
; we take for granted in C, ability to precompile floats at compile time
; without the need to create your own assembly preprocessor/assembler.
; PI equ 3.1415926 

; bar.asm:14: error: bad syntax for EQU
; assemblers often don't support list constants, this is something C
; does support using define, allowing you to define a macro that
; can be passed as a single argument to a function that takes multiple.
; eg
; #define RED 0xff, 0x00, 0x00, 0x00
; glVertex4f(RED);
; #undef RED
;RED equ 0xff, 0x00, 0x00, 0x00

生成的二进制文件根本没有字节,因为 equ 不会污染图像;所有对 equ 的引用都被该 equ 的右侧替换。

于 2018-01-26T21:19:15.773 回答