0

编写一个 NASM 宏:divide,它有 2 个参数,指定任何寻址模式下的无符号整数。宏计算其第一个参数的上限,除以第二个参数,并将结果放入寄存器 edx。如果第二个参数为 0(要在运行时测试),则结果应为 0,并且应将消息“除以零”打印到标准输出。

我怎么知道哪个是哪个,所以我们可以处理每个案例?(;地址模式是:寄存器、内存和立即数。)

编辑:这是我写的最终代码:如何编写没有标签的代码?(位置独立代码):

%macro divide 2

section .rodata
        LC1: DB "divide by zero ", 10, 0

section .text

  mov eax, %1
  mov ebx, %2
  cmp ebx, 0 ; divide by zero
  jne rest1
  push LC1
  call printf
  add esp,4
  mov edx, 0
  jmp end1

rest1:
  mov edx, 0
  div ebx
  add eax, edx
  mov edx , eax ; the result should be in edx

end1:
 %endmacro
4

1 回答 1

1

你不需要告诉哪个是哪个。从任何位置(另一个寄存器、内存、立即常数)加载一个通用寄存器EAX是可能的。MOV充分利用这一点。

编辑

为了更清楚,这就是您可以编写这样的宏的方法:

%macro mydiv 2
  mov eax, %1
  mov ebx, %2
  mov edx, 0
  div ebx
%endmacro

这就是你将如何使用它:

  mydiv 3, 2 ; 2 immediate operands

  mov ebx, 15
  mov ecx, 3
  mydiv ebx, ecx ; 2 register operands

  mydiv [dividend], [divisor] ; 2 memory operands

...

  dividend dd 42
  divisor  dd 6

当然,宏的定义方式对除法操作数的位置有一定的限制。例如,操作数 2(除数)不能在,EAX因为前面的指令会将被除数放入mov ebx, eax操作数 1(除数)中。EBXmov eax, %1EAX

您可以通过使用堆栈来解决这个问题:

%macro mydiv2 2
  push  ebx
  push  %1
  push  %2
  pop   ebx
  pop   eax
  mov   edx, 0
  div   ebx
  pop   ebx
%endmacro

这个宏将接受来自任何寄存器的除数和被除数,它不会垃圾EBX。唯一的(次要)问题是当您的操作数在内存中并且相对于 寻址时ESP,例如:

mydiv2 eax, [esp+8]

这些推动力发生了变化ESP,必须加以考虑。

编辑2

有一个警告mydiv2......它会将立即常量(例如 123)推送为 16 位模式下的 16 位和 32 位模式下的 32 位,但会将它们弹出为 32 位。要 mydiv2在 16 位模式下工作,您需要在直接常量前面加上dword

  mydiv2 dword 3, dword 2 ; 2 immediate operands

您现在可以在宏中实现其余所需的功能。

于 2012-06-24T11:16:25.790 回答