assembly - 为什么 `cmpsb`似乎没有比较寄存器的值?

标签 assembly nasm x86-16

我正在尝试在 16 位实模式下编写 DOS 克隆,尽管一旦我完成了当前问题,我可能只会学习 32 位汇编。我的问题过去一直受到负面回应,但这是最后一次,恐怕我确实需要咨询这个网站。改进我之前的问题,我付出了更多的努力来了解有关汇编代码中的指针和堆栈的更多信息。
显然,cmpsb 指令比较两个字符串,分别位于 ESDS 中。我正在尝试将 INPUT_STRING 的值移至 DS,并将 shutmsg 的值移至 ES,这看起来像正确的寄存器(这些是之前声明的变量)。我的指令看起来没问题并且编译得很好,但是当我输入 shutdown 时它不起作用,当我通过 GDB 运行它时,它显示的只是

0x0000fff0 in ?? ()

我不知道出了什么问题。我真的不知道。这是我的代码:

prompts:
    mov si, prompt
    call prints
    call scans
    push ds
    mov ds, [INPUT_STRING]
    mov es, [shutmsg]  
    mov cx, 0xFFFF
    cld
    repe cmpsb
    pop ds
    je shutdown
    mov si, newline
    call prints
    mov si, INPUT_STRING
    call prints
    mov si, newline
    call prints
    jmp prompts

提前致谢,如果这又是一个糟糕的问题,我们深表歉意。

最佳答案

事实上cmpsb比较分别由ES:DIDS:SI指向的两个字符串。我所说的 ES:DI 是指一对寄存器 ESDI,其中 ES 将保存段地址, DI 将保存偏移地址。 (你理解分段寻址吗?从你的问题中并不清楚)。

查看您的代码,有几处不正确的地方,例如:

mov ds, [INPUT_STRING]

...会将内存位置 INPUT_STRING 中的值加载到 ds 寄存器中。首先,从您的问题中不清楚 INPUT_STRING 是否确实包含指向字符串或字符串本身的指针,但我怀疑(基于您后续的代码)它是字符串本身的位置。因此,您不仅加载了错误的值,而且只加载了 ds 而不是 si

将正确的值加载到ds取决于字符串的段地址,并且这在问题中并不明显(因此很难为您提供有用的建议)。如果它与代码段相同(这可能是小程序),则可以将 esds 设置为与 cs 相同的值,类似:

mov ax, cs
mov ds, ax
mov es, ax

(但是,这只是一个示例。正确的解决方案取决于代码的其余部分)。然后,您需要加载 sidi 寄存器:

mov si, INPUT_STRING
mov di, shut_msg

您正在使用 0xFFFF 加载 cx:

mov cx, 0xFFFF
为什么?字符串的长度是否正好为 0xFFFF 字节?如果不是,您将不仅仅比较字符串的长度并得到虚假结果。

总结:

  • 您需要了解分段寻址模型以及段寄存器的用途
  • 您需要了解字符串值和字符串指针之间的区别,以及值和指针之间的一般区别
  • 您需要了解字符串在内存中的存储方式
  • 您需要阅读并理解指令行为/语义

关于assembly - 为什么 `cmpsb`似乎没有比较寄存器的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47226326/

相关文章:

assembly - mov [string]、WORD PTR 'HE' 的 MASM 语法

linux x64加法程序

assembly - DosBox如何修复字符属性?

gcc - 约束 "Rah"和 "Ral"在扩展内联汇编中意味着什么?

c - 为什么编译器会在编译的汇编代码中生成额外的 sqrts

assembly - 是否有为z/assembler量身定制的emacs组织模式的变体?

assembly - 由 nasm 插入的冗余 DS 段覆盖前缀?

c# - 即使条件评估为 false,If 语句似乎也在评估

loops - 汇编语言中的 While、Do While、For 循环 (emu8086)

linux - Hello World 通过一个系统调用打印两条消息?为什么 length equ $-msg1 包括两者?