当 esp 不是非常低时,汇编程序函数不执行
assembler function not executing when esp is not exetremely low
我目前正在编写 运行 处于实模式的汇编程序。
我使用 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,它再次不起作用。
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
.
(*) 您 可以 ,但是设置 虚幻地址模式 可能不值得花费这么短的时间这个引导程序。
我目前正在编写 运行 处于实模式的汇编程序。 我使用 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,它再次不起作用。
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
.
(*) 您 可以 ,但是设置 虚幻地址模式 可能不值得花费这么短的时间这个引导程序。