Windows ld MinGW到标准C库的链接

Windows ld MinGW到标准C库的链接,windows,assembly,x86,mingw,nasm,Windows,Assembly,X86,Mingw,Nasm,我有以下代码的问题 extern printf global _main main: push msg call printf ret msg db "Hello world",0 我使用NASM-fwin32 test.asm将其与NASM组装在一起,然后使用ld test.obj将其链接起来。 它告诉我“test.obj:test.asm:(text+0x6):对“printf”的未定义引用” 如何将我的文件链接到标准C库?我有最新MinGW的ld。使用编译器前端链接: cc test.o

我有以下代码的问题

extern printf
global _main
main:
push msg
call printf
ret
msg db "Hello world",0
我使用
NASM-fwin32 test.asm将其与NASM组装在一起,然后使用
ld test.obj
将其链接起来。 它告诉我“
test.obj:test.asm:(text+0x6):对“printf”的未定义引用


如何将我的文件链接到标准C库?我有最新MinGW的ld。

使用编译器前端链接:

cc test.obj
如果您确实想直接使用
ld
(您不应该这样做),请使用
-v
标志来
cc
来确定您需要什么完整的命令行。例如,在我的机器上,它是:

ld -demangle -dynamic -arch x86_64 -macosx_version_min 10.8.0 \
  -o a.out test.obj -lSystem                                  \
  /usr/bin/../lib/clang/4.2/lib/darwin/libclang_rt.osx.a
如果我使用GCC而不是Clang,那就更疯狂了:

ld -dynamic -arch x86_64 -macosx_version_min 10.8.4 -weak_reference_mismatches                             \
  non-weak -o a.out -lcrt1.10.6.o                                                                          \
  -L/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1/x86_64                                      \
  -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64   \
  -L/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1                                             \
  -L/usr/llvm-gcc-4.2/bin/../lib/gcc                                                                       \
  -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1          \
  -L/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1/../../..                                    \
  -L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/../../.. \
  test.obj -lgcc -lSystem

我发现你的代码有几个问题。首先,在
global\u main
上有下划线,但在
main:
上没有下划线。这些应该匹配。你可以在整个过程中使用下划线,或者-我会做的-根本不用。。。对于Windows,组装为
nasm-f win32--prefix\utest.asm
。这将使它具有“可移植性”,因为对于Linux,它将进行汇编,而不使用
--前缀
而不使用下划线。Linux在
global
extern
符号上不使用下划线。如果您使用的是OpenWatcom C,那么您可以使用
--postfix.
。是的,OpenWatcom使用尾随下划线。是的,我知道他们告诉我们C是标准化的。但一旦你被蒙在鼓里,这就不是真的了

另一个大问题是,在调用
\u printf
之后,您需要
添加esp,4
(或
弹出
一个伪寄存器)以“清理堆栈”。如果您使用的是Windows API,则它们使用STDCALL调用约定,其中“被调用方清理”,因此您不想这样做。混合使用C调用(CDECL调用约定)和Windows API可能会让人感到困惑,但应该可以工作

我认为Carl使用gcc链接它的想法是正确的。没有什么需要“编译”,但是gcc知道ld的正确命令行
gcc-o test.exe test.obj
可能就足够了(如果最新的MinGW希望执行64位代码,那么可以添加
-m32
)。这将链接一些调用
\u main
的“启动代码”。这将略微增加可执行文件的大小,并且您“可能”可以在没有它的情况下继续工作,但只做它更容易

在Linux中,我们可以直接使用ld(命令行很可怕),但是ld正在寻找
\u start
,而不是
main
,作为入口点。我们可以告诉ld
-e main
,但是这个入口点不叫(!),也没有办法从中
ret
!Windows中的情况可能不同。您至少需要
-lc
告诉ld我们需要这些C库。最简单的方法是“让gcc来做”——它不会触及你的.asm代码(但会链接到“启动代码”)。世界你好

要汇编代码:

nasm -fwin32 test.asm
Microsoft将使用带有下划线的cdecl调用约定为函数添加前缀。
要与C调用约定相匹配,printf
应该是
\u printf

这同样适用于
\u main
而不是
main

并链接到:

ld test.obj-lmsvcrt-entry=\u main-subsystem=console-o test.exe

此处
-entry
命令行选项用于调用ld来指定程序的入口点。
然后使用
-l
选项将
msvcrt
库传递给ld链接器,否则您将收到错误消息,(未定义对“printf”的引用),这意味着链接器在NASM生成的指定对象文件中未找到符号printf

以下是完整的资料来源:

global  _main
extern  _printf
section .text
_main:
push msg
call _printf
add esp, 4 ;adjust the stack
ret
msg db "Hello world",0
在的最新版本中,
libmsvcrt.a
存在于
\MinGW\lib
目录中,并且ld成功链接了目标文件。您可以尝试使用
-L
开关来指定位置:
ld test.obj-L“c:\mingw\bin\../../mingw/lib/”-lmsvcrt-entry=\u main-o test.exe
,其中
-L
之后的路径是指向您的mingw安装目录的路径。您还可以查看和3。msvcrt与crtdll?