我知道使用GCC时,标准I/O函数(例如
printf
、fprintf
等)是在静态库libc.a
中定义的。但是,我需要知道它们在 MinGW 环境中的何处定义,该环境没有 libc.a
。在我的 MinGW 安装中,我确实找到了以下库:libcap.a
、libcfgmgr32.a
、libcoldname.a
、libcomctl32.a
、libcomdlg32.a
、libcrtdll.a
、libcrypt32.a
和libctl3d32.a
。然而,我对这些是否与我想要的相关一无所知。
本质上,我需要知道标准C I/O函数在MinGW环境中定义在哪里。
作为更新,这些是默认情况下的所有 MinGW 链接库:
libmingw32.a
、libmoldname.a
、libmingwex.a
、libmsvcrt.a
、libadvapi32.a
、libshell32.a
和 libuser32.a
。我想它可能是(或以某种方式连接到)其中之一?
这比您希望的更复杂,因为在 MinGW 环境中可以通过多种不同的方式定义函数:
.a
)。.a
) 中的符号,在运行时从 DLL 导入具有相似名称的函数。该 DLL 可以是 Windows 的一部分,也可以是 MinGW 的一部分。所以我们假设
test.c
是一个基本的 C 语言 hello world 程序,它从 printf
调用 main
。
运行
gcc -S test.c
,然后运行 less test.s
以查看 GCC 为此代码生成的程序集。如果您的 MinGW 设置与我的一样(MSYS2 中的 MINGW64 环境),您将看到 test.s 实际上包含 printf
的代码。这告诉我们 printf
是在 MinGW 标头中的某处定义的。如果你仔细观察程序集,你会发现它基本上只是调用 __mingw_vfprintf
。
现在运行
gcc test.c -g -o test -Wl,-Map=test.map
和 less test.map
。搜索 __mingw_vfprintf
,找出它的来源。就我而言,它来自C:/msys64/mingw64/lib/libmingwex.a
。
您可以尝试运行
objdump -d /mingw64/lib/libmingwex.a
来查看 __mingw_vfprintf
的编译代码,但效果不太好:它似乎没有显示 __mingw_vfprintf
调用的三个函数的名称。幸运的是,GDB 可以向我们展示这一点。您已经使用之前的命令编译了 test.exe
,因此运行 gdb ./test.exe
来启动调试器,然后在其中运行以下命令:
break __mingw_vfprintf
run
layout asm
请注意,第一个命令打印出
__mingw_vfprintf
的源文件名称(在构建服务器上),这可能很有用。
最后的命令向我们展示了
__mingw_vfprintf
中的程序集,我们可以看到它调用了三个函数。它调用的最有趣的函数是__mingw_pformat
。
运行
break __mingw_pformat
和 continue
跳转到该函数。该函数中发生了很多事情。您可以使用调试器深入研究它或通过查看源代码来获取更多信息。它可能在某个时刻调用 msvcrt.dll
或其他一些 Windows DLL 中的函数。
解决此问题的另一种方法是查看运行时从 DLL 导入哪些函数。为此,请运行
objdump -p test.exe | less
并查找“导入表”。如果您的环境与我的一样,您将看到 fprintf
和 vfprintf
以及其他几个 C I/O 函数在运行时从 msvcrt.dll
(Windows 的一部分)导入。这是一个非常重要的 DLL,它是传统 MinGW 环境的基础,但是您可以通过多种方式配置 MinGW,让其使用不同的基础(即较新版本的 DLL 或 UCRT)。
我编译了一个使用
printf
函数并使用 MinGW-w64 链接器(ld.exe)的目标文件(.o),我测试发现以下命令能够执行成功的链接以生成.exe文件:
ld.exe my_prog.o -o my_prog.exe -L"%path_to_MinGW%\x86_64-w64-mingw32\lib" -lcrtdll
libcrtdll.a
进行链接)ld.exe my_prog.o -o my_prog.exe -L"%path_to_MinGW%\x86_64-w64-mingw32\lib" -lmsvcrt
libmsvcrt.a
进行链接)ld.exe my_prog.o -o my_prog.exe -L"C:\Windows\System32" -lmsvcrt
msvcrt.dll
进行链接)所有这些都成功生成了
my_prog.exe
应用程序。但是,对于使用开关 -lcrtdll
的情况,程序无法启动,并抛出错误:在我的系统上找不到 crtdll.dll
。
对于其他两个命令,应用程序启动并成功运行(显然,这两个命令在运行时使用的
msvcrt.dll
在我的系统上可用)。
我对
crtdll.dll
进行了快速搜索,发现该 DLL 主要在旧版 Windows 版本上用作 C 运行时库 (CRT),而现代 Windows 版本则使用 msvcrt.dll
作为 CRT图书馆。我没有对此进行广泛阅读,但任何感兴趣的人都可以查看:
https://mingw-users.narkive.com/SHwKXuDL/msvcrt-vs-crtdll
https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/cpp/libraries/use-c-run-time