len: equ 2
len: db 2
它们是否相同,产生一个可以用来代替的标签2
?如果不是,那么每个申报表的优点或缺点是什么?它们可以互换使用吗?
len: equ 2
len: db 2
它们是否相同,产生一个可以用来代替的标签2
?如果不是,那么每个申报表的优点或缺点是什么?它们可以互换使用吗?
第一个是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
。
概括
NASM 2.10.09 ELF 输出:
db
没有任何神奇的效果:它只是将字节直接输出到输出目标文件。
如果这些字节恰好位于符号前面,则该符号将在程序启动时指向该值。
如果您在文本部分,您的字节将被执行。
您使用的天气db
或dw
等未指定符号大小的: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
Ndx
是st_shndx
,所以我们看到x
是SHN_ABS
而y
不是。
另请参阅这Size
是0
for 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 等价物。
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 的右侧替换。