为什么这个 ASM 函数不能正确打印?
Why does this ASM function not print properly?
我正在尝试编写一个小函数来在特定内存位置打印以 null 结尾或固定长度的字符串。这是我的代码:
vbrstart:
xor eax, eax
mov sp, 0x7a00
mov bp, 0x6000
mov ss, ax
mov ds, ax
mov es, ax
xor ebx, ebx
xor ecx, ecx
push strict dword initializing
push strict word 0x0000
call printmsg
jmp end
;push strict dword memloc
;push strict word length
;call printmsg
printmsg:
pop strict dword [store_ret]
mov [store_cx], cx
mov [store_esi], esi
pop cx
pop esi
push eax
push ebx
mov ah, 0x0E
mov bx, 0x0007
cmp cx, 0x0000
je printnullterm
printgivenlen:
lodsb
cmp cx, 0x0000
je printdone
int 10h
dec cx
jmp printgivenlen
printnullterm:
lodsb
cmp al, 0x00
je printdone
int 10h
jmp printnullterm
printdone:
pop ebx
pop eax
mov esi, [store_esi]
mov cx, [store_cx]
push strict dword [store_ret]
ret
printdata:
store_cx dw 0
store_esi dd 0
store_ret dd 0
end:
hlt
jmp end
initializing db 10,13,'Initializing...',0
测试时,它不确定地打印,并且不会在空字节处停止。我哪里弄错了?
您的堆栈没有正确对齐所有的压入和弹出。检查传递的参数及其在例程中的用法。
首先,这里有一个提示:
vbrstart:
xor eax, eax
mov sp, 0x7a00
mov bp, 0x6000
mov ss, ax
mov ds, ax
mov es, ax
xor ebx, ebx
xor ecx, ecx
push strict dword initializing
push strict word 0x0000
call printmsg ; near call, only 16 bits ret addr stored
jmp end
;push strict dword memloc
;push strict word length
;call printmsg
printmsg:
pop strict dword [store_ret] ; pop dword (ret address + 16 bits- 1st argument)
mov [store_cx], cx ; store_cx = 0
mov [store_esi], esi ; store_esi = ??
pop cx ; cx = initializing
. . .
我发现您的代码有 2 个问题:
您已经编写了引导加载程序。这样的程序运行在16位实地址模式下。这意味着来自 call
的 return 地址将是一个 word 而不是像您的代码期望的 dword .
printmsg:
pop word [store_ret]
您以冒险的方式设置堆栈。您需要先更改 SS 寄存器,然后立即更改 SP 寄存器。
xor ax, ax
mov ss, ax <<< Keep these together
mov sp, 0x7a00 <<< and in this order!
由于这是 16 位代码,因此无需 push
/pop
双字地址。
push word initializing
...
pop si
我正在尝试编写一个小函数来在特定内存位置打印以 null 结尾或固定长度的字符串。这是我的代码:
vbrstart:
xor eax, eax
mov sp, 0x7a00
mov bp, 0x6000
mov ss, ax
mov ds, ax
mov es, ax
xor ebx, ebx
xor ecx, ecx
push strict dword initializing
push strict word 0x0000
call printmsg
jmp end
;push strict dword memloc
;push strict word length
;call printmsg
printmsg:
pop strict dword [store_ret]
mov [store_cx], cx
mov [store_esi], esi
pop cx
pop esi
push eax
push ebx
mov ah, 0x0E
mov bx, 0x0007
cmp cx, 0x0000
je printnullterm
printgivenlen:
lodsb
cmp cx, 0x0000
je printdone
int 10h
dec cx
jmp printgivenlen
printnullterm:
lodsb
cmp al, 0x00
je printdone
int 10h
jmp printnullterm
printdone:
pop ebx
pop eax
mov esi, [store_esi]
mov cx, [store_cx]
push strict dword [store_ret]
ret
printdata:
store_cx dw 0
store_esi dd 0
store_ret dd 0
end:
hlt
jmp end
initializing db 10,13,'Initializing...',0
测试时,它不确定地打印,并且不会在空字节处停止。我哪里弄错了?
您的堆栈没有正确对齐所有的压入和弹出。检查传递的参数及其在例程中的用法。 首先,这里有一个提示:
vbrstart:
xor eax, eax
mov sp, 0x7a00
mov bp, 0x6000
mov ss, ax
mov ds, ax
mov es, ax
xor ebx, ebx
xor ecx, ecx
push strict dword initializing
push strict word 0x0000
call printmsg ; near call, only 16 bits ret addr stored
jmp end
;push strict dword memloc
;push strict word length
;call printmsg
printmsg:
pop strict dword [store_ret] ; pop dword (ret address + 16 bits- 1st argument)
mov [store_cx], cx ; store_cx = 0
mov [store_esi], esi ; store_esi = ??
pop cx ; cx = initializing
. . .
我发现您的代码有 2 个问题:
您已经编写了引导加载程序。这样的程序运行在16位实地址模式下。这意味着来自
call
的 return 地址将是一个 word 而不是像您的代码期望的 dword .printmsg: pop word [store_ret]
您以冒险的方式设置堆栈。您需要先更改 SS 寄存器,然后立即更改 SP 寄存器。
xor ax, ax mov ss, ax <<< Keep these together mov sp, 0x7a00 <<< and in this order!
由于这是 16 位代码,因此无需 push
/pop
双字地址。
push word initializing
...
pop si