【问题标题】:How do you identify exported functions in a Windows static library?如何识别 Windows 静态库中的导出函数?
【发布时间】:2018-12-01 09:08:44
【问题描述】:

我想看看静态库中的哪些函数在链接到 dll 时会被导出。我该怎么做?

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

 __declspec(dllexport) int bar(int i)
 { return i + 1; }

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))

我怎么知道bar() 会被导出,而foo() 不会?

【问题讨论】:

    标签: c++ windows linker


    【解决方案1】:

    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.objbar.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.objfoobar.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.objfoobar.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 中定义的两个函数foobar 均已声明 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

    foobar,或两者,或两者都不会,将从 foobar.lib 链接到 可执行文件或 DLL 取决于 不在静态库中的目标文件 在链接中。

    静态库 foobar.lib 只是一个存档(在 Unix 中 ar archive format) 您可以提供给链接器的目标文件(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
    

    完全一样

    >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
    

    它报告了foodumpbin /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,虽然barfoobar.lib(bar.obj) 中也是合格的dllexport 因为那个目标文件没有链接到foo.dll

    所以链接器检测到 foofoo.obj 中被限定为dllexport 并且 在此基础上将foo添加到foo.dll的动态符号表中。

    该限定采用编译器嵌入的链接器指令的简单形式 在foo.obj 中指示链接器导出符号foo 以进行动态链接。 编译器发出该链接器指令,因为源代码声明了foo__declspec(dllexport)。并且链接器将遵守该指令,如果它链接 foo.obj,通过将foo 添加到动态符号表中。您可以构建相同的foo.dll 在源代码中根本不使用__declspec(dllexport),而是给出 链接器标志/export:foo你自己在链接器命令行中。

    因此可以通过要求 dumpbin 显示来检测 foodllexport 限定 编译器在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 的答案。

    【讨论】:

    • 也许“dumpbin /directives foobar.lib”就足够了?不过谢谢。
    猜你喜欢
    • 2010-11-04
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    • 2012-05-14
    相关资源
    最近更新 更多