2015-04-17 1 views
0

Environment, Win 7. Использование NASM, GCC (MinGW)Почему fopen не удается выполнить простой вызов сборки? [Внимание: длинный источник сборки]

У меня есть следующие очень простой источник сборки:

SECTION .data  ; initialized data 
    fname:  db "c:\asmplus\tsources\s1.txt", 0 
    fread:  db "r", 0 
    mopf:  db "[FILE] open: %s", 10, 0 

SECTION .text  ; code 
    extern _fopen 
    extern _printf 

    push  DWORD    fname 
    push  DWORD    mopf 
    call  _printf 
    add   esp, 8   ; clean up stack use 

    mov   DWORD [esp],  fname 
    mov   DWORD [esp + 4], fread 
    call  _fopen 

я получаю следующий результат:

[FILE] открыто: с: \ asmplus \ tsources \ s1.txt

... а затем диалог Windows, произнося приложения час как разбился. У меня нет никакого отладочного устройства, поэтому я пропустил его до самого простого источника и попробовал его именно так. Файл доступен, а не открыт. Что-то не так с моим кодом?

UPDATE
полный код добавил @ просьбе шута

parse.asm

SECTION .data   ; initialized data 
    mend:  db 10, "*** END ***", 10, 0 

    mopf:  db "open_file", 0 

    mcll:  db "[MAIN] call %s: %s", 10, 0 
    mret:  db "[MAIN] ret: %d", 10, 0 


SECTION .text use32  ; code 
    extern open_file 
    extern _printf 

    global _main 

    _main: 
     ; stash base stack pointer 
     push ebp 
     mov  ebp, esp 

     mov  eax, [ebp + 8] ; num args 
     mov  ebx, [ebp + 12] ; address of args (strings) 
     mov  ecx, 0   ; init counter register to 0 

     .do: 
      push ebp 
      push eax 
      push ecx 

      mov  [c], ecx 

      ; only expect args[1] to contain the file name 
      mov  eax, 1 
      cmp  eax, [c] 
      jne  .cont 
      jmp  .openFile 

      .cont: 
       pop  ecx 
       pop  eax 
       pop  ebp 

       add  ebx, 4  ; move to next arg 
       inc  ecx    ; increment counter 

       cmp  ecx, eax 
       jne  .do 

     .openFile: 
      push DWORD [ebx] 
      push DWORD mopf 
      push DWORD mcll 
      call _printf 
      add  esp, 12 

      push DWORD [ebx] 
      call open_file   ; should push result to eax 

      mov  eax, [ebp + 8] ; stash file handle from stack 
      mov  [fh], eax   ; into fh variable 

      add  esp, 4   ; clean up stack 

      push DWORD [fh] 
      push DWORD mret 
      call _printf 
      add  esp, 8   ; clean up stack 

     .end: 
      push DWORD mend 
      call _printf 
      ; restore base stack pointer 
      mov  esp, ebp 
      pop  ebp 

SECTION .bss   ; uninitialized data 
    c:  resd 1 
    fh:  resd 1 

fileops.asm

; Contains file operations: 
;  open_file 
;  ... TODO: read/write/close 

SECTION .data  ; initialized data 
    fread:  db "r", 0 

    merr:  db "[FILE] error [%d:%d] %s", 10, 0 
    mopf:  db "[FILE] open: %s", 10, 0 

SECTION .text  ; code 
    extern _fopen 
    extern _printf 

    global open_file 

    open_file: 
     ; stash base stack pointer 
     push ebp 
     mov  ebp, esp 

     mov  eax,  [ebp + 8] 
     mov  [fnarg], eax 
     push DWORD  [fnarg] 
     push DWORD  mopf 
     call _printf 
     add  esp, 8 

     ; open file 
     push DWORD fread 
     push DWORD [fnarg] 
     call _fopen 
     add  esp, 8 

     push DWORD [eax] 
     xor  eax, eax 

     .done: 
     ; restore base stack pointer 
     mov  esp, ebp 
     pop  ebp 

     ret 

SECTION .bss  ; uninitialized data 
    fnarg:  resb 128    ; reserve 128 bytes for file name 
    fhndl:  resd 1 

выходной ток:

D: \ asmplus> \ EXEs \ синтаксического анализа \ tsources \ s1.txt
[MAIN] вызов open_file:... \ Tsources \ s1.txt
[FILE] открыто:. \ Tsources \ s1.txt
[MAIN] RET: 2

ответ

1

Это все из кода? Если после этого у вас ничего не получится, это, конечно, потерпит крах, так как вы не закончите свою программу правильно, выполнив call _exit или просто вернувшись.

Также обратите внимание, что вы очищаете стек с помощью add esp, 8, поэтому у вас больше нет свободного места, в которое вы пытаетесь переместить аргументы. Вы переписываете вещи в стеке, такие как адрес возврата, что вызовет проблемы, если вы когда-нибудь попытаетесь вернуться из своей функции, например. Вы можете переместить это add вниз после call _fopen, когда вам действительно не нужны слоты.

Исправленная версия может выглядеть более как:

push  DWORD    fname 
push  DWORD    mopf 
call  _printf 

mov   DWORD [esp],  fname 
mov   DWORD [esp + 4], fread 
call  _fopen 
add   esp, 8   ; clean up stack use 
xor   eax, eax   ; 0 return value 
ret 

-или-

push  DWORD    fname 
push  DWORD    mopf 
call  _printf 
add   esp, 8   ; clean up stack use 

push  DWORD    fread 
push  DWORD    fname 
call  _fopen 
add   esp, 8   ; clean up stack use 
xor   eax, eax   ; 0 return value 
ret 
+1

Я завершающего правильно. Базовый тест перед реализацией 'call _fopen' напечатал желаемый результат и был правильно завершен. Именно в этом конкретном разделе приложение сбой. :) – IAbstract

+1

Как я уже сказал, если «закончить правильно» вы имеете в виду использование «ret», то это будет ошибкой, потому что ваш код перепутал стек. Опубликовать полный код, если вы не знаете, где проблема, в каком случае решить ее самостоятельно: P – Jester

+1

Вы помогли мне выяснить, что было не так. В моем исходном приложении я передаю имя файла аргумента команды в мою функцию open_file. Полагаю, я обнаружил, что некорректно переносил аргумент из стека и в переменную. Кажется, он работает сейчас. Благодаря! – IAbstract