【问题标题】:Linking error for 64-bit NASM code with MinGW 3264 位 NASM 代码与 MinGW 32 的链接错误
【发布时间】:2019-06-22 15:42:45
【问题描述】:

我写了这段代码:

    global  _main
    extern  _printf

    section .text
_main:
    push    message
    call    _printf
    add     esp, 4
    ret
message:
    db  'Hello, World', 10, 0

并尝试从 cmd 运行它。看起来是这样的:

C:\Users\user\AppData\Local\bin\NASM>nasm helloworld.asm -f win64 -o helloworld.obj

C:\Users\user\AppData\Local\bin\NASM>gcc helloworld.obj -m64 -o helloworld.exe
helloworld.obj: file not recognized: File format not recognized
collect2: ld returned 1 exit status

我在 google 中搜索了这个错误,但没有什么与我相关。如您所见,我正在使用 Windows (10)。有人知道如何解决这个问题吗?谢谢。

当我运行 gcc -v 我得到这个:

Reading specs from C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/specs
Configured with: ../gcc-3.4.5-20060117-3/configure --with-gcc --with-gnu-ld --with-gnu-as --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls --enable-languages=c,c++,f77,ada,objc,java --disable-win32-registry --disable-shared --enable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x --enable-java-gc=boehm --disable-libgcj-debug --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.5 (mingw-vista special r3)

【问题讨论】:

  • 你能显示gcc -v的输出吗
  • 你有两个问题。您使用的 GCC 似乎不理解 windows 目标文件,其次,即使链接到可执行文件,您编写的代码也是针对 32 位代码的。 64 位 Windows 调用约定与 32 位不同。
  • @MichaelPetch 我添加了它
  • 这看起来像一个 32 位 MinGW 编译器。如果使用nasm helloworld.asm -f win32 -o helloworld.objgcc helloworld.obj -m32 -o helloworld.exe 生成32 位可执行文件会发生什么?对于 64 位代码,您需要 MinGW-w64。您的 GCC 版本也很老,可以追溯到 2000 年代中期。
  • 它工作在 32 位,因为它是一个 32 位编译器。推荐下载新版MinGW-w64(-w64可以编译32位和64位代码)。您必须使用 Microsoft 64 位调用约定重写汇编代码(第一个参数数量通过寄存器传递,您需要在 16 字节边界上对齐的 32 字节影子空间)。 MS 文档中讨论了 Windows 的 64 位调用约定:docs.microsoft.com/en-us/cpp/build/…

标签: gcc assembly mingw x86-64 nasm


【解决方案1】:

从您的 gcc -v 输出看来,您正在使用 mingw-32。

你需要得到mingw-w64

此外,Windows 的 64 位代码中的函数看起来完全不同。重写你的代码如下:

; ----------------------------------------------------------------------------------------
; This is a Win64 console program that writes "Hello" on one line and then exits.  It
; uses puts from the C library.  To assemble and run:
;
;     nasm -fwin64 hello.asm && gcc hello.obj && a
; ----------------------------------------------------------------------------------------

        global  main
        extern  puts
        section .text
main:
        sub     rsp, 28h                        ; Reserve the shadow space and align stack
        mov     rcx, message                    ; First argument is address of message
        call    puts                            ; puts(message)
        add     rsp, 28h                        ; Remove shadow space
        ret
message:
        db      'Hello', 0                      ; C strings need a zero byte at the end

this page底部讨论

【讨论】:

  • 我是您的支持者,但此代码存在问题。在调用puts 之前,RSP 不是 16 字节对齐的。当main 开始运行时,堆栈未对齐8(因为调用指令的返回地址在堆栈上)。您可以考虑减去 28h 来考虑阴影空间和对齐方式。额外的 8 会将影子空间放回 16 字节边界。来自 ABI:在不属于 Epilog 或 prolog 的任何代码区域中,堆栈指针必须与 16 字节对齐,叶函数除外。
  • 谢谢,我稍后再查。另一个问题:有没有办法通过汇编而不是调用外部函数来打印字符串?
  • @Omer :Windows 中的替代方法是调用 WinAPI 直接输出。您必须使用类似 Windows Console API 的东西。与 Linux/BSD/MacOS 等不同,WInAPI 是围绕系统调用(可能会因版本而异)的包装器。
  • 谢谢@MichaelPetch - 两年前,这段代码经过 20 字节调整,纯属运气。更新到 28。
  • 这对我不起作用!!我有 nasm 版本 2.14.02 和 gcc 版本 8.1.0 请帮助
猜你喜欢
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
相关资源
最近更新 更多