Программа на ассемблере аварийно завершает работу после вызова printf

Я пишу простую функцию для печати значения с плавающей запятой из стека. Эта функция сгенерирована, поэтому она не оптимизирована. Программа вылетает при вызове 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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
479
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Глядя на изображение, я вижу потенциальную проблему, но не знаю синтаксиса 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-битную сборку с использованием Visual Studio 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

@mcmikecreations - да, возврат на ebp+4. Я преобразовал код для работы с Visual Studio, но потерял редактирование, в котором я скопировал и вставил преобразованный код. Если printstr не является проблемой, я не уверен, в чем проблема.

rcgldr 08.04.2019 11:46

Большое спасибо за ответ! Ошибка действительно была со скобками, fasm иногда использует макросы для автоматического заполнения этого материала, но в этом случае это было не так. Я так привык к этой автоматизации, что начал забывать важные вещи. Спасибо за публикацию версии для masm, я использую masm для тестирования вещей в VS, прежде чем писать их в fasm.

mcmikecreations 08.04.2019 14:59

Другие вопросы по теме