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

时间:2018-06-21 23:10:21

标签: c++ windows linker

我想看看静态库中的哪些函数(如果链接到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()不会?

1 个答案:

答案 0 :(得分:3)

Q1)

  

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

这是一个问题,并且:

第二季度)

  

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

是另一个问题。

第二季度

首先考虑第二季度:通过对静态库的任何检查,您都无法分辨出哪些全局符号 如果其中定义的静态库(包括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.

接下来,将DLL与输入foomain.objfoobar.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

最后,将另一个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

声明在foo中定义的两个函数barfoobar.lib 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链接到barfoobar.lib,还是两者,或者都不链接 可执行文件或DLL取决于静态库中的哪些目标文件 在链接中。

静态库foobar.lib只是一个存档(在Unix ar archive format中) 可以提供给链接器的目标文件(foo.obar.o)的数量 选择进行可执行文件或DLL链接所需的文件(如果有)。链接器 从存档中仅提取那些目标文件,并将其准确地输入到链接中 就像您在链接器命令行中单独命名它们一样,而没有提及静态 图书馆。

链接器需要从静态库中提取的目标文件是那些 为 other 对象文件中产生的未解析引用提供定义 必须链接。

因此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,而有些则没有,如果给定0或更大的值,我该如何判断将从DLL中导出哪些符号那些目标文件被链接到其中了?

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

返回第一季度

同样,Q1等于:

如何识别Windows目标文件中的导出函数?

必须是可能的,因为链接程序可以做到。

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

>dumpbin /exports foo.dll

,它报告了foodumpbin /exports FILE是我们通常会询问的方式 DLL导出的FILE是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

Likwise:

>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,尽管bardllexport中也被限定为foobar.lib(bar.obj) 因为该目标文件 not 未链接到foo.dll

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

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

因此可以通过要求dllexport进行展示来检测foo的{​​{1}}资格 您是编译器在dumpbin中标出的链接器指令:

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

这就是对Q1的答案。