【问题标题】:Division of two numbers in NASM [duplicate]NASM中两个数字的除法[重复]
【发布时间】:2018-01-12 08:54:07
【问题描述】:

开始自学组装 (NASM) 我想知道如何除以 2 个数字(例如在 Windows 上)。

我的代码看起来像这样,但它崩溃了。

global _main
extern _printf

section .text

_main:

mov eax, 250
mov ebx, 25
div ebx
push ebx
push message 

call _printf
add esp , 8
ret

message db "Value is = %d", 10 , 0

我想知道真正的问题是什么?它甚至不显示除法后的值。

【问题讨论】:

  • 请参阅指令集参考以了解 div 的工作原理。提示:被除数是 64 位值,您需要将 edx 归零。此外,调用约定要求 ebx 被保留,并且结果不会在 ebx 中。
  • 汇编指令不遵循意愿或逻辑,即仅仅因为某些指令被称为“DIV”,并不意味着它可以按预期工作。但是您的代码看起来像您没有检查说明手册。您需要指令参考指南(simplified web version here)(但在极少数情况下不要犹豫使用英特尔官方文档)进行 ASM 编程,经常检查它是否有各种指令(尤其是涉及标志或其他棘手的微妙细节时,像DIV 行为)。

标签: assembly x86 nasm integer-division


【解决方案1】:

您的指令div ebx寄存器对 edx:eax(这是该指令的隐式操作数)除以提供的源操作数(即:除数)。


mov edx, 0
mov eax, 250
mov ecx, 25
div ecx

在上面的代码中,edx:eax除数ecx除数。 执行div 指令后,寄存器eax 包含edx 包含余数


我使用寄存器ecx 而不是ebx 来保存除数,因为像stated in the comments 一样,必须在调用之间保留寄存器ebx。否则必须在修改前正确保存并在从相应子程序返回前恢复


除以零错误可能会发生

作为stated in one comment,如果商不在商寄存器的范围内(在这种情况下为eax),则会发生除以零错误

这可以解释程序崩溃的原因:因为在执行div 指令之前没有设置寄存器edx,它可能包含一个非常大的值,以至于结果商不适合@ 987654337@注册。

【讨论】:

  • 我已经意识到,在设置eaxxor edx, edx 之后,cdq 的性能将优于mov edx, 0。我只是使用后者来使代码更易于理解。
  • cdq 符号将 eax 扩展为 edx,而不是零扩展它。
  • @MichaelPetch 你是对的,cdq 符号将eax 扩展为edx,因此它适合idiv 而不是div
  • 这解释了正确使用 div,但没有解释为什么代码崩溃而不是打印值是 25。在大多数汇编程序中,“推送消息”推送消息的前 4 个字节而不是消息的地址。但在 NASM 中,该语法确实会推送地址。所以这次崩溃仍然无法解释。
【解决方案2】:

其他 cmets 和答案解释了如何正确使用 div,但它们没有解释为什么您的代码会崩溃而不是打印错误的结果。在大多数汇编程序中,“推送消息”推送消息的前 4 个字节,而不是消息的地址,这正是 printf 所期望的。在 NASM 中,据我所知,它会推送地址。但是你应该仔细检查一下,因为我不使用 NASM。

【讨论】:

  • 在 NASM 语法中,它推送地址。你总是需要[] 来做内存引用。
  • 此外,如果商不适合 32 位寄存器,它可能会因 SIGFPE(或 Windows 等效项)而崩溃。 (与除以零相同的错误。)
猜你喜欢
  • 2016-10-12
  • 2015-07-28
  • 2021-12-02
  • 2013-07-14
  • 1970-01-01
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多