如何在Windows静态库中标识导出的函数?

And*_*rew 5 c++ windows linker

我想看看静态库中的哪些函数(如果链接到dll中)将被导出。我该怎么做呢?

 int foo(int i)
 { return i + 1; }

 __declspec(dllexport) int bar(int i)
 { return i + 1; }
Run Code Online (Sandbox Code Playgroud)

dumpbin /symbols mylib.lib 这两个函数产生相同的信息。

00A 00000000 SECT4  notype ()    External     | ?foo@@YAHH@Z (int__cdecl foo(int))
00B 00000020 SECT4  notype ()    External     | ?bar@@YAHH@Z (int __cdecl bar(int))
Run Code Online (Sandbox Code Playgroud)

我怎么知道bar()将被导出但foo()不会被导出?

Mik*_*han 5

Q1)

如何在Windows静态库中标识导出的函数?

这是一个问题,并且:

Q2)

我想看看静态库中的哪些函数(如果链接到dll中)将被导出。我该怎么做呢?

是一个不同的问题。

Q2

首先考虑问题2:如果对静态库进行了任何检查,就无法确定静态库中定义的全局符号(包括DLL导出)将链接到任意DLL中。展示:

foo.c

__declspec(dllexport) int foo(int i) { return i + 1; }
Run Code Online (Sandbox Code Playgroud)

bar.c

__declspec(dllexport) in bar(int i) { return i + 1; }
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

编译所有这些源文件:

>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...
Run Code Online (Sandbox Code Playgroud)

现在制作一个包含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.
Run Code Online (Sandbox Code Playgroud)

接下来,将DLL与输入foomain.obj和链接foobar.lib

>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
Run Code Online (Sandbox Code Playgroud)

最后,将另一个DLL与输入链接barmain.obj,然后再次,foobar.lib

>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
Run Code Online (Sandbox Code Playgroud)

这两个函数foo和都bar定义在foobar.libdllexport。让我们看看什么符号被导出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
Run Code Online (Sandbox Code Playgroud)

只是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
Run Code Online (Sandbox Code Playgroud)

只是bar,不是foo

无论是foobar,或两者,或两者都不是,将从链接foobar.lib到一个可执行文件或DLL取决于什么对没有在静态库的目标文件也都在联系。

静态库foobar.lib是一个简单的档案(在Unix的ar档案格式对象文件(的)foo.obar.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
Run Code Online (Sandbox Code Playgroud)

完全相同

>link /out:foo.dll /dll foomain.obj foo.obj
Run Code Online (Sandbox Code Playgroud)

同样,链接:

>link /out:bar.dll /dll barmain.obj foobar.lib
Run Code Online (Sandbox Code Playgroud)

与以下内容完全相同:

>link /out:bar.dll /dll barmain.obj bar.obj
Run Code Online (Sandbox Code Playgroud)

静态库除了从链接库中挑选出的目标文件外,对链接没有任何贡献,而挑选出的对象文件(如果有)取决于链接中的其他目标文件。因此,您可以看到Q2等于:

如果我有一些定义了符号的对象文件,有些则声明了dllexport,而有些则没有,如果链接到这些对象文件中的0个或更多,我怎么知道哪个符号将从DLL中导出?

一段绳子有多长?您需要获得一些实际DLL的实际链接,才能确定其DLL导出将是什么。

回到第一季

同样,Q1等于:

如何识别Windows对象文件中的导出函数?

一定是可能的,因为链接程序可以做到。

我们foo.dll通过运行检查了DLL的导出:

>dumpbin /exports foo.dll
Run Code Online (Sandbox Code Playgroud)

并报告foodumpbin /exports FILE这是我们通常询问FILEDLL或程序的DLL导出的方式。它向我们显示的动态符号表中的符号FILE

dumpbin知道静态库只是一袋目标文件。所以

>dumpbin /symbols foobar.lib
Run Code Online (Sandbox Code Playgroud)

向我们显示了两个相同的符号表:

>dumpbin /symbols foo.obj bar.obj
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

顺便说一句:

>dumpbin /exports foobar.lib
Run Code Online (Sandbox Code Playgroud)

报告相同的DLL导出-即 -如下:

>dumpbin /exports foo.obj bar.obj
Run Code Online (Sandbox Code Playgroud)

并且它必须为空,因为目标文件没有动态符号表。

动态符号表由链接器生成。因此,只有链接程序生成的文件才能拥有一个。这意味着DLL或可执行文件。不是目标文件,它是由编译器生成并由链接器使用的。

链接器在DLL或可执行文件的动态符号表中记录实际链接dllexport的目标文件中限定的全局符号。因此,导出是因为符合链接到的存档成员中的条件。它不导出 ,尽管也合格, 因为该对象文件链接到foo.dllfoofoodllexportfoobar.lib(foo.obj) foo.dllbarbardllexportfoobar.lib(bar.obj)foo.dll

因此,链接器会检测foo合格dllexportfoo.obj并在此基础上将其添加foo到的动态符号表中foo.dll

该限定条件采用链接器指令的简单形式,编译器嵌入该foo.obj指令以指示链接器导出foo用于动态链接的符号。编译器发出链接器指令,因为源代码声明foo__declspec(dllexport)。如果链接器foo.obj通过添加foo到动态符号表中,则链接器将遵循该指令 。您可以完全foo.dll 不使用__declspec(dllexport)源代码来构建它们,而可以在链接/export:foo器命令行中自己给链接器标记。

因此,可以通过要求向您展示编译器已在其中写入的链接器指令来检测的dllexport资格:foodumpbinfoo.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
Run Code Online (Sandbox Code Playgroud)

并且类似地:

>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
Run Code Online (Sandbox Code Playgroud)

所以:

>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
Run Code Online (Sandbox Code Playgroud)

报告与以下两项相同的出口:

>dumpbin /directives foo.obj bar.obj
Run Code Online (Sandbox Code Playgroud)

那就是对第一季度的答案。