在NASM程序集中,有db
和dw
伪指令来声明数据。 NASM Manual提供了几个示例,但没有直接说明它们之间的区别。我已经尝试了以下"你好世界"两者都有代码,事实证明没有可观察到的差异。我怀疑明显与内部数据格式有关,但我不知道如何检查它。
section .data
msg db "hello world",10,13,0
msg2 dw "hello world",10,13,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, msg ; or use msg2
mov rdx, 14
syscall
jmp .exit
.exit:
mov rax, 60
mov rdi, 0
syscall
答案 0 :(得分:2)
dw 'a'
相当于dw 0x61
并将WORD 0x0061(big-endian)存储为61 00
(little-endian)。
dw 'ab'
(little-endian)相当于dw 0x6261
(big-endian)并存储61 62
(little-endian)。
dw 'abc'
(一个字,一个字节)相当于dw 0x6261, 0x63
并存储两个字(小端):61 62 63 00
。
dw 'abcd'
(两个单词)存储两个WORD:61 62 63 64
。
msg2 dw "hello world",10,13,0
将字符串转换为6个单词,将数字转换为3个单词并将其存储:68 65 6C 6C 6F 20 77 6F 72 6C 64 00 0A 00 0D 00
。在您的示例中,msg将在结束之前不会打印。
答案 1 :(得分:2)
NASM手册部分3.2.1 DB and Friends: Declaring Initialized Data和3.4.2 Character Strings表示单个字符串短于元素大小时存在差异。每个元素都用零字节填充到其原始大小。
为确保数据中没有非预期的字符,请始终将DB用于8位字符串。 DW可能适用于UTF-16,也可能不适用,具体取决于机器字节顺序和代码中的任何假设。
使用DW伪指令肯定会导致数值的意外值,因为这些值将被解释为16位字,将意外的空字符引入字符串。
使用2.1.3 The -l Option: Generating a Listing File查看正在输出的实际内存图像,以查看您正在生成的内容。
答案 2 :(得分:1)
NASM的db
,dw
,dd
等接受一个整数列表,并将它们编码为little-endian,例如: dw 0x1234, 0x5678
组合为34 12 78 56
。
NASM还支持多字符字符文字,例如'ab'
在任何接受整数的上下文中,例如。 add ax, '00'
与0x3030
相同。 (也许用于未压缩的BCD-> ASCII转换。)
NASM的多字符字面量字节顺序在内存中的生成顺序与little-endian x86上的源顺序相同。因此,例如mov eax, '1234'
/ mov [buf], eax
将在存储器中产生与buf: db '1', '2', '3', '4'
相同的4字节序列。 mov
指令被编码为b8 31 32 33 34
,因为x86立即操作数使用Little-endian,就像数据加载/存储一样。
对于args db
/ dw
/ dd
/ etc 有一种特殊情况:而不是像add ax, '123456'
那样被截断,( foo.asm:1: warning: word data exceeds bounds [-w+number-overflow]
)仅保留整数值的低字节/字/双字,ASCII或UTF-8字符串被视为多个元素。
但是最后一个元素用零填充(最后是little-endian)使总大小是元素大小的倍数(dw / ddd代表dd等)
所以所有这些都是完全相同的
db 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x00
db 'a', 'b', 'c', 'd', 'e', 'f', 'g', 0
db 'abcdefg', 0
db `abcdefg\0` ; C-style escapes like \n or \0 work inside backtick strings only. (NASM only, not YASM)
dw 'abcdefg' ; 7 bytes padded to 4 words = 8
dw 'ab', 'cd', 'ef', 'g' ; 'g' is a small WORD value
dw 0x6261, 0x6463, 0x6665, 0x0067 ; x86 is little-endian (LSB first) but we write integer values with MSD on the left
dd 'abcdefg' ; 7 bytes padded to 2 dwords = 8
使用dd
和dq
(以及do
和其他更广泛的类型),您可以拥有超过1个字节的零,但始终位于结尾。例如dd 'abcde'
是db 'abcde', 0,0,0
。
请参阅NASM手册3.2.1 DB and Friends: Declaring Initialized Data和3.4.2 Character Strings
源值和诸如0x123456
之类的整数值没有“字节序”。那是对术语的滥用。
字节序是将多字节整数序列化到内存,然后按照地址递增的顺序检查各个字节时看到的效果。
从MSD到LSD约定,从左到右的阿拉伯数字是与内存中字节顺序分开的东西。在通常情况下,我们通常使用地址从左到右递增的方式来绘制内存图,并且我们写数字的方式恰好像Big Endian。
我们也可以使用罗马数字来表示源代码和/或伪代码或任何其他计数系统中的数字。 (例如一元,其中3 = 111)。
记住,“小尾数会使数字倒数”,这在脑海中并不是一个不好的捷径。但这是在字节边界上,而不是十六进制(4位)边界上。
但是不要陷入认为寄存器中的值是“大端”的陷阱。除了存储在内存中之外,它们没有字节序。