当esp极低时汇编函数不执行

时间:2018-11-03 15:35:27

标签: assembly x86 gdb nasm real-mode

我目前正在编写以实模式运行的汇编程序。 我使用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运行,​​它将再次无法正常工作。

1 个答案:

答案 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

提示:如果代码确实不需要本地变量,则不要设置它!

此外,由于该程序以实地址模式运行,因此您应该停止使用ESPEBP的操作方式。仅使用16位部分spbp

(*)您可以,但是设置虚幻地址模式可能不值得在此引导加载程序中花费很短的时间。