Q1)
如何识别 Windows 静态库中的导出函数?
这是一个问题,并且:
Q2)
我想看看静态库中的哪些函数在链接到 dll 时会被导出。我该怎么做?
是一个不同的问题。
第二季度
首先考虑 Q2:通过对静态库的任何检查,您无法分辨出哪些全局符号
如果该静态库是在其中定义的(包括 DLL 导出)将链接到任意 DLL
输入到它的链接。演示:
foo.c
__declspec(dllexport) int foo(int i) { return i + 1; }
bar.c
__declspec(dllexport) in bar(int i) { return i + 1; }
foomain.c
#include <windows.h>
__declspec(dllexport) int foo(int i);
BOOLEAN WINAPI DllMain( IN HINSTANCE hDllHandle,
IN DWORD nReason,
IN LPVOID Reserved )
{
return foo(1) == 2;
}
barmain.c
#include <windows.h>
__declspec(dllexport) int bar(int i);
BOOLEAN WINAPI DllMain( IN HINSTANCE hDllHandle,
IN DWORD nReason,
IN LPVOID Reserved )
{
return bar(1) == 2;
}
编译所有这些源文件:
>cl /c foo.c bar.c foomain.c barmain.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
foo.c
bar.c
foomain.c
barmain.c
Generating Code...
现在制作一个包含foo.obj 和bar.obj 的静态库:
>lib /out:foobar.lib foo.obj bar.obj
Microsoft (R) Library Manager Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
接下来,用输入 foomain.obj 和 foobar.lib 链接一个 DLL:
>link /out:foo.dll /dll foomain.obj foobar.lib
Microsoft (R) Incremental Linker Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Creating library foo.lib and object foo.exp
最后,用输入 barmain.obj 和 foobar.lib 链接另一个 DLL
>link /out:bar.dll /dll barmain.obj foobar.lib
Microsoft (R) Incremental Linker Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Creating library bar.lib and object bar.exp
在foobar.lib 中定义的两个函数foo 和bar 均已声明
dllexport。看看foo.dll导出了哪些符号:
>dumpbin /exports foo.dll
Microsoft (R) COFF/PE Dumper Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file foo.dll
File Type: DLL
Section contains the following exports for foo.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00001030 foo
Summary
2000 .data
6000 .rdata
1000 .reloc
B000 .text
只是foo,而不是bar。
bar.dll 的出口是什么?
>dumpbin /exports bar.dll
Microsoft (R) COFF/PE Dumper Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file bar.dll
File Type: DLL
Section contains the following exports for bar.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00001030 bar
Summary
2000 .data
6000 .rdata
1000 .reloc
B000 .text
只是bar,而不是foo。
foo 或 bar,或两者,或两者都不会,将从 foobar.lib 链接到
可执行文件或 DLL 取决于 不在静态库中的目标文件
在链接中。
静态库 foobar.lib 只是一个存档(在 Unix 中 ar archive format)
您可以提供给链接器的目标文件(foo.o、bar.o)
选择它需要的那些,如果有的话,以进行可执行文件或 DLL 的链接。链接器
从存档中仅提取那些目标文件并将它们输入到链接中,确切地说
好像您在链接器命令行中单独命名了它们并且没有提到静态
图书馆。
链接器需要从静态库中提取的目标文件是那些
为从其他对象文件中产生的未解析引用提供定义
必须链接。
所以foo.dll 的链接是这样进行的:
foomain.obj 已链接,因为在命令行中命名的目标文件是无条件链接的。
foomain.obj 的链接导致对foo 的未解析引用。
所以在foobar.lib 中搜索定义foo 的目标文件。
发现归档成员foobar.lib(foo.obj)提供了foo的定义,因此将其提取并链接到foo.dll。
另一个存档成员 foobar.lib(bar.obj) 没有为任何未解析的引用提供定义,因此它不会被提取或链接。
联动:
>link /out:foo.dll /dll foomain.obj foobar.lib
完全一样:
>link /out:foo.dll /dll foomain.obj foo.obj
同样,链接:
>link /out:bar.dll /dll barmain.obj foobar.lib
完全一样:
>link /out:bar.dll /dll barmain.obj bar.obj
除了对象文件之外,静态库对链接没有任何贡献
从中挑选出来的,而被挑选出来的,如果有的话,取决于
链接中的其他目标文件。从这个角度来看,您可以看到 Q2 相当于:
如果我有一些目标文件,其中定义了符号,一些声明了 dllexport,而另一些则没有,我怎么知道哪些符号将从 DLL 中导出,因为其中有 0 个或更多目标文件是否链接到其中?
一根绳子有多长?您需要获得某些实际 DLL 的实际链接,才能确定其 DLL 导出将是什么。
回到第一季度
同样,Q1 相当于:
如何识别 Windows 对象文件中的导出函数?
这必须是可能的,因为链接器做到了。
我们通过运行检查了foo.dll 的 DLL 导出:
>dumpbin /exports foo.dll
它报告了foo。 dumpbin /exports FILE 是我们通常询问的方式
FILE 的 DLL 导出,它是一个 DLL 或程序。它向我们展示了
FILE的动态符号表。
dumpbin 知道静态库只是一袋目标文件。所以
>dumpbin /symbols foobar.lib
向我们展示了相同的两个符号表:
>dumpbin /symbols foo.obj bar.obj
即
COFF SYMBOL TABLE
000 010463CB ABS notype Static | @comp.id
001 80000191 ABS notype Static | @feat.00
002 00000000 SECT1 notype Static | .drectve
Section length 3C, #relocs 0, #linenums 0, checksum 67EAC832
004 00000000 SECT2 notype Static | .debug$S
Section length 6C, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT3 notype Static | .text$mn
Section length B, #relocs 0, #linenums 0, checksum B38E4E30
008 00000000 SECT3 notype () External | _bar
String Table Size = 0x0 bytes
COFF SYMBOL TABLE
000 010463CB ABS notype Static | @comp.id
001 80000191 ABS notype Static | @feat.00
002 00000000 SECT1 notype Static | .drectve
Section length 3C, #relocs 0, #linenums 0, checksum 1D7A1E73
004 00000000 SECT2 notype Static | .debug$S
Section length 6C, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT3 notype Static | .text$mn
Section length B, #relocs 0, #linenums 0, checksum B38E4E30
008 00000000 SECT3 notype () External | _foo
String Table Size = 0x0 bytes
同理:
>dumpbin /exports foobar.lib
报告相同的 DLL 导出 - 即 none - 如下:
>dumpbin /exports foo.obj bar.obj
而且它必须是none,因为目标文件没有动态符号表。
链接器生成动态符号表。所以只有文件由
链接器可以拥有一个。这意味着 DLL 或可执行文件。不是目标文件,它是
由编译器生成并由链接器使用。
链接器记录在 DLL 或可执行文件的动态符号表中
在实际链接的目标文件中中限定为dllexport 的全局符号。
因此,foo.dll 导出 foo 因为 foo 在存档中被限定为 dllexport
成员 foobar.lib(foo.obj) 已链接 到 foo.dll。它不出口
bar,虽然bar 在foobar.lib(bar.obj) 中也是合格的dllexport
因为那个目标文件没有链接到foo.dll
所以链接器检测到 foo 在foo.obj 中被限定为dllexport 并且
在此基础上将foo添加到foo.dll的动态符号表中。
该限定采用编译器嵌入的链接器指令的简单形式
在foo.obj 中指示链接器导出符号foo 以进行动态链接。
编译器发出该链接器指令,因为源代码声明了foo
与__declspec(dllexport)。并且链接器将遵守该指令,如果它链接
foo.obj,通过将foo 添加到动态符号表中。您可以构建相同的foo.dll
在源代码中根本不使用__declspec(dllexport),而是给出
链接器标志/export:foo你自己在链接器命令行中。
您因此可以通过要求 dumpbin 显示来检测 foo 的 dllexport 限定
编译器在foo.obj 中写入的链接器指令:
>dumpbin /directives foo.obj
Microsoft (R) COFF/PE Dumper Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file foo.obj
File Type: COFF OBJECT
Linker Directives
-----------------
/DEFAULTLIB:LIBCMT
/DEFAULTLIB:OLDNAMES
/EXPORT:_foo <-- This
Summary
6C .debug$S
3C .drectve
B .text$mn
同样:
>dumpbin /directives bar.obj
Microsoft (R) COFF/PE Dumper Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file bar.obj
File Type: COFF OBJECT
Linker Directives
-----------------
/DEFAULTLIB:LIBCMT
/DEFAULTLIB:OLDNAMES
/EXPORT:_bar <-- And this
Summary
6C .debug$S
3C .drectve
B .text$mn
所以:
>dumpbin /directives foobar.lib
Microsoft (R) COFF/PE Dumper Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file foobar.lib
File Type: LIBRARY
Linker Directives
-----------------
/DEFAULTLIB:LIBCMT
/DEFAULTLIB:OLDNAMES
/EXPORT:_bar
Linker Directives
-----------------
/DEFAULTLIB:LIBCMT
/DEFAULTLIB:OLDNAMES
/EXPORT:_foo
Summary
D8 .debug$S
78 .drectve
16 .text$mn
报告与以下相同的两个导出:
>dumpbin /directives foo.obj bar.obj
这就是 Q1 的答案。