【问题标题】:NASM x86 using of nonexisting segment register 7NASM x86 使用不存在的段寄存器 7
【发布时间】:2016-07-28 06:54:49
【问题描述】:

我目前正在用 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

【问题讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读About 页面并访问描述How to Ask a QuestionHow to create a Minimal, Complete, and Verifiable example 的链接。提供必要的详细信息,包括您的代码和相关错误(如果有),将让这里的每个人都能帮助您解决问题。
  • 看起来你的代码试图“运行”字符串,即字符串的字节在运行时被解释为代码。您可以发布 print_hex 的代码吗?只需编辑您的问题并将其包含在内。
  • ascii_table移动到函数之后。数据就是代码。
  • 您可以自己调试,方法是使用 bochs 的内置调试器单步执行您的代码,向您展示反汇编代码。
  • 谢谢,以后我会更好地使用调试器

标签: assembly x86 nasm


【解决方案1】:

你必须将字符串数据移到代码之外,因为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

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

【讨论】:

  • 这行得通。我将有问题的行移到 ret 指令之后,它运行完美。为了将来参考,我不应该将任何定义为数据的东西放在任何定义为指令的东西的中间,对吗?
  • @qaxf6auux - 除非您想将数据作为指令执行。汇编语言是有史以来最强大的语言,这种方法有时可以用于某些目的。您只需要始终知道自己在做什么。此外,例如在 FASM 库中,有一些宏允许您在任何地方定义数据,但后来将所有定义的数据分组到一个连续的块中的不同位置。
  • @qaxf6auux:最好将只读数据放在单独的部分中,这样所有只读数据都会组合在一起。然后您不必担心将它与您的代码混合或跳过这些字节。如果您正在编写用户空间程序,您将使用 section .rodatasection .data 初始化只读或读写数据,使用 section .bss 初始化零空间。
  • @PeterCordes - 它看起来像 DOS .com 文件。 COM 文件中没有“单独的部分”。
  • @john:我的意思是说“如果你是”,因为我知道 16 位代码通常没有好的操作系统程序加载器。考虑到使用 bochs,我猜测引导扇区,但是是的,.COM 也是可能的。当然,.rodata 链接器部分在链接后成为文本段的一部分,所以我所说的一切仍然适用于制作 .COM。部分用于对事物进行分组,但对于加载(例如 ELF 二进制文件),加载器只需要关心 text/data/bss 段,而不是像 .rodata 这样的部分。 IDK 如果您将section .rodata-fbin 一起使用,NASM 在实践中会做什么
猜你喜欢
  • 2014-02-04
  • 2019-12-04
  • 2012-02-17
  • 2014-11-19
  • 2019-01-02
  • 1970-01-01
  • 1970-01-01
  • 2017-04-23
  • 2020-07-03
相关资源
最近更新 更多