我目前正在编写以实模式运行的汇编程序。 我使用NASM进行编译。 我的问题是,如果我尝试从另一个函数调用一个函数,则仅当我从esp(70)中减去一个非常高的值或没有推送任何参数时,该函数才会执行。 我认为调用函数的方式存在问题,但是我无法弄清楚是什么。
完整的代码:
; boot.asm
[ORG 0x7c00] ;set base addresse
;mov ax, 0x7c0
xor ax, ax ; set zero
mov ds, ax ; set data pointer
mov ss, ax ; set stack start ptr
mov sp, 0x2000
add sp, ax
call main
hang:
jmp hang
main:
push ebp
mov ebp, esp
push 0x13
call setVideoMode_mode
add esp, 2
push 2
push 320*200
call clearScreen_char_n
add esp, 4
push 100
call drawVerticalLine
add esp, 2
nop
mov esp, ebp
pop ebp
ret
setVideoMode_mode:
push ebp
mov ebp, esp
mov ah, 0x00 ;change mode command
mov al, [ebp+6] ;video mode
int 0x10 ;execute command
mov esp, ebp
pop ebp
ret
putPixel_pos_char:
push ebp
mov ebp, esp
sub esp, 16 ; 3 local vars
mov eax, DWORD [ebp+8] ;POS
mov WORD [ebp-12], ax
mov eax, DWORD [ebp+6] ;CHAR
mov WORD [ebp-8], ax
mov DWORD [ebp-4], 0xA0000 ;STD VIDEO POINTER
mov eax, [ebp-12]
add eax, DWORD [ebp-4]
movzx edx, WORD [ebp-8]
mov BYTE [eax], dl
nop
; leave
mov esp, ebp
pop ebp
ret
;----------------------------
有问题的功能:
drawVerticalLine: ;doing debugging stuf at the moment
push ebp
mov ebp, esp
sub esp, 16 ;the function call only works with 70 or higher / no arguments for this function
mov eax, DWORD [ebp+6]
mov WORD [ebp-4], ax
push 4
push 320*200
call clearScreen_char_n ;not working (should make the screen red)
add esp, 4
nop
mov esp, ebp
push ebp
ret
clearScreen_char_n:
push ebp
mov ebp, esp
sub esp, 32
mov eax, DWORD [ebp+8]
mov WORD [ebp-12], ax ; CHAR
mov eax, DWORD [ebp+6]
mov WORD [ebp-8], ax ; N
mov DWORD [ebp-4], 0 ; COUNTER
jmp .LoopCompare
.LoopBody:
push WORD [ebp-4] ;COUNTER
push WORD [ebp-12] ;CHAR
call putPixel_pos_char
add esp, 4
inc DWORD[ebp-4] ;COUNTER ++
.LoopCompare:
mov ax, WORD [ebp-8] ;N
cmp ax, WORD [ebp-4] ;COUNTER
jne .LoopBody ;NOT EQUAL
nop
mov esp, ebp
pop ebp
ret
times 510-($-$$) db 0
db 0x55 ;mark bootsector
db 0xAA
感谢您的帮助。
编辑: 我只是注意到一个更奇怪的事情: 如果我在每条指令(断点+ x / x $ sp)(循环除外)之后使用gdb和logg sp进行调试,那么它神奇地工作了。 如果我在没有任何断点的情况下使用gdb运行,它将再次无法正常工作。
答案 0 :(得分:3)
mov DWORD [ebp-4], 0xA0000 ;STD VIDEO POINTER mov eax, [ebp-12] add eax, DWORD [ebp-4] movzx edx, WORD [ebp-8] mov BYTE [eax], dl
程序中的麻烦来自上述指令mov BYTE [eax], dl
错误地覆盖了内存!
因为整个程序都以实地址模式运行,所以您不能(*)通过其线性地址0xA0000访问视频存储器。您需要使用0xA000设置段寄存器,并在该段中使用16位偏移。
putPixel_pos_char:
push bp
mov bp, sp
push ds
mov ax, 0xA000 ; Segment of graphical video memory
mov ds, ax
mov al, [bp+4] ; 1st arg : Color
mov bp, [bp+6] ; 2nd arg : Position in video memory 0-63999
mov [ds:bp], al
pop ds
pop bp
ret
提示:如果代码确实不需要本地变量,则不要设置它!
此外,由于该程序以实地址模式运行,因此您应该停止使用ESP
和EBP
的操作方式。仅使用16位部分sp
和bp
。
(*)您可以,但是设置虚幻地址模式可能不值得在此引导加载程序中花费很短的时间。