【问题标题】:Assembler program crashes after call to printf调用 printf 后汇编程序崩溃
【发布时间】:2019-04-07 23:33:32
【问题描述】:

我正在编写一个简单的函数来从堆栈中打印一个浮点值。这个函数是生成的,所以没有优化。程序在 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

【问题讨论】:

    标签: c assembly x86 fasm


    【解决方案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,并在 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
    

    【讨论】:

    • @mcmikecreations - 是的,返回在 ebp+4。我已将代码转换为与 Visual Studio 一起使用,但在复制和粘贴转换后的代码时丢失了编辑。除非 printstr 是一个问题,否则我不确定问题是什么。
    • 非常感谢您的回答!错误确实与括号有关,fasm 有时使用宏来自动填充这些内容,但这种情况并非如此。我已经习惯了这种自动化,以至于开始忘记重要的事情。也感谢你发布 masm 版本,我用 masm 在 VS 中测试东西,然后再用 fasm 编写它。
    猜你喜欢
    • 2014-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    相关资源
    最近更新 更多