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

qax*_*uux 4 x86 assembly nasm

我目前正在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
Run Code Online (Sandbox Code Playgroud)

joh*_*und 7

您必须将字符串数据移到代码之外,因为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
Run Code Online (Sandbox Code Playgroud)

只要这些指令非常随机,就会产生随机行为.另请注意,堆栈指针已被修改,因此在程序退出时会出现更多混乱.

  • @ qaxf6auux - 除非您想要将数据作为指令执行.汇编语言是有史以来最强大的语言,这种方法有时可以用于某些目的.你只需要总是知道自己在做什么.此外,例如在FASM库中,有些宏允许您在任何地方定义数据,但稍后将所有定义的数据分组到一个连续的块中的不同位置. (3认同)
  • @john:我想说"如果你是",因为我知道16位代码通常没有一个很好的OS程序加载器.考虑到使用bochs,我猜测引导扇区,但是.COM也是可能的.当然,`.rodata`链接器部分在链接后成为文本段的一部分,所以我说的所有内容仍然适用于制作.COM.段用于分组,但是对于加载(例如ELF二进制),加载器只需关心text/data/bss段,而不是像.rodata这样的段.如果你使用`section.rodata`和`-fbin`,那么NASK会在实践中做些什么 (3认同)