функция ассемблера не выполняется, когда esp не очень низкий - PullRequest
0 голосов
/ 03 ноября 2018

Я сейчас пишу ассемблерную программу, которая работает в реальном режиме. Я компилирую его с помощью 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

Спасибо за вашу помощь.

EDIT: Я только заметил еще более странную вещь: Если я отлаживаю с помощью gdb и logg sp после каждой инструкции (точки останова + x / x $ sp) (кроме цикла), это волшебным образом работает так, как должно. Если я запускаю с GDB без каких-либо точек останова, он снова не работает.

1 Ответ

0 голосов
/ 04 ноября 2018
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.

(*) Вы можете , но настройка нереального режима адреса может не стоить проблем из-за короткого времени, проведенного в этом загрузчике.

...