首页 > 解决方案 > 调用 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

标签: cassemblyx86fasm

解决方案


查看图像,我看到可能是一个潜在问题,但我不知道 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 并在 Windows 7 Pro 64 位上使用 Visual Studio 2015 测试了 32 位构建(构建是 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

推荐阅读