Я пишу простую функцию для печати значения с плавающей запятой из стека. Эта функция сгенерирована, поэтому она не оптимизирована. Программа вылетает при вызове 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
Глядя на изображение, я вижу потенциальную проблему, но не знаю синтаксиса 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
Большое спасибо за ответ! Ошибка действительно была со скобками, fasm иногда использует макросы для автоматического заполнения этого материала, но в этом случае это было не так. Я так привык к этой автоматизации, что начал забывать важные вещи. Спасибо за публикацию версии для masm, я использую masm для тестирования вещей в VS, прежде чем писать их в fasm.
@mcmikecreations - да, возврат на ebp+4. Я преобразовал код для работы с Visual Studio, но потерял редактирование, в котором я скопировал и вставил преобразованный код. Если printstr не является проблемой, я не уверен, в чем проблема.