Skip to content

coff split: let the linker regenerate a PE import table - #12

Merged
handsomematt merged 1 commit into
coff_prototypefrom
pe-import-libraries
Oct 11, 2026
Merged

handsomematt merged 1 commit into
coff_prototypefrom
pe-import-libraries

Conversation

@handsomematt

Copy link
Copy Markdown
Member

Adds a generate_imports module option: the linker builds the image's import directory instead of the split objects carrying the original's bytes. Needs openblack/llvm-project#4 for /vc6imports:.

What the split writes (read back from the original import directory)

  • imports.lib: a COFF archive of short-format import objects, one per imported function.
    • Each carries the original hint and imported name (IMPORT_OBJECT_NAME_EXPORTAS), or the ordinal.
    • All are DATA imports, so the linker defines only __imp_<symbol>. The image's own jmp [__imp_X] stubs stay in the split objects, where link.exe put them.
  • imports.order: the layout link.exe gave the tables. link.exe 6 ordered them by its library-search order, which can't be redone without the original import libraries:
    • descriptor order;
    • IAT/lookup slot order (grouped by DLL, not name-sorted within one);
    • the hint/name area with the DLL names interleaved;
    • pad lines for the zero padding an incremental link leaves after each DLL's entries, or that the splits' .idata$5 covers past the IAT.
  • args.rsp: passes the library and /vc6imports:<order>.

Requirements

  • The IAT slots must be named __imp_… in the symbols.
  • The splits must leave the original .idata$N out of the linked units; bw1-decomp holds those units back.

Testing

  • cargo test: 36 pass, including new tests for the import objects, the archive's symbol table and member offsets, the order file, and both kinds of padding.
  • clippy has no diagnostics on the new code.
  • bw1-decomp BW1W120 with a local build of lld: Lay out export and import tables like vc6 link.exe on i386 llvm-project#4:
    • runblack.exe, LHAudio, LHLog, LHMultiplayer and LHDialog (incrementally linked, with MFC ordinal imports) link their import tables from these;
    • all 15 build.sha1 hashes match.

🤖 Generated with Claude Code

A module with `generate_imports: true` gets its import directory from the
linker instead of carrying the original's bytes. The split reads the
original import directory back into:

- imports.lib: a COFF archive of short-format import objects, one per
  imported function, with the original hint and imported name
  (IMPORT_OBJECT_NAME_EXPORTAS) or ordinal. All are DATA imports, so the
  linker defines only __imp_<symbol>; the image's own jmp stubs come
  from the split objects.
- imports.order: the layout link.exe gave the tables, for a vc6-aware
  lld-link's /vc6imports: (descriptor order, IAT slot order, the
  hint/name area with the DLL names, and incremental-link padding).

args.rsp passes both. The IAT slots must be named __imp_ in the symbols,
and the splits must leave the original .idata$N out of the linked units.
@handsomematt
handsomematt merged commit ad1dc7b into coff_prototype Oct 11, 2026
30 checks passed
@bwrsandman
bwrsandman deleted the pe-import-libraries branch October 13, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant