I assembled the following code with
nasm -f bin option
and put it into floppy image and then run with virtualbox
my goal is to call print_word
but how can I call print_word
here?
To learn how to call a function which is in extra sector,
I put print_word
into second sector with intension.
Thanks in advance.
main.asm:
org 0x7c00
start:
mov ax, 0x0206
mov cx, 0x0002
mov dx, 0x0000
mov bx, 0x7e00
push bx
pop es
mov bx, 0
.try_again:
int 13h
jc .try_again
mov ax, 0xabcd
push ax
jmp 0x7e00
jmp $
times 510 - ($-$$) db 0
dw 0xaa55
more:
%include "./common/print_word.asm"
print_word.asm:
;print_word(word)
print_word:
push bp
mov bp, sp
push word [bp+4]
call print_word_1
push word [bp+4]
call print_word_2
push word [bp+4]
call print_word_3
push word [bp+4]
call print_word_4
mov sp, bp
pop bp
ret
print_word_1:
push bp
mov bp, sp
mov ah, 0x0e
mov byte al, [bp+4]
shr al, 4
cmp al, 0x0a
jl .num
sub al, 0x0a
jmp .char
.num:
add al, '0'
jmp .put
.char:
add al, 'A'
jmp .put
.put:
int 10h
mov sp, bp
pop bp
ret
print_word_2:
push bp
mov bp, sp
mov ah, 0x0e
mov byte al, [bp+4]
shl al, 4
shr al, 4
cmp al, 0x0a
jl .num
sub al, 0x0a
jmp .char
.num:
add al, '0'
jmp .put
.char:
add al, 'A'
jmp .put
.put:
int 10h
mov sp, bp
pop bp
ret
print_word_3:
push bp
mov bp, sp
mov ah, 0x0e
mov byte al, [bp+5]
shr al, 4
cmp al, 0x0a
jl .num
sub al, 0x0a
jmp .char
.num:
add al, '0'
jmp .put
.char:
add al, 'A'
jmp .put
.put:
int 10h
mov sp, bp
pop bp
ret
print_word_4:
push bp
mov bp, sp
mov ah, 0x0e
mov byte al, [bp+5]
shl al, 4
shr al, 4
cmp al, 0x0a
jl .num
sub al, 0x0a
jmp .char
.num:
add al, '0'
jmp .put
.char:
add al, 'A'
jmp .put
.put:
int 10h
mov sp, bp
pop bp
ret
Use a regular CALL instruction. Your assembler will assemble a CALL NEAR with a displacement rather an absolute address. Something like this:
mov ax,0xabcd
push ax
call print_word
add sp,2 ;to restore the stack
jmp $
Also, note that your print_word routine
, when calling print_word_1
, print_word_2
, etc, doesn't restore the stack properly. Your calling convention requires the caller to remove the arguments it pushed on the stack, so after each call print_word_N
instruction, you have to restore the stack, either by issuing an add sp,2
instruction, or by popping the last stack element into an unused register. For example, like this:
As the value passed to the different print_word_N routines is always the same, and as your routines don't change the value of the parameter, you can optimize code size a litte by assuming the argument is already on the stack for the second and subsequent calls:
print_word:
push bp
mov bp, sp
push word [bp+4]
call print_word_1
call print_word_2
call print_word_3
call print_word_4
mov sp, bp
pop bp
ret
BTW: Don't forget this is a little endian machine. You are converting to hex and printing the byte at [ebp+4]
, then the byte at [ebp+5]
. This will result in CDAB
printed on screen. Two left-most digits of your hex number are located in the byte at [ebp+5]
so you should print them first, then digits stored at byte [ebp+4]
.
Ah! About loading sectors: your mistake is how you have considered the segment and offset of the block where the sector is loaded. You want to load the next sector at 0000:7E00, that is, next to the first 512 bytes of code loaded. Instead, you load it at 7E00:0000, which is not the same address at all.
The updated and fixed code is as follows (the part that loads the next sector):
org 0x7c00
start:
mov ax, 0 ;segment is 0
mov ds, ax
mov es, ax
.try_again:
mov ax, 0x0201 ;load 1 sector
mov cx, 0x0002 ;located at sector 2
mov dx, 0x0000
mov bx, 0x7e00 ;into 0000:7E00
int 13h
jnc .ok
.errorsector:
mov ax,0 ;reset floppy controller ir error
int 13h
jmp .try_again
.ok:
mov ax, 0xabcd
push ax
call print_word
add sp,2
jmp $