我遇到以下代码问题。
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): undefined reference to 'printf'
”
如何将我的文件链接到标准C库?我来自最新的MinGW。
答案 0 :(得分:4)
汇编代码:
nasm -fwin32 test.asm
Microsoft将使用带有下划线的cdecl调用约定为函数添加前缀
要与C调用约定printf
匹配,应为_printf
这同样适用于_main
而非main
。
并链接:
ld test.obj -lmsvcrt -entry = _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
答案 1 :(得分:1)
我可以看到您的代码有几个问题。首先,您在global _main
上有一个下划线,但在main:
上没有。这些应该匹配。您可以在整个过程中使用下划线,或者 - 我会做什么 - 根本不使用...而对于Windows,汇编为nasm -f win32 --prefix _ test.asm
。这将使其“可移植”,对于Linux来说,它会组装,没有--prefix _
没有下划线。 Linux不会在global
或extern
符号上使用下划线。如果您有可能使用OpenWatcom C,则可以使用--postfix _
。是的,OpenWatcom使用尾随下划线。是的,我知道他们告诉我们C是标准化的。但是一旦你陷入困境,这就不是真的了。
另一个大问题是,在调用_printf
之后,您需要add esp, 4
(或pop
虚拟寄存器)来“清理堆栈”。如果您使用的是Windows API,它们会使用“callee清理”的STDCALL调用约定,因此您不希望这样做。混合C调用(CDECL调用约定)和Windows API可能会让人感到困惑,但应该可以正常工作。
我认为卡尔有正确的想法使用gcc链接它。没有什么可以“编译”,但是gcc知道ld的正确命令行。 gcc -o test.exe test.obj
可能就足够了(如果最新的MinGW希望使用64位代码,可能会添加-m32
)。这将链接一些调用_main
的“启动代码”。这会稍微增加你的可执行文件的大小,你可能“没有它”就可以相处,但是这样做更容易。
在Linux中,我们可以直接使用ld(命令行是可怕的),但是ld正在寻找_start
而不是main
作为入口点。我们可以告诉ld -e main
,但是这个入口点没有被调用(!),并且没有办法从它ret
开始! Windows中的情况可能有所不同。你需要 - 至少 - -lc
告诉ld我们想要那些C库。最容易“让gcc这样做” - 它不会触及您的.asm代码(但会链接到“启动代码”)。快乐的Hello World! :)
答案 2 :(得分:0)
使用编译器前端链接:
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