質問

Write a NASM macro: divide, which has 2 arguments, which specify unsigned integers in any addressing mode. The macro computes the ceiling of its first argument, divided by its second argument, and places the result in register edx. If the second argument is 0 (to be tested at runtime), the result should be 0, and a message "divide by zero" should be printed to stdout.

How can I tell which is which, so we can handle each case? (;The address modes are: register, memory, and immediate.)

edit: this is the final code i wrote: how to write this code without labels? (position indepen code):

%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
役に立ちましたか?

解決

You don't need to tell which is which. Loading a general-purpose register such as EAX is possible with the MOV instruction from any location (another register, memory, immediate constant). Take advantage of that.

EDIT:

To make it even more clear, this is how you could write a macro like that:

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

And this is how you would use it:

  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

Of course, the way the macro is defined imposes certain restrictions on where the division operands can be located. For instance, operand 2 (divisor) cannot be in EAX because mov ebx, eax would load EBX with operand 1 (dividend) since the preceding instruction mov eax, %1 would put the dividend into EAX.

You can work around that by using the stack:

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

This macro will accept the divisor and dividend from any registers just fine and it won't trash EBX. The only (minor) problem with it will be when your operand(s) is/are in memory and addressed relative to ESP, e.g.:

mydiv2 eax, [esp+8]

Those pushes change ESP and that has to be accounted for.

EDIT2:

There's one caveat with mydiv2... It will push immediate constants (such as 123) as 16-bit in 16-bit mode and 32-bit in 32-bit mode but will pop them as 32-bit ones. To make mydiv2 work in 16-bit mode you'd need to prefix the immediate constants with dword:

  mydiv2 dword 3, dword 2 ; 2 immediate operands

You can now implement the rest of the needed functionality in the macro.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top