【问题标题】:Why does `cmpsb` not seem to compare the values of registers?为什么`cmpsb`似乎不比较寄存器的值?
【发布时间】:2017-11-10 15:37:09
【问题描述】:

我正在尝试在 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

在此先感谢,如果这又是一个糟糕的问题,我们深表歉意。

【问题讨论】:

  • DS 和 ES 是 segment 寄存器,只是指针的一半。两个字符串的完整指针是 DS:SI 和 ES:DI
  • 您从哪里读到cmpsb 比较了“分别位于 ES 和 DS 中”的两个字符串?看来您需要继续阅读。
  • @cHao Hmmm...尝试时,汇编器抛出“操作码和操作数的无效组合”
  • @davmac 我想在某处的在线文档网站上,但是,再次检查,我发现它是 DS:SI 和 ES:DI
  • @SafalAryal 我祝你一切顺利,但如果你略读一些内容并在每次遇到最轻微的障碍时跳到stackoverflow,你就不会走得太远。你需要自己做研究。

标签: assembly nasm x86-16


【解决方案1】:

实际上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 字节吗?如果不是,您将不仅仅比较字符串的长度并得到一个虚假的结果。

总结:

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

【讨论】:

  • 谢谢!根据我之前提出的问题,这两个值都是指向字符串的指针。如果你想(无论如何,我现在可以解决这个问题)我的完整代码是github.com/safsom/kerryos。我在另一个 SO 问题(不是我自己的问题)上被告知,由我的输入函数创建的 C 样式字符串具有该长度
  • 好的,我现在正在阅读分段寻址模型。我确实需要学习这个。
  • @SafalAryal 从您的代码中我看到 INPUT_STRING 是字节保留区域的标签。所以,mov si, INPUT_STRING 加载 si 并带有指向该区域的指针,是的。但是mov si, [INPUT_STRING] 做了其他事情——它从该内存区域加载一个字大小的值。如果INPUT_STRING 是一个变量,那么我们将说它是一个指针。然而,不同的人可能会略有不同。
  • @SafalAryal 我很高兴为您提供帮助。但是:那里有很多代码示例 - 阅读它们,理解它们。他们会为您提供更多帮助。
  • @SafalAryal 还有:如果scans 是您的输入函数,它肯定不会总是创建长度为0xffff 的字符串。如果您键入“shutdown”,然后由 nul 终止,那么长度怎么可能是 0xffff?如果算上 nul 终止符,则为 8 或 9。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-24
  • 1970-01-01
  • 2017-01-18
  • 2016-01-28
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
相关资源
最近更新 更多