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?