Bug 12969 - ld silently generates bad DLL when there are more than 65536 exports
Summary: ld silently generates bad DLL when there are more than 65536 exports
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.22
: P2 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-07-07 12:22 UTC by batterseapower
Modified: 2017-03-06 12:25 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description batterseapower 2011-07-07 12:22:32 UTC
(This was previously an email message to binutils-bugs at http://lists.gnu.org/archive/html/bug-binutils/2011-07/msg00038.html, but I didn't get a reply)

Windows DLLs use 16-bit ordinals to name exports, but when ld is told
to export more than 65536 exports from a DLL it does not fail.
Instead, it generates a broken DLL which correctly exports the
alphabetically-first 65k exports but also contains bogus "junk"
exports for the remaining exports.

At the very least, ld should error out rather than silently generating
a bad DLL.

Proposed patch:

"""
--- ld-old/pe-dll.c     2011-07-04 15:16:56.050491400 +0100
+++ ld/pe-dll.c 2011-07-04 15:05:27.497120800 +0100
@@ -1095,6 +1095,12 @@
        pe_def_file->exports[i].ordinal = next_ordinal;
       }

+  if (max_ordinal > 65535 || next_ordinal > 65535) {
+    /* xgettext:c-format */
+    einfo(_("%XError, export ordinal too large: %d\n"),
+          max_ordinal > next_ordinal ? max_ordinal : next_ordinal);
+  }
+
   /* OK, now we can allocate some memory.  */
   edata_sz = (40                               /* directory */
              + 4 * export_table_size           /* addresses */
"""

(On reflection, I think this patch can be simplified because it max_ordinal should always be larger than next_ordinal)

Test case:

"""
$ cat generate.c
#include <stdio.h>

int main(int argc, char **argv) {
    FILE *file = fopen("too_big.c", "w");
    int i;

    for (i = 0; i < (1 << 16); i++) {
        fprintf(file, "__declspec(dllexport) int
export%05d(void);\nint export%05d(void) { return %d; }\n\n", i, i, i);
    }

    fclose(file);

    return 0;
}

$ gcc generate.c -o generate && ./generate
$ gcc -shared too_big.c -o too_big.dll
"""

Inspect the generated too_big.dll in e.g. Dependency Walker.
Dependency Walker shows two exports with the same ordinal (this a
result of integer overflow). This is wrong.
Comment 1 Alex 2017-03-02 20:08:57 UTC
Why has this patch not been accepted? I've been bitten by the issue a number of times.
Comment 2 Sourceware Commits 2017-03-03 11:36:21 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=611a3ca929d6529f4e7576b0e2ffb588839c1b21

commit 611a3ca929d6529f4e7576b0e2ffb588839c1b21
Author: Nick Clifton <nickc@redhat.com>
Date:   Fri Mar 3 11:35:03 2017 +0000

    Make the linker fail if asked to create more than 1^16 ordinal values for PE targets.
    
    	PR 12969
    	* pe-dll.c (generate_edata): Fail if the input file(s) require too
    	many ordinals.
Comment 3 Nick Clifton 2017-03-03 11:38:19 UTC
Hi Alex, Hi Max,

  Sorry about this.  The PR, and Max's patch, completely fell off my radar.

  Anyway, the patch is now applied.  I left in the check for next_ordinal being too large, just in case a different bug makes it exceed max_ordinal.

Cheers
  Nick
Comment 4 batterseapower 2017-03-04 11:37:38 UTC
Thanks for the merge. I'd given up all hope of seeing this fixed!
Comment 5 Nick Clifton 2017-03-06 12:25:37 UTC
> Thanks for the merge. I'd given up all hope of seeing this fixed!

Just FYI: In situations like this, pinging the mailing list, or the PR, is a good way to remind us that we have missed something!

Cheers
  Nick