Программа Ассемблер вылетает после вызова printf - PullRequest
0 голосов
/ 08 апреля 2019

Я пишу простую функцию для вывода значения с плавающей точкой из стека. Эта функция генерируется, поэтому она не оптимизирована. Сбой программы при вызове printf.

;input: float32 as dword ptr ebp+8
printfloat32:
 push   ebp
  mov   ebp,    esp
  sub   esp,    16
;local ptr variable k at dword ptr ebp-4
  mov   dword ptr ebp-4,    lpcstr4 ;which is "%f"

movss       xmm0,           dword ptr ebp+8
cvtss2sd    xmm0,           xmm0
  sub       esp,            8
movsd       qword ptr esp,  xmm0
 push       dword ptr ebp-4
 call       printstr
  add       esp,            12

  mov   esp,    ebp
  pop   ebp
  ret

printstr - это printf. Вот полный сгенерированный код: https://pastebin.com/g0Wff0JY

1 Ответ

1 голос
/ 08 апреля 2019

Глядя на изображение, я вижу, что может быть потенциальной проблемой, но я не знаю синтаксис fasm:

        call    [printstr]     ;syntax used for the first call
        ...
        call    printstr       ;syntax used for the second call that fails

Если printstr - это указатель на функцию, основанный на памяти, то второй вызовсинтаксис может пытаться выполнить вызов в том месте, где хранится указатель, а не вызывать фактическую функцию, используя значение в памяти в качестве указателя на функцию.

В случае последних версий Visual StudioСтандартные printf и scanf эффективно встроены в код C / C ++ с довольно сложным синтаксисом.Вместо того, чтобы справляться с этим, существуют доступные версии, которые можно вызвать с помощью этого оператора includelib:

        includelib      legacy_stdio_definitions.lib    ;for scanf, printf, ...

Я преобразовал код из вопроса в синтаксис masm, изменил printstr на printf и протестировал 32-битную сборку с использованием VisualStudio 2015 на 64-битной Windows 7 Pro (сборка 32-битная, поэтому была запущена в 32-битном режиме).У меня не было проблем с этим кодом.Я прошел по коду с помощью отладчика и не увидел никаких проблем с тем, как вещи хранятся в стеке.Я подозреваю, что проблема связана со вторым вызовом printstr без скобок, который я исправил как часть преобразования в синтаксис masm.

        .data
varf    real4   123.75
lpcstr4 db      "%f",00ah,0             ;added new line
        .code
        extern  printf:near             ;instead of printstr

printfloat32 proc
        push    ebp
        mov     ebp,esp
        sub     esp,16
        mov     dword ptr [ebp-4], offset lpcstr4
        movss   xmm0,dword ptr [ebp+8]
        cvtss2sd xmm0,xmm0
        sub     esp,8
        movsd   qword ptr [esp],xmm0
        push    dword ptr [ebp-4]
        call    printf                  ;was printstr
        add     esp,12
        mov     esp,ebp
        pop     ebp
        ret
printfloat32 endp

main    proc
        push    varf            ;test printfloat32 function
        call    printfloat32
        add     esp,4
        xor     eax,eax
        ret
main    endp
        end

Использование printstr в качестве указателя на printf.Masm не нужны скобки, поскольку он знает, что printstr - это dd (указатель на printf).

        .code
        extern  printf:near
printstr dd     printf          ;masm doesn't need brackets

printfloat32 proc
;       ...
        call    printstr        ;masm doesn't need brackets
;       ...
printfloat32 endp

Если бы printstr был внешним по отношению к этому исходному файлу, синтаксис masm был бы

        extrn   printstr:ptr    ; or extern   printstr:dword
...