NASM x86 使用不存在的段寄存器 7

NASM x86 using of nonexisting segment register 7

我目前正在用 x86 汇编语言编写一个简单的程序,它在任意内存地址获取数据并以十六进制将其打印到终端。它是在 NASM 2.12.02 中组装的,我是 运行 带有 bochs 2.6.8 的结果 bin。我编写了一个名为 print_hex.asm 的例程,它使用 db 来定义 ascii 字符的索引,如下所示。

ascii_table: db "0123456789ABCDEF"

组装完整程序和运行结果时,同一行

(an increasing number)i[CPU0 ] MOV_EwSw: using of nonexisting segment register 7

一遍又一遍地打印到终端,前面是一个不断增加的数字。奇怪的是,如果我将行更改为

ascii_table: db "0123456789ABC"

通过简单地省略字符串的最后三个字母,它工作得很好(尽管汇编程序在尝试转换 D、E 或 F 的十六进制值时会出现运行时错误)

这是怎么回事?不允许我连续申报那么多数据吗? NASM 是在骚扰我吗?

编辑:请参阅下面的完整源代码。请注意,它仍在进行中,其他地方可能存在逻辑错误。

print_hex:                        ; prints the value stored at bx in hex
    pusha                         ; push all the local registers to the stack
    ascii_table:                  ; define a table to store ascii characters for conversion
        db "0123456789ABCDEF"
    mov ah, 0x0e                  ; move 0x0e to the high byte of ax in preparation for a teletype interrupt
    mov al, "0"                   ; move the ascii char 0 to the lower byte of ax
    int 0x10                      ; perform a teletype interrupt
    mov al, "x"                   ; move the ascii char x to the lower byte of ax
    int 0x10                      ; perfrom a teletype interrupt
    mov dx, 0                     ; move 0 to dx in preparation for the loop
    mov cx, 0                     ; zero out cx
    hex_print_loop_start:
        mov cl, bl                ; move bl to cl to isolate the lowest nybble of bx
        add cl, ascii_table       ; set the table offset with cx
        mov al, cl                ; get the value at the offset index of the table and store it in al for printing
        int 0x10                  ; perform a teletype interrupt
        inc dx                    ; increment dx by one
        shr bx, 1                 ; shift bx right in preparation for reading the next character
        cmp dx, byte 0x04         ; check if the loop has been performed 4 times
        jl hex_print_loop_start   ; if it hasn't been performed 4 times, jump to the beginning of the loop
    popa                          ; restore local registers
    ret                           ; return

您必须将字符串数据移到代码之外,因为CPU在执行pusha指令后会将字符串作为指令执行。您的字符串被解释为以下代码:

'01'  30 31  XOR BYTE PTR [BX+DI],DH
'23'  32 33  XOR DH,BYTE PTR [BP+DI]
'45'  34 35  XOR AL,35H
'67'  36:37  SS:AAA                   ;  Superfluous prefix
'89'  38 39  CMP BYTE PTR [BX+DI],BH
'A'   41     INC CX
'B'   42     INC DX
'C'   43     INC BX
'D'   44     INC SP
'E'   45     INC BP
'F'   46     INC SI

只要这些指令是相当随机的,那么随机行为就是意料之中的。另请注意,堆栈指针已修改,因此在程序退出时会出现更多混乱。