3

我对以下代码有疑问。

extern printf
global _main
main:
push msg
call printf
ret
msg db "Hello world",0

我使用 NASM 组装它,nasm -fwin32 test.asm然后我使用ld test.obj. 它告诉我“ test.obj:test.asm:(text+0x6): undefined reference to 'printf'

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

4

3 回答 3

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来指定 program 的入口点。
然后使用-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
于 2013-09-14T20:43:31.860 回答
1

我可以看到您的代码有几个问题。首先,你有一个下划线 onglobal _main但不是 on main:。这些应该匹配。您可以在整个过程中使用下划线,或者 - 我会做的 - 根本不......对于 Windows,组装为nasm -f win32 --prefix _ test.asm. 这将使其“可移植”,因为对于 Linux,它可以在--prefix _没有下划线的情况下进行组装。Linux 不使用下划线globalextern符号。如果您有机会使用 OpenWatcom C,您可以使用--postfix _. 是的,OpenWatcom 使用尾随下划线。是的,我知道他们告诉我们 C 是标准化的。但是一旦你深入了解,这并不是真的。

另一个大问题是,在调用之后_printf,您需要add esp, 4(或pop一个虚拟寄存器)来“清理堆栈”。如果您使用的是 Windows API,它们使用“被调用者清理”的 STDCALL 调用约定,因此您不想这样做。混合 C 调用(CDECL 调用约定)和 Windows API 可能会令人困惑,但应该可以。

我认为 Carl 使用 gcc 链接它的想法是正确的。没有什么可以“编译”的,但 gcc 知道 ld 的正确命令行。gcc -o test.exe test.obj可能就足够了(-m32如果最新的 MinGW 期望使用 64 位代码,可能会添加)。这将链接到一些调用_main. 这将略微增加可执行文件的大小,并且您“可能”没有它也可以相处,但这样做更容易。

在 Linux 中,我们可以直接使用 ld (命令行很可怕),但 ld 正在寻找_start,而不是main,作为入口点。我们可以告诉 ld -e main,但是这个入口点没有被调用(!)并且没有可能的方法ret!Windows 中的情况可能有所不同。您至少-lc需要告诉 ld 我们想要那些 C 库。最容易“让 gcc 去做”——它不会触及你的 .asm 代码(但会链接到那个“启动代码”)。快乐你好世界!:)

于 2013-09-14T19:36:59.147 回答
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
于 2013-09-14T18:24:52.187 回答