当 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

提示:如果代码确实不需要,请不要设置局部变量!

另外因为这个程序运行在实地址模式,你应该停止使用ESPEBP的方式。仅使用 16 位部分 spbp.

(*) 您 可以 ,但是设置 虚幻地址模式 可能不值得花费这么短的时间这个引导程序。