Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you identify exported functions in a Windows static library?

I'd like to see which functions in a static library will be exported if linked into a dll. How do I do this?

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

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

dumpbin /symbols mylib.lib yields the same information for both functions.

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

How can I know that bar() will be exported but foo() will not?

like image 253
Andrew Avatar asked Jun 21 '18 23:06

Andrew


1 Answers

Q1)

How do you identify exported functions in a Windows static library?

That is one question, and:

Q2)

I'd like to see which functions in a static library will be exported if linked into a dll. How do I do this?

is a different question.

Q2

Taking Q2 first: You cannot tell, by any inspection of a static library, which global symbols defined in it (including DLL exports) will be linked into an arbitrary DLL if that static library is input to its linkage. To demonstrate:

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;
}

Compile all those source files:

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

Now make a static library containing foo.obj and 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.

Next, link a DLL with inputs foomain.obj and 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

Lastly, link another DLL with inputs barmain.obj and, again, 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

Both of the functions, foo and bar, defined within foobar.lib, are declared dllexport. Let's see what symbols are exported by 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

Just foo, not bar.

And what are the exports of 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

Just bar, not foo.

Whether foo or bar, or both, or neither, will be linked from foobar.lib into an executable or DLL depends on what object files not within static libraries are also in the linkage.

The static library foobar.lib is simply an archive (in Unix ar archive format) of object files (foo.o, bar.o) that you can offer to the linker from which to select the ones it needs, if any, to carry on the linkage of an executable or DLL. The linker extracts just those object files from the archive and inputs them to the linkage, exactly as if you had named them individually in the linker commandline and not mentioned the static library at all.

The object files that the linker will need to extract from a static library are those that provide definitions for unresolved references that accrue from other object files that must be linked.

So the linkage of foo.dll proceeds like this:

  • foomain.obj is linked because an object file named in the commandline is linked unconditionally.

  • The linkage of foomain.obj gives rises to an unresolved reference to foo.

  • So foobar.lib is searched for an object file that defines foo.

  • The archive member foobar.lib(foo.obj) is found to provide a definition of foo, so it is extracted and linked into foo.dll.

  • The other archive member foobar.lib(bar.obj) provides no definitions for any unresolved references, so it is not extracted or linked.

The linkage:

>link /out:foo.dll /dll foomain.obj foobar.lib

is exactly the same as:

>link /out:foo.dll /dll foomain.obj foo.obj

And likewise, the linkage:

>link /out:bar.dll /dll barmain.obj foobar.lib

is exactly the same as:

>link /out:bar.dll /dll barmain.obj bar.obj

A static library contributes nothing to a linkage except the object files that are picked out of it, and the ones that are picked out, if any, depend on the other object files in the linkage. In this light you can see that Q2 amounts to:

If I have some object files in which are are defined symbols some declared dllexport, and some not, how can I tell which of the symbols will be exported from a DLL, given that 0 or more of those object files are linked into it?

How long is a piece of string? You need to be given the actual linkage of some actual DLL to be able to determine what its DLL exports will be.

Back to Q1

In the same light, Q1 amounts to:

How do you identify exported functions in a Windows object file?

That must be possible, because the linker does it.

We inspected the DLL exports of foo.dll by running:

>dumpbin /exports foo.dll

and it reported foo. dumpbin /exports FILE is the way we'd usually interrogate the DLL exports of a FILE that is a DLL or program. It shows us the symbols in the dynamic symbol table of FILE.

dumpbin knows that a static libary is just a bag of object files. So

>dumpbin /symbols foobar.lib

shows us the same two symbol tables as:

>dumpbin /symbols foo.obj bar.obj

i.e.

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

reports the same DLL exports - namely none - as:

>dumpbin /exports foo.obj bar.obj

And it must be none because an object file has no dynamic symbol table.

A dynamic symbol table is generated by the linker. So only files produced by the linker can possess one. That means a DLL or executable. Not an object file, which is produced by the compiler and consumed by the linker.

The linker records in the dynamic symbol table of a DLL or executable the global symbols that are qualified dllexport in the object files that were actually linked. Thus, foo.dll exports foo because foo is qualfied as dllexport in the archive member foobar.lib(foo.obj) which was linked into foo.dll. It does not export bar, although bar is also qualified dllexport in foobar.lib(bar.obj) because that object file was not linked into foo.dll

So the linker detects that foo is qualified as dllexport in foo.obj and on that basis adds foo to the dynamic symbol table of foo.dll.

That qualification takes the simple form of a linker directive that the compiler embeds in foo.obj instructing the linker to export the symbol foo for dynamic linkage. The compiler emits that linker directive because the source code declares foo with __declspec(dllexport). And the linker will obey that directive, if it links foo.obj, by adding foo to the dynamic symbol table. You could build the same foo.dll without using __declspec(dllexport) at all in the source code and instead giving the linker flag /export:foo yourself in the linker commandline.

You can therefore detect the dllexport qualification of foo by asking dumpbin to show you the linker directives that the compiler has inscribed in 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

And similarly:

>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

So:

>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

reports the same two exports as:

>dumpbin /directives foo.obj bar.obj

and that is the answer to Q1.

like image 61
Mike Kinghan Avatar answered Oct 02 '22 14:10

Mike Kinghan