len: equ 2
len: db 2
它们是否相同,产生的标签可以代替2
使用?如果没有,那么每份申报表的优缺点是什么?它们可以互换使用吗?
答案 0 :(得分:32)
第一个是equate
,类似于C:
#define len 2
因为它实际上并没有在最终代码中分配任何空格,它只是将len
符号设置为等于2.然后,当您在源代码中使用len
时,就像你使用常量2
一样。
第二个是define byte
,类似于C:
int len = 2;
它 实际分配空间,内存中的一个字节,在那里存储2
,并将len
设置为地址字节。
这里有一些psuedo-assembler代码显示了区别:
line addr code label instruction
---- ---- -------- ----- -----------
1 0000 org 1234
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行只是将汇编地址设置为1234
,以便更容易解释发生了什么。
在第2行中,没有生成代码,汇编器只需将elen
加载到符号表中,其值为2
。由于没有生成代码,因此地址不会改变。
然后,当您在第4行使用它时,它会将该值加载到寄存器中。
第3行显示db
不同,它实际上分配了一些空间(一个字节)并将值存储在该空间中。然后,它会将dlen
加载到符号表中,但会为其提供该地址1234
的值,而不是常量值2
。
如果您稍后在第5行使用dlen
,则会获得地址,您必须取消引用该地址才能获得实际值2
。
答案 1 :(得分:1)
<强>摘要强>
NASM 2.10.09 ELF输出:
db
没有任何魔法效果:它只是将字节直接输出到输出目标文件。
如果这些字节恰好位于符号前面,则符号将在程序启动时指向该值。
如果您在文本部分,您的字节将被执行。
您使用db
或dw
等未指定符号大小的天气:符号表条目的st_size
字段不受影响。
equ
使当前行中的符号在其符号表条目中具有st_shndx == SHN_ABS
魔术值。
不是将字节输出到当前对象文件位置,而是将其输出到符号表条目的st_value
字段。
其他所有内容都来自此。
要了解其真正含义,首先应了解the basics of the ELF standard和relocation。
SHN_ABS理论
SHN_ABS
告诉链接器:
st_value
字段将直接用作值将此与#34;常规&#34;进行对比。符号,其中符号的值是内存地址,因此必须通过重定位。
由于它没有指向内存,因此链接器可以通过内联来有效地从可执行文件中删除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
包含文字值,因此不必像[]
那样对其进行解除引用y
。
如果我们想要使用C程序中的x
,我们需要以下内容:
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
则不是。{/ p>
另请注意Size
0
y
db
:y
绝不告诉db
它是单字节宽。我们可以简单地添加两个objdump -dr equ
指令来在那里分配2个字节。
然后:
08048080 <_start>:
8048080: b0 01 mov $0x1,%al
8048082: a0 88 90 04 08 mov 0x8049088,%al
给出:
0x1
因此,我们看到y
被内联到指令中,而0x8049088
获得了重定位地址message db 'hello, world'
msglen equ $-message
的值。
在Ubuntu 14.04 AMD64上测试。
<强>文档强>
http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4:
EQU定义给定常数值的符号:当使用EQU时,源代码行必须包含标签。 EQU的作用是将给定的标签名称定义为其(仅)操作数的值。这个定义是绝对的,以后不能改变。所以,例如,
.equiv
将msglen定义为常量12.稍后可能不会重新定义msglen。这也不是预处理器定义:msglen的值被评估一次,在定义点使用$的值(参见第3.5节有关$的解释),而不是在被引用的任何地方进行求值并使用值$在参考点。
另见
GAS的类似问题:Difference between .equ and .word in ARM Assembly? {{1}}似乎是关闭GAS的等价物。
答案 2 :(得分:1)
equ :预处理器时间。类似于#define,但是大多数汇编程序缺少#undef,并且除了右侧的固定字节数的原子常量之外不能有任何东西,所以大多数汇编程序的equ指令都不支持浮点数,双精度数,列表。
db :编译时间。存储在db中的值由汇编程序在特定偏移量处存储在二进制输出中。 equ允许您定义通常需要硬编码或需要mov操作才能获得的常量。 db允许您在程序启动之前在内存中提供数据。
这是一个演示db的鼻子:
; 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的右边所取代。