定义字符串时db和dw之间的差异

时间:2015-01-21 21:14:36

标签: assembly nasm x86-64

在NASM程序集中,有dbdw伪指令来声明数据。 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

3 个答案:

答案 0 :(得分:2)

无论如何,NASM生产WORD; - )

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 Data3.4.2 Character Strings表示单个字符串短于元素大小时存在差异。每个元素都用零字节填充到其原始大小。

为确保数据中没有非预期的字符,请始终将DB用于8位字符串。 DW可能适用于UTF-16,也可能不适用,具体取决于机器字节顺序和代码中的任何假设。

使用DW伪指令肯定会导致数值的意外值,因为这些值将被解释为16位字,将意外的空字符引入字符串。

使用2.1.3 The -l Option: Generating a Listing File查看正在输出的实际内存图像,以查看您正在生成的内容。

答案 2 :(得分:1)

NASM的dbdwdd等接受一个整数列表,并将它们编码为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

使用dddq(以及do和其他更广泛的类型),您可以拥有超过1个字节的零,但始终位于结尾。例如dd 'abcde'db 'abcde', 0,0,0

请参阅NASM手册3.2.1 DB and Friends: Declaring Initialized Data3.4.2 Character Strings


源值和诸如0x123456之类的整数值没有“字节序”。那是对术语的滥用。

字节序是将多字节整数序列化到内存,然后按照地址递增的顺序检查各个字节时看到的效果。

从MSD到LSD约定,从左到右的阿拉伯数字是与内存中字节顺序分开的东西。在通常情况下,我们通常使用地址从左到右递增的方式来绘制内存图,并且我们写数字的方式恰好像Big Endian。

我们也可以使用罗马数字来表示源代码和/或伪代码或任何其他计数系统中的数字。 (例如一元,其中3 = 111)。

记住,“小尾数会使数字倒数”,这在脑海中并不是一个不好的捷径。但这是在字节边界上,而不是十六进制(4位)边界上。

但是不要陷入认为寄存器中的值是“大端”的陷阱。除了存储在内存中之外,它们没有字节序。