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.