diff --git a/src/base/base_strings.c b/src/base/base_strings.c
index fde890c5..ab34f01a 100644
--- a/src/base/base_strings.c
+++ b/src/base/base_strings.c
@@ -522,6 +522,17 @@ push_str8f(Arena *arena, char *fmt, ...){
return(result);
}
+internal String8
+push_cstr(Arena *arena, String8 str)
+{
+ U64 buffer_size = str.size + 1;
+ U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
+ MemoryCopy(buffer, str.str, str.size);
+ buffer[str.size] = 0;
+ String8 result = str8(buffer, buffer_size);
+ return result;
+}
+
////////////////////////////////
//~ rjf: String <=> Integer Conversions
diff --git a/src/base/base_strings.h b/src/base/base_strings.h
index 7b9b3d20..14e71c74 100644
--- a/src/base/base_strings.h
+++ b/src/base/base_strings.h
@@ -232,6 +232,7 @@ internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
internal String8 push_str8_copy(Arena *arena, String8 s);
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
internal String8 push_str8f(Arena *arena, char *fmt, ...);
+internal String8 push_cstr(Arena *arena, String8 str);
////////////////////////////////
//~ rjf: String <=> Integer Conversions
diff --git a/src/coff/coff.c b/src/coff/coff.c
index 1d68d786..a474f698 100644
--- a/src/coff/coff.c
+++ b/src/coff/coff.c
@@ -253,18 +253,6 @@ coff_pick_reloc_value_x64(COFF_Reloc_X64 type,
return result;
}
-internal COFF_RelocType
-coff_virt_off_reloc_from_machine(COFF_MachineType machine)
-{
- COFF_RelocType result = 0;
- switch (machine) {
- case COFF_MachineType_Unknown: break;
- case COFF_MachineType_X64: result = COFF_Reloc_X64_Addr32Nb; break;
- default: { NotImplemented; } break;
- }
- return result;
-}
-
internal String8
coff_make_import_lookup(Arena *arena, U16 hint, String8 name)
{
diff --git a/src/coff/coff.h b/src/coff/coff.h
index 5d1473b9..3cbe8f8e 100644
--- a/src/coff/coff.h
+++ b/src/coff/coff.h
@@ -603,7 +603,6 @@ internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x);
internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x);
internal COFF_RelocValue coff_pick_reloc_value_x64(COFF_Reloc_X64 type, U64 reloc_virtual_offset, U32 symbol_section_number, U32 symbol_section_offset, U32 symbol_virtual_offset, U64 symbol_address);
-internal COFF_RelocType coff_virt_off_reloc_from_machine(COFF_MachineType machine);
////////////////////////////////
// Import
diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c
index 6ad24044..e29370d5 100644
--- a/src/coff/coff_lib_writer.c
+++ b/src/coff/coff_lib_writer.c
@@ -128,11 +128,9 @@ coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_d
}
}
-internal COFF_LibWriterSymbolNode *
+internal void
coff_lib_writer_push_export(COFF_LibWriter *writer, String8 raw_import_header)
{
- COFF_LibWriterSymbolNode *result = 0;
-
U64 member_idx = writer->member_list.count;
COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(raw_import_header);
@@ -147,35 +145,36 @@ coff_lib_writer_push_export(COFF_LibWriter *writer, String8 raw_import_header)
COFF_LibWriterSymbol def_symbol = {0};
def_symbol.name = push_str8_copy(writer->arena, import_header.func_name);
def_symbol.member_idx = member_idx;
- result = coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, def_symbol);
+ coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, def_symbol);
+
+ COFF_LibWriterSymbol imp_symbol = {0};
+ imp_symbol.name = push_str8f(writer->arena, "__imp_%S", import_header.func_name);
+ imp_symbol.member_idx = member_idx;
+ coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, def_symbol);
} break;
case COFF_ImportHeader_Data: {
COFF_LibWriterSymbol imp_symbol = {0};
imp_symbol.name = push_str8f(writer->arena, "__imp_%S", import_header.func_name);
imp_symbol.member_idx = member_idx;
- result = coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, imp_symbol);
- } break;
- case COFF_ImportHeader_Const: {
- NotImplemented;
+ coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, imp_symbol);
} break;
+ case COFF_ImportHeader_Const: { NotImplemented; } break;
default: { InvalidPath; } break;
}
-
- return result;
}
-internal COFF_LibWriterSymbolNode *
+internal void
coff_lib_writer_push_export_by_ordinal(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportType import_type, U16 ordinal)
{
String8 import_header = coff_make_import_header_by_ordinal(lib_writer->arena, machine, time_stamp, dll_name, ordinal, import_type);
- return coff_lib_writer_push_export(lib_writer, import_header);
+ coff_lib_writer_push_export(lib_writer, import_header);
}
-internal COFF_LibWriterSymbolNode *
+internal void
coff_lib_writer_push_export_by_name(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportType import_type, String8 name, U16 hint)
{
String8 import_header = coff_make_import_header_by_name(lib_writer->arena, machine, time_stamp, dll_name, name, hint, import_type);
- return coff_lib_writer_push_export(lib_writer, import_header);
+ coff_lib_writer_push_export(lib_writer, import_header);
}
internal String8List
diff --git a/src/coff/coff_lib_writer.h b/src/coff/coff_lib_writer.h
index 0b2c166c..76dee152 100644
--- a/src/coff/coff_lib_writer.h
+++ b/src/coff/coff_lib_writer.h
@@ -12,8 +12,8 @@ typedef struct COFF_LibWriterMember
typedef struct COFF_LibWriterMemberNode
{
- struct COFF_LibWriterMemberNode *next;
COFF_LibWriterMember data;
+ struct COFF_LibWriterMemberNode *next;
} COFF_LibWriterMemberNode;
typedef struct COFF_LibWriterMemberList
@@ -31,8 +31,8 @@ typedef struct COFF_LibWriterSymbol
typedef struct COFF_LibWriterSymbolNode
{
- struct COFF_LibWriterSymbolNode *next;
COFF_LibWriterSymbol data;
+ struct COFF_LibWriterSymbolNode *next;
} COFF_LibWriterSymbolNode;
typedef struct COFF_LibWriterSymbolList
@@ -60,9 +60,9 @@ internal void coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 c
internal COFF_LibWriter * coff_lib_writer_alloc(void);
internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr);
internal void coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data);
-internal COFF_LibWriterSymbolNode * coff_lib_writer_push_export(COFF_LibWriter *writer, String8 raw_import_header);
-internal COFF_LibWriterSymbolNode * coff_lib_writer_push_export_by_ordinal(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportType import_type, U16 ordinal);
-internal COFF_LibWriterSymbolNode * coff_lib_writer_push_export_by_name(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportType import_type, String8 name, U16 hint);
+internal void coff_lib_writer_push_export(COFF_LibWriter *writer, String8 raw_import_header);
+internal void coff_lib_writer_push_export_by_ordinal(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportType import_type, U16 ordinal);
+internal void coff_lib_writer_push_export_by_name(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportType import_type, String8 name, U16 hint);
internal String8List coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member);
#endif // COFF_LIB_WRITER_H
diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c
index faa0dd29..9b730d9c 100644
--- a/src/coff/coff_obj_writer.c
+++ b/src/coff/coff_obj_writer.c
@@ -16,6 +16,24 @@ coff_obj_writer_release(COFF_ObjWriter **obj_writer)
*obj_writer = 0;
}
+internal COFF_ObjSection *
+coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
+{
+ COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
+ SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
+ obj_writer->sect_count += 1;
+
+ COFF_ObjSection *sect = §_n->v;
+ sect->name = name;
+ sect->flags = flags;
+
+ if (data.size) {
+ str8_list_push(obj_writer->arena, §->data, data);
+ }
+
+ return sect;
+}
+
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class)
{
@@ -104,15 +122,6 @@ coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
return s;
}
-internal COFF_ObjSymbol *
-coff_obj_writer_push_symbol_undef_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags)
-{
- COFF_SymbolType type = {0};
- COFF_SymbolLocation loc = { COFF_SymbolLocation_Undef };
- COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, flags, loc, type, COFF_SymStorageClass_Section);
- return s;
-}
-
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
{
@@ -159,24 +168,6 @@ coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32
return s;
}
-internal COFF_ObjSection *
-coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
-{
- COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
- SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
- obj_writer->sect_count += 1;
-
- COFF_ObjSection *sect = §_n->v;
- sect->name = name;
- sect->flags = flags;
-
- if (data.size) {
- str8_list_push(obj_writer->arena, §->data, data);
- }
-
- return sect;
-}
-
internal COFF_ObjReloc*
coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type)
{
@@ -192,6 +183,30 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *
return reloc;
}
+internal COFF_ObjReloc *
+coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
+{
+ COFF_RelocType reloc_type = 0;
+ switch (obj_writer->machine) {
+ case COFF_MachineType_Unknown: break;
+ case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break;
+ default: { NotImplemented; } break;
+ }
+ return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
+}
+
+internal COFF_ObjReloc *
+coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
+{
+ COFF_RelocType reloc_type = 0;
+ switch (obj_writer->machine) {
+ case COFF_MachineType_Unknown: break;
+ case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break;
+ default: { NotImplemented; } break;
+ }
+ return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
+}
+
internal void
coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive)
{
diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h
index 56cf47e2..e537a632 100644
--- a/src/coff/coff_obj_writer.h
+++ b/src/coff/coff_obj_writer.h
@@ -94,11 +94,26 @@ typedef struct COFF_ObjWriter
////////////////////////////////
-internal COFF_ObjWriter* coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
-internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
-internal COFF_ObjSection* coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
+internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
+internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
+
+internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
+
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
-internal COFF_ObjReloc* coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
+internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
+
+internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
+internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
+internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
#endif // COFF_OBJ_WRITER_H
diff --git a/src/linker/base_ext/base_arena.c b/src/linker/base_ext/base_arena.c
index 79471dfb..669cf47f 100644
--- a/src/linker/base_ext/base_arena.c
+++ b/src/linker/base_ext/base_arena.c
@@ -1,17 +1,6 @@
// Copyright (c) 2025 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
-internal String8
-push_cstr(Arena *arena, String8 str)
-{
- U64 buffer_size = str.size + 1;
- U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
- MemoryCopy(buffer, str.str, str.size);
- buffer[str.size] = 0;
- String8 result = str8(buffer, buffer_size);
- return result;
-}
-
internal U32 *
push_u32(Arena *arena, U32 value)
{
diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c
index bdc32ac3..964506aa 100644
--- a/src/linker/hash_table.c
+++ b/src/linker/hash_table.c
@@ -329,6 +329,19 @@ keys_from_hash_table_u64(Arena *arena, HashTable *ht)
return result;
}
+internal String8 *
+keys_from_hash_table_string(Arena *arena, HashTable *ht)
+{
+ String8 *result = push_array_no_zero(arena, String8, ht->count);
+ for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) {
+ for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) {
+ Assert(cursor < ht->count);
+ result[cursor++] = n->v.key_string;
+ }
+ }
+ return result;
+}
+
internal KeyValuePair *
key_value_pairs_from_hash_table(Arena *arena, HashTable *ht)
{
diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h
index cc65cbf5..504aedc6 100644
--- a/src/linker/hash_table.h
+++ b/src/linker/hash_table.h
@@ -79,6 +79,7 @@ internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_o
internal U32 * keys_from_hash_table_u32 (Arena *arena, HashTable *ht);
internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable *ht);
+internal String8 keys_from_hash_table_str8 (Arena *arena, HashTable *ht);
internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht);
internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht);
diff --git a/src/linker/lnk.c b/src/linker/lnk.c
index ecf53d44..7fec2c93 100644
--- a/src/linker/lnk.c
+++ b/src/linker/lnk.c
@@ -41,6 +41,9 @@
#include "coff/coff_obj_writer.h"
#include "coff/coff_lib_writer.h"
#include "pe/pe.h"
+#include "pe/pe_section_flags.h"
+#include "pe/pe_make_import_table.h"
+#include "pe/pe_make_export_table.h"
#include "codeview/codeview.h"
#include "codeview/codeview_parse.h"
#include "codeview/codeview_enum.h"
@@ -59,6 +62,8 @@
#include "coff/coff_obj_writer.c"
#include "coff/coff_lib_writer.c"
#include "pe/pe.c"
+#include "pe/pe_make_import_table.c"
+#include "pe/pe_make_export_table.c"
#include "codeview/codeview.c"
#include "codeview/codeview_enum.c"
#include "codeview/codeview_parse.c"
@@ -119,9 +124,6 @@
#include "lnk_io.h"
#include "lnk_cmd_line.h"
#include "lnk_input.h"
-#include "lnk_image_section_flags.h"
-#include "lnk_import_table.h"
-#include "lnk_export_table.h"
#include "lnk_config.h"
#include "lnk_symbol_table.h"
#include "lnk_section_table.h"
@@ -137,8 +139,6 @@
#include "lnk_io.c"
#include "lnk_cmd_line.c"
#include "lnk_input.c"
-#include "lnk_import_table.c"
-#include "lnk_export_table.c"
#include "lnk_config.c"
#include "lnk_symbol_table.c"
#include "lnk_section_table.c"
@@ -425,8 +425,8 @@ lnk_serialize_pe_resource_tree(COFF_ObjWriter *obj_writer, PE_ResourceDir *root_
stack->coff_entry_arr[1] = 0;
}
- COFF_ObjSection *rsrc1 = coff_obj_writer_push_section(obj_writer, str8_lit(".rsrc$01"), LNK_RSRC1_SECTION_FLAGS, str8_zero());
- COFF_ObjSection *rsrc2 = coff_obj_writer_push_section(obj_writer, str8_lit(".rsrc$02"), LNK_RSRC2_SECTION_FLAGS, str8_zero());
+ COFF_ObjSection *rsrc1 = coff_obj_writer_push_section(obj_writer, str8_lit(".rsrc$01"), PE_RSRC1_SECTION_FLAGS, str8_zero());
+ COFF_ObjSection *rsrc2 = coff_obj_writer_push_section(obj_writer, str8_lit(".rsrc$02"), PE_RSRC2_SECTION_FLAGS, str8_zero());
for (; stack; ) {
for (; stack->arr_idx < ArrayCount(stack->res_arr); stack->arr_idx += 1) {
@@ -635,7 +635,7 @@ lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer,
str8_serial_push_align(scratch.arena, &sub_sect_srl, CV_C13SubSectionAlign);
String8 sub_sect_data = str8_serial_end(obj_writer->arena, &sub_sect_srl);
- coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS, sub_sect_data);
+ coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS, sub_sect_data);
scratch_end(scratch);
ProfEnd();
@@ -749,7 +749,7 @@ lnk_make_linker_coff_obj(Arena *arena,
String8 obj;
{
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
- coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
+ coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
obj = coff_obj_writer_serialize(arena, obj_writer);
coff_obj_writer_release(&obj_writer);
}
@@ -773,7 +773,7 @@ lnk_push_pe_debug_data_directory(COFF_ObjWriter *obj_writer,
dir->size = data_size;
//dir->voff = 0; // relocated through 'data_symbol'
//dir->foff = 0; // relocated through 'data_symbol'
- COFF_ObjSection *debug_dir_sect = coff_obj_writer_push_section(obj_writer, dir_name, LNK_DATA_SECTION_FLAGS, str8_struct(dir));
+ COFF_ObjSection *debug_dir_sect = coff_obj_writer_push_section(obj_writer, dir_name, PE_DATA_SECTION_FLAGS, str8_struct(dir));
coff_obj_writer_section_push_reloc(obj_writer, debug_dir_sect, OffsetOf(PE_DebugDirectory, voff), data_symbol, COFF_Reloc_X64_Addr32Nb);
coff_obj_writer_section_push_reloc(obj_writer, debug_dir_sect, OffsetOf(PE_DebugDirectory, foff), data_symbol, COFF_Reloc_X64_Abs);
}
@@ -782,8 +782,8 @@ internal String8
lnk_make_debug_directory_obj(Arena *arena, LNK_Config *config)
{
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, config->machine);
- COFF_ObjSection *sect_a = coff_obj_writer_push_section(obj_writer, str8_lit(".RAD_LINKER_DEBUG_DIR$a"), LNK_DATA_SECTION_FLAGS, str8_zero());
- COFF_ObjSection *sect_z = coff_obj_writer_push_section(obj_writer, str8_lit(".RAD_LINKER_DEBUG_DIR$z"), LNK_DATA_SECTION_FLAGS, str8_zero());
+ COFF_ObjSection *sect_a = coff_obj_writer_push_section(obj_writer, str8_lit(".RAD_LINKER_DEBUG_DIR$a"), PE_DATA_SECTION_FLAGS, str8_zero());
+ COFF_ObjSection *sect_z = coff_obj_writer_push_section(obj_writer, str8_lit(".RAD_LINKER_DEBUG_DIR$z"), PE_DATA_SECTION_FLAGS, str8_zero());
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
coff_obj_writer_release(&obj_writer);
return obj;
@@ -794,7 +794,7 @@ lnk_make_debug_directory_pdb_obj(Arena *arena, LNK_Config *config)
{
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, config->machine);
String8 debug_pdb_data = pe_make_debug_header_pdb70(obj_writer->arena, config->guid, config->age, config->pdb_alt_path);
- COFF_ObjSection *debug_pdb_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$z"), LNK_DATA_SECTION_FLAGS, debug_pdb_data);
+ COFF_ObjSection *debug_pdb_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$z"), PE_DATA_SECTION_FLAGS, debug_pdb_data);
COFF_ObjSymbol *debug_pdb_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("PDB_DEBUG_HEADER_70"), 0, debug_pdb_sect);
lnk_push_pe_debug_data_directory(obj_writer, debug_pdb_symbol, debug_pdb_data.size, str8_lit(".RAD_LINKER_DEBUG_DIR$PDB"), PE_DebugDirectoryType_CODEVIEW, config->time_stamp);
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
@@ -806,7 +806,7 @@ lnk_make_debug_directory_rdi_obj(Arena *arena, LNK_Config *config)
{
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, COFF_MachineType_Unknown);
String8 debug_rdi_data = pe_make_debug_header_rdi(obj_writer->arena, config->guid, config->rad_debug_alt_path);
- COFF_ObjSection *debug_rdi_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$z"), LNK_DATA_SECTION_FLAGS, debug_rdi_data);
+ COFF_ObjSection *debug_rdi_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$z"), PE_DATA_SECTION_FLAGS, debug_rdi_data);
COFF_ObjSymbol *debug_rdi_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("RDI_DEBUG_HEADER"), 0, debug_rdi_sect);
lnk_push_pe_debug_data_directory(obj_writer, debug_rdi_symbol, debug_rdi_data.size, str8_lit("RAD_LINKER_DEBUG_DIR$RDI"), PE_DebugDirectoryType_CODEVIEW, config->time_stamp);
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
@@ -871,10 +871,10 @@ lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path)
}
internal void
-lnk_push_export(Arena *arena, HashTable *export_ht, LNK_ExportParseList *export_list, String8List *include_symbol_list, LNK_ExportParse export_parse)
+lnk_push_export(Arena *arena, HashTable *export_ht, PE_ExportParseList *export_list, String8List *include_symbol_list, PE_ExportParse export_parse)
{
- LNK_ExportParseNode *exp_n = 0;
- String8 export_name = lnk_name_from_export_parse(&export_parse);
+ PE_ExportParseNode *exp_n = 0;
+ String8 export_name = pe_name_from_export_parse(&export_parse);
hash_table_search_string_raw(export_ht, export_name, &exp_n);
if (exp_n == 0) {
@@ -884,12 +884,12 @@ lnk_push_export(Arena *arena, HashTable *export_ht, LNK_ExportParseList *export_
}
// push new export
- exp_n = lnk_export_parse_list_push(arena, export_list, export_parse);
+ exp_n = pe_export_parse_list_push(arena, export_list, export_parse);
hash_table_push_string_raw(arena, export_ht, export_name, exp_n);
} else {
B32 is_ambiguous = 1;
- LNK_ExportParse *extant_export = &exp_n->data;
+ PE_ExportParse *extant_export = &exp_n->data;
if (extant_export->alias.size && export_parse.alias.size && !str8_match(extant_export->alias, export_parse.alias, 0)) {
goto report;
@@ -2066,9 +2066,9 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
// init section table
//
LNK_SectionTable *sectab = lnk_section_table_alloc();
- lnk_section_table_push(sectab, str8_lit(".text"), LNK_TEXT_SECTION_FLAGS);
- lnk_section_table_push(sectab, str8_lit(".data"), LNK_DATA_SECTION_FLAGS);
- lnk_section_table_push(sectab, str8_lit(".rdata"), LNK_RDATA_SECTION_FLAGS);
+ lnk_section_table_push(sectab, str8_lit(".text"), PE_TEXT_SECTION_FLAGS);
+ lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS);
+ lnk_section_table_push(sectab, str8_lit(".rdata"), PE_RDATA_SECTION_FLAGS);
//
// obj list -> array
@@ -2392,9 +2392,9 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
ProfBeginV("Assign Common Block Offsets [count %llu]", common_block_contribs_count);
// search/push .data
- common_block_sect = lnk_section_table_search(sectab, str8_lit(".data"), LNK_DATA_SECTION_FLAGS);
+ common_block_sect = lnk_section_table_search(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS);
if (common_block_sect == 0) {
- common_block_sect = lnk_section_table_push(sectab, str8_lit(".data"), LNK_DATA_SECTION_FLAGS);
+ common_block_sect = lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS);
}
// sort common blocks from largest to smallest for tighter packing
@@ -2742,7 +2742,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
if (~config->flags & LNK_ConfigFlag_Fixed) {
String8List base_relocs_data = lnk_build_base_relocs(tp, arena, config, objs_count, objs);
if (base_relocs_data.total_size) {
- LNK_Section *reloc = lnk_section_table_push(sectab, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS);
+ LNK_Section *reloc = lnk_section_table_push(sectab, str8_lit(".reloc"), PE_RELOC_SECTION_FLAGS);
LNK_SectionContribChunk *first_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &reloc->contribs, 1);
LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(first_sc_chunk, 1);
sc->data_list = base_relocs_data.first;
@@ -2938,7 +2938,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
// patch .pdata
{
- LNK_Section *pdata_sect = lnk_section_table_search(sectab, str8_lit(".pdata"), LNK_PDATA_SECTION_FLAGS);
+ LNK_Section *pdata_sect = lnk_section_table_search(sectab, str8_lit(".pdata"), PE_PDATA_SECTION_FLAGS);
if (pdata_sect) {
String8 pdata = str8_substr(image_data, rng_1u64(pdata_sect->foff, pdata_sect->foff + pdata_sect->vsize));
@@ -2964,7 +2964,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
// patch export
{
- LNK_Section *edata_sect = lnk_section_table_search(sectab, str8_lit(".edata"), LNK_EDATA_SECTION_FLAGS);
+ LNK_Section *edata_sect = lnk_section_table_search(sectab, str8_lit(".edata"), PE_EDATA_SECTION_FLAGS);
if (edata_sect) {
PE_DataDirectory *export_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXPORT, sizeof(PE_DataDirectory));
export_dir->virt_off = edata_sect->voff;
@@ -2974,7 +2974,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
// patch base relocs
{
- LNK_Section *reloc_sect = lnk_section_table_search(sectab, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS);
+ LNK_Section *reloc_sect = lnk_section_table_search(sectab, str8_lit(".reloc"), PE_RELOC_SECTION_FLAGS);
if (reloc_sect) {
PE_DataDirectory *reloc_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_BASE_RELOC, sizeof(PE_DataDirectory));
reloc_dir->virt_off = reloc_sect->voff;
@@ -3033,7 +3033,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
ProfBegin("Patch TLS Align");
// loop over .tls sections and extract max alignment
- LNK_Section *tls_sect = lnk_section_table_search(sectab, str8_lit(".tls"), LNK_RDATA_SECTION_FLAGS);
+ LNK_Section *tls_sect = lnk_section_table_search(sectab, str8_lit(".tls"), PE_RDATA_SECTION_FLAGS);
U64 tls_align = 0;
for (LNK_SectionContribChunk *sc_chunk = tls_sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
@@ -3070,7 +3070,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
// patch Debug
{
- LNK_Section *debug_dir_sect = lnk_section_table_search(sectab, str8_lit(".RAD_LINKER_DEBUG_DIR"), LNK_RDATA_SECTION_FLAGS);
+ LNK_Section *debug_dir_sect = lnk_section_table_search(sectab, str8_lit(".RAD_LINKER_DEBUG_DIR"), PE_RDATA_SECTION_FLAGS);
if (debug_dir_sect) {
PE_DataDirectory *debug_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, sizeof(PE_DataDirectory));
debug_dir->virt_off = debug_dir_sect->voff;
@@ -3100,7 +3100,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
// patch resources
{
- LNK_Section *rsrc_sect = lnk_section_table_search(sectab, str8_lit(".rsrc"), LNK_RSRC_SECTION_FLAGS);
+ LNK_Section *rsrc_sect = lnk_section_table_search(sectab, str8_lit(".rsrc"), PE_RSRC_SECTION_FLAGS);
if (rsrc_sect) {
PE_DataDirectory *rsrc_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_RESOURCES, sizeof(PE_DataDirectory));
rsrc_dir->virt_off = rsrc_sect->voff;
@@ -3538,7 +3538,7 @@ lnk_run(int argc, char **argv)
String8List input_disallow_lib_list = config->disallow_lib_list;
String8List input_manifest_path_list = str8_list_copy(scratch.arena, &config->input_list[LNK_Input_Manifest]);
String8List manifest_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list);
- LNK_ExportParseList export_symbol_list = config->export_symbol_list;
+ PE_ExportParseList export_symbol_list = config->export_symbol_list;
HashTable *export_ht = hash_table_init(scratch.arena, max_U16/2);
LNK_AltNameList alt_name_list = config->alt_name_list;
LNK_InputObjList input_obj_list = {0};
@@ -3559,11 +3559,12 @@ lnk_run(int argc, char **argv)
// state
LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena);
LNK_SectionTable *sectab = 0;
- LNK_ImportTable *imptab_static = lnk_import_table_alloc();
- LNK_ImportTable *imptab_delayed = lnk_import_table_alloc();
+ HashTable *static_imports = hash_table_init(scratch.arena, 512);
+ HashTable *delayed_imports = hash_table_init(scratch.arena, 512);
LNK_ObjList obj_list = {0};
LNK_LibList lib_index[LNK_InputSource_Count] = {0};
Arena *ht_arena = arena_alloc();
+ String8 delay_load_helper_name = {0};
HashTable *disallow_lib_ht = hash_table_init(scratch.arena, 0x100);
HashTable *delay_load_dll_ht = hash_table_init(scratch.arena, 0x100);
HashTable *loaded_lib_ht = hash_table_init(scratch.arena, 0x100);
@@ -3618,7 +3619,7 @@ lnk_run(int argc, char **argv)
//
// Push config exports
//
- for (LNK_ExportParseNode *exp_n = config->export_symbol_list.first; exp_n != 0; exp_n = exp_n->next) {
+ for (PE_ExportParseNode *exp_n = config->export_symbol_list.first; exp_n != 0; exp_n = exp_n->next) {
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, exp_n->data);
}
@@ -3651,24 +3652,56 @@ lnk_run(int argc, char **argv)
for (LNK_InputImport *input = input_import_list.first; input != 0; input = input->next) {
COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(input->coff_import);
+ // import machine compat check
if (import_header.machine != config->machine) {
- lnk_error(LNK_Error_IncompatibleMachine, "symbol pulls in an import with incompatible machine %S (expected %S)",
+ lnk_error(LNK_Error_IncompatibleMachine, "symbol %S pulled in import with incompatible machine %S (expected %S)",
+ import_header.func_name,
coff_string_from_machine_type(import_header.machine),
coff_string_from_machine_type(config->machine));
+ continue;
}
- LNK_Symbol *thunk_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1);
- thunk_symbol->type = LNK_Symbol_Import;
- thunk_symbol->name = import_header.func_name;
- thunk_symbol->u.coff_import = input->coff_import;
+ // create import stubs (later replaced with acutal imports generated by linker)
+ LNK_Symbol *thunk_symbol;
+ {
+ thunk_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1);
+ thunk_symbol->type = LNK_Symbol_Import;
+ thunk_symbol->name = import_header.func_name;
+ thunk_symbol->u.coff_import = input->coff_import;
- LNK_Symbol *iat_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1);
- iat_symbol->type = LNK_Symbol_Import;
- iat_symbol->name = push_str8f(symtab->arena->v[0], "__imp_%S", import_header.func_name);
- iat_symbol->u.coff_import = input->coff_import;
+ LNK_Symbol *iat_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1);
+ iat_symbol->type = LNK_Symbol_Import;
+ iat_symbol->name = push_str8f(symtab->arena->v[0], "__imp_%S", import_header.func_name);
+ iat_symbol->u.coff_import = input->coff_import;
- lnk_symbol_table_push(symtab, thunk_symbol);
- lnk_symbol_table_push(symtab, iat_symbol);
+ lnk_symbol_table_push(symtab, thunk_symbol);
+ lnk_symbol_table_push(symtab, iat_symbol);
+ }
+
+ // pick imports hash table
+ HashTable *imports_ht;
+ {
+ B32 is_delay_load_dll = hash_table_search_path_u64(delay_load_dll_ht, import_header.dll_name, 0);
+ if (is_delay_load_dll) {
+ imports_ht = delayed_imports;
+ } else {
+ imports_ht = static_imports;
+ }
+ }
+
+ // search DLL symbol list
+ String8List *import_symbols;
+ {
+ import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name);
+ if (import_symbols == 0) {
+ import_symbols = push_array(scratch.arena, String8List, 1);
+ hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols);
+ }
+ hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols);
+ }
+
+ // push symbol
+ str8_list_push(scratch.arena, import_symbols, input->coff_import);
}
// reset input
@@ -3816,7 +3849,7 @@ lnk_run(int argc, char **argv)
// /EXPORT
{
for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) {
- LNK_ExportParse export_parse = {0};
+ PE_ExportParse export_parse = {0};
lnk_parse_export_directive_ex(scratch.arena, dir->value_list, obj->path, obj->lib_path, &export_parse);
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, export_parse);
}
@@ -3991,14 +4024,13 @@ lnk_run(int argc, char **argv)
case State_PushDllHelperUndefSymbol: {
ProfBegin("Push Dll Helper Undef Symbol");
- String8 delay_helper_name = str8_zero();
switch (config->machine) {
- case COFF_MachineType_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break;
- case COFF_MachineType_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break;
- default: NotImplemented;
+ case COFF_MachineType_X86: delay_load_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break;
+ case COFF_MachineType_X64: delay_load_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break;
+ default: { NotImplemented; } break;
}
- str8_list_push(scratch.arena, &include_symbol_list, delay_helper_name);
+ str8_list_push(scratch.arena, &include_symbol_list, delay_load_helper_name);
ProfEnd();
} break;
case State_PushLinkerSymbols: {
@@ -4176,52 +4208,96 @@ lnk_run(int argc, char **argv)
}
} break;
case State_InputImportObjs: {
- if (input_import_list.count) {
- ProfBegin("Build Import Table");
+ ProfBegin("Build Import Table");
- // warn about unused delayloads
- if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) {
- if (imptab_delayed) {
- for (String8Node *node = config->delay_load_dll_list.first; node != 0; node = node->next) {
- LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_delayed, node->string);
- if (dll == 0) {
- lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", node->string);
- }
- }
+ // warn about unused delayloads
+ if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) {
+ for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) {
+ if (!hash_table_search_string_raw(delayed_imports, dll_name_n->string, 0)) {
+ lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string);
}
}
+ }
- // make and input static imports
- String8Array import_objs_static = lnk_make_import_dlls_static(scratch.arena, imptab_static, config->machine, str8_skip_last_slash(config->image_name));
- for (U64 i = 0; i < import_objs_static.count; i += 1) {
- LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
- input->path = str8_lit("* Import Obj *");
- input->input_idx = i;
- input->data = import_objs_static.v[i];
- }
-
- // make and input delayed imports
+ // make and input delayed imports
+ if (delayed_imports->count) {
+ COFF_TimeStamp time_stamp = COFF_TimeStamp_Max;
B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes;
B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes;
- String8Array import_objs_delayed = lnk_make_import_dlls_delayed(scratch.arena, imptab_delayed, config->machine, str8_skip_last_slash(config->image_name), emit_biat, emit_uiat);
- for (U64 i = 0; i < import_objs_delayed.count; i += 1) {
- LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
- input->path = str8_lit("* Import Obj *");
- input->input_idx = import_objs_static.count + i;
- input->data = import_objs_delayed.v[i];
- }
+ String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports);
+ String8List *dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports);
- ProfEnd();
+ for (U64 dll_idx = 0; dll_idx < delayed_imports->count; dll_idx += 1) {
+ String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]);
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_import_dll_obj_delayed(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, dll_import_headers[dll_idx], emit_biat, emit_uiat);
+ input->path = dll_names[dll_idx];
+ }
+ String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
+ {
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_import_entry_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols);
+ input->path = str8_lit("* Delayed Import Entry Obj *");
+ }
+ {
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_null_import_descriptor_obj(scratch.arena, time_stamp, config->machine, linker_debug_symbols);
+ input->path = str8_lit("* Delayed Null Import Descriptor *");
+ }
+ {
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_null_thunk_data_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols);
+ input->path = str8_lit("* Delayed Null Thunk Data *");
+ }
}
+
+ // make and input static imports
+ if (static_imports->count) {
+ COFF_TimeStamp time_stamp = COFF_TimeStamp_Max;
+ String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports);
+ String8List *dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports);
+ for (U64 dll_idx = 0; dll_idx < static_imports->count; dll_idx += 1) {
+ String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]);
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_import_dll_obj_static(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, dll_import_headers[dll_idx]);
+ input->path = dll_names[dll_idx];
+ }
+ String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
+ {
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_import_entry_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols);
+ input->path = str8_lit("* Import Entry Obj *");
+ }
+ {
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_null_import_descriptor_obj(scratch.arena, time_stamp, config->machine, linker_debug_symbols);
+ input->path = str8_lit("* Null Import Descriptor *");
+ }
+ {
+ LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
+ input->input_idx = input_obj_list.count;
+ input->data = pe_make_null_thunk_data_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols);
+ input->path = str8_lit("* Null Thunk Data *");
+ }
+ }
+
+ ProfEnd();
} break;
case State_InputExportObjs: {
if (export_symbol_list.count) {
ProfBegin("Build Export Table");
- LNK_ExportParseList resolved_exports = {0};
- for (LNK_ExportParseNode *exp_n = export_symbol_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) {
+ PE_ExportParseList resolved_exports = {0};
+ for (PE_ExportParseNode *exp_n = export_symbol_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) {
exp_n_next = exp_n->next;
- LNK_ExportParse *exp = &exp_n->data;
+ PE_ExportParse *exp = &exp_n->data;
if (!exp->is_forwarder) {
// filter out unresolved exports
@@ -4255,15 +4331,16 @@ lnk_run(int argc, char **argv)
}
// push resolved export
- lnk_export_parse_list_push_node(&resolved_exports, exp_n);
+ pe_export_parse_list_push_node(&resolved_exports, exp_n);
}
- String8 edata_obj = lnk_make_edata_obj(scratch.arena, symtab, str8_skip_last_slash(config->image_name), config->machine, resolved_exports);
+ PE_FinalizedExports finalized_exports = pe_finalize_export_list(scratch.arena, resolved_exports);
+ String8 edata_obj = pe_make_edata_obj(scratch.arena, str8_skip_last_slash(config->image_name), COFF_TimeStamp_Max, config->machine, finalized_exports);
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
- input->path = str8_lit("* Exports *");
- input->dedup_id = input->path;
- input->data = edata_obj;
+ input->path = str8_lit("* Exports *");
+ input->dedup_id = input->path;
+ input->data = edata_obj;
ProfEnd();
}
@@ -4420,7 +4497,8 @@ lnk_run(int argc, char **argv)
case State_BuildImpLib: {
ProfBegin("Build Imp Lib");
lnk_timer_begin(LNK_Timer_Lib);
- String8List lib_list = lnk_build_import_lib(tp_arena->v[0], config->machine, config->time_stamp, config->image_name, export_symbol_list);
+ String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
+ String8List lib_list = pe_make_import_lib(tp_arena->v[0], config->machine, config->time_stamp, str8_skip_last_slash(config->image_name), linker_debug_symbols, export_symbol_list);
lnk_write_data_list_to_file_path(config->imp_lib_name, str8_zero(), lib_list);
lnk_timer_end(LNK_Timer_Lib);
ProfEnd();
diff --git a/src/linker/lnk.h b/src/linker/lnk.h
index 2a1b1808..89842710 100644
--- a/src/linker/lnk.h
+++ b/src/linker/lnk.h
@@ -31,27 +31,6 @@
// PE_TLSHeader32 or PE_TLSHeader64, according to machine type.
#define LNK_TLS_SYMBOL_NAME "_tls_used"
-// --- Default Section Flags --------------------------------------------------
-
-#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CntCode|COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead)
-#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
-#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead)
-#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CntUninitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
-#define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
-#define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
-#define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
-#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
-#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
-#define LNK_XDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_PDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_EDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GFIDS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GIATS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GLJMP_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GEHCONT_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
-#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
-
// --- Base Reloc --------------------------------------------------------------
typedef struct LNK_BaseRelocPage
diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c
index 7df1713a..632147b9 100644
--- a/src/linker/lnk_config.c
+++ b/src/linker/lnk_config.c
@@ -801,6 +801,122 @@ lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameLis
return 0;
}
+internal B32
+lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out)
+{
+ ProfBeginFunction();
+ Temp scratch = scratch_begin(&arena, 1);
+ B32 is_parsed = 0;
+
+ // parse "alias=name"
+ String8 name = {0};
+ String8 alias = {0};
+ String8List flags = {0};
+ {
+ String8List alias_name_split = str8_split_by_string_chars(scratch.arena, directive.first->string, str8_lit("="), 0);
+ if (alias_name_split.node_count == 2) {
+ alias = alias_name_split.first->string;
+ name = alias_name_split.last->string;
+ } else if (alias_name_split.node_count == 1) {
+ name = alias_name_split.first->string;
+ } else {
+ String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
+ lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
+ goto exit;
+ }
+
+ flags = directive;
+ str8_list_pop_front(&flags);
+ }
+
+ // discard alias to itself
+ if (str8_match(name, alias, 0)) {
+ alias = str8_zero();
+ }
+
+ // does directive have ordinal?
+ U16 ordinal16 = 0;
+ String8 ordinal = {0};
+ String8 noname_flag = {0};
+ if (str8_match(str8_prefix(str8_list_first(&flags), 1), str8_lit("@"), 0)) {
+ // parse ordinal
+ ordinal = str8_skip(str8_list_pop_front(&flags)->string, 1);
+ if (str8_is_integer(ordinal, 10)) {
+ U64 ordinal64 = u64_from_str8(ordinal, 10);
+ if (ordinal64 <= max_U16) {
+ ordinal16 = (U16)ordinal64;
+ } else {
+ String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
+ lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "ordinal value must fit into 16-bit integer, \"/EXPORT:%S\"", d);
+ goto exit;
+ }
+ } else {
+ String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
+ lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
+ goto exit;
+ }
+
+ // detect NONAME flag
+ if (str8_match(str8_list_first(&flags), str8_lit("NONAME"), StringMatchFlag_CaseInsensitive)) {
+ noname_flag = str8_list_pop_front(&flags)->string;
+ }
+ }
+
+ // detect PRIVATE flag
+ String8 private_flag = {0};
+ if (str8_match(str8_list_first(&flags), str8_lit("PRIVATE"), StringMatchFlag_CaseInsensitive)) {
+ private_flag = str8_list_pop_front(&flags)->string;
+ }
+
+ // parse export type
+ COFF_ImportType type = COFF_ImportHeader_Code;
+ if (flags.node_count) {
+ type = coff_import_header_type_from_string(str8_list_pop_front(&flags)->string);
+ if (type == COFF_ImportType_Invalid) {
+ String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
+ lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
+ goto exit;
+ }
+ }
+
+ // are there leftover nodes?
+ if (flags.node_count != 0) {
+ String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
+ lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
+ goto exit;
+ }
+
+ // fill out export
+ export_out->obj_path = obj_path;
+ export_out->lib_path = lib_path;
+ export_out->name = push_str8_copy(arena, name);
+ export_out->alias = push_str8_copy(arena, alias);
+ export_out->type = type;
+ export_out->ordinal = ordinal16;
+ export_out->is_ordinal_assigned = ordinal.size > 0;
+ export_out->is_noname_present = noname_flag.size > 0;
+ export_out->is_private = private_flag.size > 0;
+ export_out->is_forwarder = str8_find_needle(name, 0, str8_lit("."), 0) < name.size;
+
+ is_parsed = 1;
+
+exit:;
+ scratch_end(scratch);
+ ProfEnd();
+ return is_parsed;
+}
+
+internal B32
+lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out)
+{
+ Temp scratch = scratch_begin(&arena, 1);
+ String8List split_directive = str8_split_by_string_chars(scratch.arena, directive, str8_lit(","), 0);
+ B32 is_parsed = lnk_parse_export_directive_ex(arena, split_directive, obj_path, lib_path, export_out);
+ scratch_end(scratch);
+ return is_parsed;
+}
+
+
internal LNK_MergeDirectiveNode *
lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data)
{
@@ -1062,9 +1178,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_Export: {
- LNK_ExportParse export_parse = {0};
+ PE_ExportParse export_parse = {0};
if (lnk_parse_export_directive_ex(arena, value_strings, obj_path, lib_path, &export_parse)) {
- lnk_export_parse_list_push(arena, &config->export_symbol_list, export_parse);
+ pe_export_parse_list_push(arena, &config->export_symbol_list, export_parse);
}
} break;
diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h
index 20946905..d139cf2d 100644
--- a/src/linker/lnk_config.h
+++ b/src/linker/lnk_config.h
@@ -336,7 +336,7 @@ typedef struct LNK_Config
LNK_TypeNameHashMode pdb_hash_type_names;
String8 pdb_hash_type_name_map;
U64 pdb_hash_type_name_length;
- LNK_ExportParseList export_symbol_list;
+ PE_ExportParseList export_symbol_list;
String8List input_list[LNK_Input_Count];
String8List input_default_lib_list;
String8List disallow_lib_list;
@@ -559,6 +559,9 @@ internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_
internal B32 lnk_parse_alt_name_directive (Arena *arena, String8 input, LNK_AltNameList *list_out);
internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out);
+internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out);
+internal B32 lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out);
+
internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data);
internal B32 lnk_parse_merge_directive(String8 string, LNK_MergeDirective *parse_out);
diff --git a/src/linker/lnk_debug_helper.c b/src/linker/lnk_debug_helper.c
index 3e964c76..b4190db4 100644
--- a/src/linker/lnk_debug_helper.c
+++ b/src/linker/lnk_debug_helper.c
@@ -36,4 +36,43 @@ lnk_make_debug_s(Arena *arena, CV_SymbolList symbol_list)
return debug_s_data;
}
+internal String8
+lnk_make_linker_debug_symbols(Arena *arena, COFF_MachineType machine)
+{
+ Temp scratch = scratch_begin(&arena, 1);
+ CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
+ String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
+ cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
+ String8 debug_symbols = lnk_make_debug_s(arena, symbol_list);
+ scratch_end(scratch);
+ return debug_symbols;
+}
+
+internal String8
+lnk_make_dll_import_debug_symbols(Arena *arena, COFF_MachineType machine, String8 dll_name)
+{
+ Temp scratch = scratch_begin(&arena,1);
+
+ CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
+
+ // S_OBJ
+ String8 obj_data = cv_make_obj_name(scratch.arena, dll_name, 0);
+ cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_OBJNAME, obj_data);
+
+ // S_COMPILE3
+ String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
+ cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
+
+ // S_END
+ cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_END, str8_zero());
+
+ // TODO: add thunks
+
+ // serialize symbols
+ String8 debug_symbols = lnk_make_debug_s(arena, symbol_list);
+
+ scratch_end(scratch);
+ return debug_symbols;
+}
+
diff --git a/src/linker/lnk_export_table.c b/src/linker/lnk_export_table.c
deleted file mode 100644
index e3866ab9..00000000
--- a/src/linker/lnk_export_table.c
+++ /dev/null
@@ -1,451 +0,0 @@
-// Copyright (c) 2025 Epic Games Tools
-// Licensed under the MIT license (https://opensource.org/license/mit/)
-
-internal String8
-lnk_name_from_export_parse(LNK_ExportParse *exp)
-{
- String8 name;
- if (exp->is_forwarder) {
- name = exp->alias;
- } else if (exp->alias.size) {
- name = exp->alias;
- } else {
- name = exp->name;
- }
- return name;
-}
-
-internal B32
-lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, LNK_ExportParse *export_out)
-{
- ProfBeginFunction();
- Temp scratch = scratch_begin(&arena, 1);
- B32 is_parsed = 0;
-
- // parse "alias=name"
- String8 name = {0};
- String8 alias = {0};
- String8List flags = {0};
- {
- String8List alias_name_split = str8_split_by_string_chars(scratch.arena, directive.first->string, str8_lit("="), 0);
- if (alias_name_split.node_count == 2) {
- alias = alias_name_split.first->string;
- name = alias_name_split.last->string;
- } else if (alias_name_split.node_count == 1) {
- name = alias_name_split.first->string;
- } else {
- String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
- lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
- goto exit;
- }
-
- flags = directive;
- str8_list_pop_front(&flags);
- }
-
- // discard alias to itself
- if (str8_match(name, alias, 0)) {
- alias = str8_zero();
- }
-
- // does directive have ordinal?
- U16 ordinal16 = 0;
- String8 ordinal = {0};
- String8 noname_flag = {0};
- if (str8_match(str8_prefix(str8_list_first(&flags), 1), str8_lit("@"), 0)) {
- // parse ordinal
- ordinal = str8_skip(str8_list_pop_front(&flags)->string, 1);
- if (str8_is_integer(ordinal, 10)) {
- U64 ordinal64 = u64_from_str8(ordinal, 10);
- if (ordinal64 <= max_U16) {
- ordinal16 = (U16)ordinal64;
- } else {
- String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
- lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "ordinal value must fit into 16-bit integer, \"/EXPORT:%S\"", d);
- goto exit;
- }
- } else {
- String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
- lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
- goto exit;
- }
-
- // detect NONAME flag
- if (str8_match(str8_list_first(&flags), str8_lit("NONAME"), StringMatchFlag_CaseInsensitive)) {
- noname_flag = str8_list_pop_front(&flags)->string;
- }
- }
-
- // detect PRIVATE flag
- String8 private_flag = {0};
- if (str8_match(str8_list_first(&flags), str8_lit("PRIVATE"), StringMatchFlag_CaseInsensitive)) {
- private_flag = str8_list_pop_front(&flags)->string;
- }
-
- // parse export type
- COFF_ImportType type = COFF_ImportHeader_Code;
- if (flags.node_count) {
- type = coff_import_header_type_from_string(str8_list_pop_front(&flags)->string);
- if (type == COFF_ImportType_Invalid) {
- String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
- lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
- goto exit;
- }
- }
-
- // are there leftover nodes?
- if (flags.node_count != 0) {
- String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
- lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
- goto exit;
- }
-
- // fill out export
- export_out->obj_path = obj_path;
- export_out->lib_path = lib_path;
- export_out->name = push_str8_copy(arena, name);
- export_out->alias = push_str8_copy(arena, alias);
- export_out->type = type;
- export_out->ordinal = ordinal16;
- export_out->is_ordinal_assigned = ordinal.size > 0;
- export_out->is_noname_present = noname_flag.size > 0;
- export_out->is_private = private_flag.size > 0;
- export_out->is_forwarder = str8_find_needle(name, 0, str8_lit("."), 0) < name.size;
-
- is_parsed = 1;
-
-exit:;
- scratch_end(scratch);
- ProfEnd();
- return is_parsed;
-}
-
-internal B32
-lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, LNK_ExportParse *export_out)
-{
- Temp scratch = scratch_begin(&arena, 1);
- String8List split_directive = str8_split_by_string_chars(scratch.arena, directive, str8_lit(","), 0);
- B32 is_parsed = lnk_parse_export_directive_ex(arena, split_directive, obj_path, lib_path, export_out);
- scratch_end(scratch);
- return is_parsed;
-}
-
-internal LNK_ExportParsePtrArray
-lnk_array_from_export_list(Arena *arena, LNK_ExportParseList list)
-{
- LNK_ExportParsePtrArray result = {0};
- result.v = push_array_no_zero(arena, LNK_ExportParse *, list.count);
- for (LNK_ExportParseNode *exp = list.first; exp != 0; exp = exp->next) {
- result.v[result.count++] = &exp->data;
- }
- return result;
-}
-
-internal void
-lnk_export_parse_list_push_node(LNK_ExportParseList *list, LNK_ExportParseNode *node)
-{
- SLLQueuePush(list->first, list->last, node);
- list->count += 1;
-}
-
-internal LNK_ExportParseNode *
-lnk_export_parse_list_push(Arena *arena, LNK_ExportParseList *list, LNK_ExportParse data)
-{
- LNK_ExportParseNode *node = push_array(arena, LNK_ExportParseNode, 1);
- node->data = data;
- lnk_export_parse_list_push_node(list, node);
- return node;
-}
-
-internal void
-lnk_export_parse_list_concat_in_place(LNK_ExportParseList *list, LNK_ExportParseList *to_concat)
-{
- SLLConcatInPlace(list, to_concat);
-}
-
-internal int
-lnk_named_export_is_before(void *raw_a, void *raw_b)
-{
- LNK_ExportParse *a = *(LNK_ExportParse **)raw_a;
- LNK_ExportParse *b = *(LNK_ExportParse **)raw_b;
- int cmp = str8_compar_case_sensitive(&a->name, &b->name);
- return cmp < 0;
-}
-
-internal int
-lnk_ordinal_export_is_before(void *raw_a, void *raw_b)
-{
- LNK_ExportParse *a = raw_a;
- LNK_ExportParse *b = raw_b;
- return a->ordinal < b->ordinal;
-}
-
-internal String8
-lnk_make_edata_obj(Arena *arena,
- LNK_SymbolTable *symtab,
- String8 image_name,
- COFF_MachineType machine,
- LNK_ExportParseList export_list)
-{
- Temp scratch = scratch_begin(&arena, 1);
-
- // compute max ordinal and used ordinal flag array
- U64 ordinal_low = max_U64;
- B8 *is_ordinal_used = push_array(arena, B8, max_U16);
- for (LNK_ExportParseNode *exp_n = export_list.first; exp_n != 0; exp_n = exp_n->next) {
- LNK_ExportParse *exp = &exp_n->data;
- if (exp->is_ordinal_assigned) {
- ordinal_low = Min(ordinal_low, exp->ordinal);
- is_ordinal_used[exp->ordinal] = 1;
- }
- }
-
- LNK_ExportParsePtrArray named_exports = {0};
- LNK_ExportParsePtrArray noname_exports = {0};
- LNK_ExportParsePtrArray forwarder_exports = {0};
- {
- // group exports based on flags
- LNK_ExportParseList named_exports_list = {0};
- LNK_ExportParseList noname_exports_list = {0};
- LNK_ExportParseList forwarder_exports_list = {0};
- for (LNK_ExportParseNode *exp_n = export_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) {
- exp_n_next = exp_n->next;
- if (exp_n->data.is_forwarder) {
- lnk_export_parse_list_push_node(&forwarder_exports_list, exp_n);
- } else if (exp_n->data.is_noname_present) {
- AssertAlways(exp_n->data.is_ordinal_assigned);
- lnk_export_parse_list_push_node(&noname_exports_list, exp_n);
- } else {
- lnk_export_parse_list_push_node(&named_exports_list, exp_n);
- }
- }
-
- // list -> array
- named_exports = lnk_array_from_export_list(scratch.arena, named_exports_list);
- noname_exports = lnk_array_from_export_list(scratch.arena, noname_exports_list);
- forwarder_exports = lnk_array_from_export_list(scratch.arena, forwarder_exports_list);
-
- // sort exports
- radsort(named_exports.v, named_exports.count, lnk_named_export_is_before);
- radsort(noname_exports.v, noname_exports.count, lnk_ordinal_export_is_before);
- radsort(forwarder_exports.v, forwarder_exports.count, lnk_named_export_is_before);
-
- MemoryZeroStruct(&export_list);
- lnk_export_parse_list_concat_in_place(&export_list, &named_exports_list);
- lnk_export_parse_list_concat_in_place(&export_list, &forwarder_exports_list);
- lnk_export_parse_list_concat_in_place(&export_list, &noname_exports_list);
- }
-
- // assign omitted ordinals
- {
- U16 last_ordinal = ordinal_low;
- for (U64 exp_idx = 0; exp_idx < named_exports.count; exp_idx += 1) {
- LNK_ExportParse *exp = named_exports.v[exp_idx];
- if (!exp->is_ordinal_assigned) {
- for (; last_ordinal < max_U16 && is_ordinal_used[last_ordinal] != 0; last_ordinal += 1);
- exp->ordinal = last_ordinal;
- exp->is_ordinal_assigned = 1;
- is_ordinal_used[last_ordinal] = 1;
- }
- }
- for (U64 exp_idx = 0; exp_idx < forwarder_exports.count; exp_idx += 1) {
- LNK_ExportParse *exp = forwarder_exports.v[exp_idx];
- if (!exp->is_ordinal_assigned) {
- for (; last_ordinal < max_U16 && is_ordinal_used[last_ordinal] != 0; last_ordinal += 1);
- exp->ordinal = last_ordinal;
- exp->is_ordinal_assigned = 1;
- is_ordinal_used[last_ordinal] = 1;
- }
- }
- for (U64 exp_idx = 0; exp_idx < noname_exports.count; exp_idx += 1) {
- LNK_ExportParse *exp = noname_exports.v[exp_idx];
- if (!exp->is_ordinal_assigned) {
- exp->ordinal = last_ordinal;
- exp->is_ordinal_assigned = 1;
- is_ordinal_used[last_ordinal] = 1;
- }
- }
- }
-
- COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, machine);
-
- // push sections
- COFF_ObjSection *voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$2"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
- COFF_ObjSection *name_voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$3"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
- COFF_ObjSection *ordinal_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$4"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
- COFF_ObjSection *string_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$5"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
- COFF_ObjSection *image_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$6"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, push_cstr(obj_writer->arena, image_name));
-
- ProfBegin("Virtual Offset Table");
- {
- B8 *is_ordinal_bound = push_array(scratch.arena, B8, max_U16);
- LNK_ExportParsePtrArray *all_exports[] = { &named_exports, &forwarder_exports, &noname_exports };
-
- for (U64 arr_idx = 0; arr_idx < ArrayCount(all_exports); arr_idx += 1) {
- for (U64 exp_idx = 0; exp_idx < all_exports[arr_idx]->count; exp_idx += 1) {
- LNK_ExportParse *exp = all_exports[arr_idx]->v[exp_idx];
- if (is_ordinal_bound[exp->ordinal] == 0) {
- // alloc only one slot per ordinal, so it's possible to map ordinal to a virtual offset
- is_ordinal_bound[exp->ordinal] = 1;
-
- // create slot for the ordinal virtual offset
- U64 voff_offset = voff_table_sect->data.total_size;
- U32 *voff = push_array(obj_writer->arena, U32, 1);
- str8_list_push(obj_writer->arena, &voff_table_sect->data, str8_struct(voff));
-
- COFF_ObjSymbol *exp_symbol;
- if (exp->is_forwarder) {
- U64 forwarder_name_offset = string_table_sect->data.total_size;
- String8 forwarder_name_cstr = push_cstr(obj_writer->arena, exp->name);
- str8_list_push(obj_writer->arena, &string_table_sect->data, forwarder_name_cstr);
- // symbol to the name string
- exp_symbol = coff_obj_writer_push_symbol_static(obj_writer, exp->name, forwarder_name_offset, string_table_sect);
- } else {
- // function or global var symbol
- exp_symbol = coff_obj_writer_push_symbol_undef(obj_writer, exp->name);
- }
-
- U16 ordinal_nb = exp->ordinal - ordinal_low;
- coff_obj_writer_section_push_reloc(obj_writer, voff_table_sect, ordinal_nb*sizeof(U32), exp_symbol, coff_virt_off_reloc_from_machine(machine));
- }
- }
- }
- }
- ProfEnd();
-
- ProfBegin("Named & Forwarder Exports");
- {
- LNK_ExportParsePtrArray *exports_with_names[] = { &named_exports, &forwarder_exports };
-
- // assign hints
- for (U64 arr_idx = 0, hint = 0; arr_idx < ArrayCount(exports_with_names); arr_idx += 1) {
- for (U64 exp_idx = 0; exp_idx < exports_with_names[arr_idx]->count; exp_idx += 1, hint += 1) {
- LNK_ExportParse *exp = exports_with_names[arr_idx]->v[exp_idx];
- exp->hint = hint;
- }
- }
-
- for (U64 arr_idx = 0; arr_idx < ArrayCount(exports_with_names); arr_idx += 1) {
- LNK_ExportParsePtrArray *exports = exports_with_names[arr_idx];
- for (U64 exp_idx = 0; exp_idx < exports->count; exp_idx += 1) {
- LNK_ExportParse *exp = exports->v[exp_idx];
-
- String8 name = lnk_name_from_export_parse(exp);
-
- // store symbol name string
- U64 export_name_offset = string_table_sect->data.total_size;
- String8 export_name_cstr = push_cstr(obj_writer->arena, name);
- str8_list_push(obj_writer->arena, &string_table_sect->data, export_name_cstr);
-
- // create symbol for the name string
- String8 export_name_symbol_name = push_str8f(obj_writer->arena, "RAD_NAME:%S", name);
- COFF_ObjSymbol *export_name_symbol = coff_obj_writer_push_symbol_extern(obj_writer, export_name_symbol_name, export_name_offset, string_table_sect);
-
- // create slot for export virtual offset
- U64 export_name_voff_offset = name_voff_table_sect->data.total_size;
- U8 *export_name_voff = push_array(obj_writer->arena, U8, sizeof(U32));
- str8_list_push(obj_writer->arena, &name_voff_table_sect->data, str8_array(export_name_voff, sizeof(U32)));
-
- // write string's virtual offset
- coff_obj_writer_section_push_reloc(obj_writer, name_voff_table_sect, export_name_voff_offset, export_name_symbol, coff_virt_off_reloc_from_machine(machine));
-
- // create and store export's ordinal
- U16 *ordinal = push_array(obj_writer->arena, U16, 1);
- *ordinal = exp->ordinal - ordinal_low;
- str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
- }
- }
- }
- ProfEnd();
-
- ProfBegin("NONAME Exports");
- {
- for (U64 exp_idx = 0; exp_idx < noname_exports.count; exp_idx += 1) {
- // create and store export's ordinal
- LNK_ExportParse *exp = noname_exports.v[exp_idx];
- U16 *ordinal = push_array(obj_writer->arena, U16, 1);
- *ordinal = exp->ordinal - ordinal_low;
- str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
- }
- }
- ProfEnd();
-
- // fill out export table header
- PE_ExportTableHeader *header = push_array(obj_writer->arena, PE_ExportTableHeader, 1);
- header->time_stamp = COFF_TimeStamp_Max;
- header->ordinal_base = safe_cast_u16(ordinal_low);
- header->export_address_table_count = safe_cast_u32(voff_table_sect->data.node_count);
- header->name_pointer_table_count = safe_cast_u32(name_voff_table_sect->data.node_count);
-
- // push header field's symbols
- COFF_ObjSymbol *image_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_NAME_VOFF"), 0, image_name_sect);
- COFF_ObjSymbol *address_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_ADDRESS_TABLE_VOFF"), 0, voff_table_sect);
- COFF_ObjSymbol *name_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_NAME_POINTER_VOFF"), 0, name_voff_table_sect);
- COFF_ObjSymbol *ordinal_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_ORDINAL_TABLE_VOFF"), 0, ordinal_table_sect);
-
- // push export table header section
- COFF_ObjSection *header_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$1"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_struct(header));
- coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_HEADER"), 0, header_sect);
-
- // patch export table header
- COFF_RelocType virt_off_reloc_type = coff_virt_off_reloc_from_machine(machine);
- coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_voff), image_name_symbol, virt_off_reloc_type);
- coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, export_address_table_voff), address_table_symbol, virt_off_reloc_type);
- coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_pointer_table_voff), name_table_symbol, virt_off_reloc_type);
- coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, ordinal_table_voff), ordinal_table_symbol, virt_off_reloc_type);
-
- String8 obj = coff_obj_writer_serialize(arena, obj_writer);
- coff_obj_writer_release(&obj_writer);
-
- os_write_data_to_file_path(str8_lit("foo.obj"), obj);
-
- scratch_end(scratch);
- return obj;
-}
-
-internal String8List
-lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ExportParseList export_list)
-{
- ProfBeginFunction();
- Temp scratch = scratch_begin(&arena, 1);
-
- dll_name = str8_skip_last_slash(dll_name);
-
- // These objects appear in first three members of any lib that linker produces with /dll.
- // Objects are used by MSVC linker to build import table.
- String8 import_entry_obj = lnk_build_import_entry_obj(scratch.arena, dll_name, time_stamp, machine);
- String8 null_import_descriptor_obj = lnk_build_null_import_descriptor_obj(scratch.arena, time_stamp, machine);
- String8 null_thunk_data_obj = lnk_build_null_thunk_data_obj(scratch.arena, dll_name, time_stamp, machine);
-
- COFF_LibWriter *lib_writer = coff_lib_writer_alloc();
-
- // push import table nulls
- coff_lib_writer_push_obj(lib_writer, dll_name, import_entry_obj);
- coff_lib_writer_push_obj(lib_writer, dll_name, null_import_descriptor_obj);
- coff_lib_writer_push_obj(lib_writer, dll_name, null_thunk_data_obj);
-
- // push exports
- for (LNK_ExportParseNode *exp_n = export_list.first; exp_n != 0; exp_n = exp_n->next) {
- LNK_ExportParse *exp = &exp_n->data;
- if (exp->is_noname_present) {
- coff_lib_writer_push_export_by_ordinal(lib_writer, machine, time_stamp, dll_name, exp->type, exp->ordinal);
- } else {
- String8 name = lnk_name_from_export_parse(exp);
- COFF_LibWriterSymbolNode *member_symbol = coff_lib_writer_push_export_by_name(lib_writer, machine, time_stamp, dll_name, exp->type, name, exp->hint);
-
- COFF_LibWriterSymbol imp_symbol = {0};
- imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
- imp_symbol.member_idx = member_symbol->data.member_idx;
- coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
- }
- }
-
- // serialize lib
- String8List lib = coff_lib_writer_serialize(arena, lib_writer, COFF_TimeStamp_Max, 0, /* emit second member: */ 1);
- coff_lib_writer_release(&lib_writer);
-
- scratch_end(scratch);
- ProfEnd();
- return lib;
-}
-
diff --git a/src/linker/lnk_export_table.h b/src/linker/lnk_export_table.h
deleted file mode 100644
index 78474d61..00000000
--- a/src/linker/lnk_export_table.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2025 Epic Games Tools
-// Licensed under the MIT license (https://opensource.org/license/mit/)
-
-#pragma once
-
-typedef struct LNK_ExportParse
-{
- String8 obj_path;
- String8 lib_path;
- String8 name;
- String8 alias;
- COFF_ImportType type;
- U16 ordinal;
- U16 hint;
- B32 is_ordinal_assigned;
- B32 is_noname_present;
- B32 is_private;
- B32 is_forwarder;
-} LNK_ExportParse;
-
-typedef struct LNK_ExportParseNode
-{
- LNK_ExportParse data;
- struct LNK_ExportParseNode *next;
-} LNK_ExportParseNode;
-
-typedef struct LNK_ExportParseList
-{
- U64 count;
- LNK_ExportParseNode *first;
- LNK_ExportParseNode *last;
-} LNK_ExportParseList;
-
-typedef struct LNK_ExportParsePtrArray
-{
- U64 count;
- LNK_ExportParse **v;
-} LNK_ExportParsePtrArray;
-
-////////////////////////////////
-
-internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, LNK_ExportParse *export_out);
-internal B32 lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, LNK_ExportParse *parse_out);
-internal LNK_ExportParsePtrArray lnk_array_from_export_list(Arena *arena, LNK_ExportParseList list);
-internal LNK_ExportParseNode * lnk_export_parse_list_push(Arena *arena, LNK_ExportParseList *list, LNK_ExportParse data);
-internal String8List lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ExportParseList export_list);
diff --git a/src/linker/lnk_image_section_flags.h b/src/linker/lnk_image_section_flags.h
deleted file mode 100644
index a237d7ce..00000000
--- a/src/linker/lnk_image_section_flags.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2025 Epic Games Tools
-// Licensed under the MIT license (https://opensource.org/license/mit/)
-
-#pragma once
-
-// --- Default Section Flags --------------------------------------------------
-
-#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CntCode|COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead)
-#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
-#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead)
-#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CntUninitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
-#define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
-#define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
-#define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
-#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
-#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
-#define LNK_XDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_PDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_EDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GFIDS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GIATS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GLJMP_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_GEHCONT_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
-#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
-#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
-
diff --git a/src/linker/lnk_import_table.h b/src/linker/lnk_import_table.h
deleted file mode 100644
index 6dcd300b..00000000
--- a/src/linker/lnk_import_table.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2025 Epic Games Tools
-// Licensed under the MIT license (https://opensource.org/license/mit/)
-
-#pragma once
-
-typedef struct LNK_ImportFunc
-{
- struct LNK_ImportFunc *next;
- struct LNK_Symbol *symbol;
-} LNK_ImportFunc;
-
-typedef struct LNK_ImportDLL
-{
- struct LNK_ImportDLL *next;
- struct LNK_ImportFunc *first_func;
- struct LNK_ImportFunc *last_func;
- String8 name;
-} LNK_ImportDLL;
-
-typedef struct LNK_ImportTable
-{
- Arena *arena;
- LNK_ImportDLL *first_dll;
- LNK_ImportDLL *last_dll;
- U64 dll_count;
- HashTable *dll_ht;
-} LNK_ImportTable;
-
-////////////////////////////////
-
-internal LNK_ImportTable * lnk_import_table_alloc(void);
-internal void lnk_import_table_release(LNK_ImportTable **imptab_ptr);
-internal LNK_ImportDLL * lnk_import_table_push_dll(LNK_ImportTable *imptab, String8 dll_name, COFF_MachineType machine);
-internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 dll_name);
-internal LNK_ImportFunc * lnk_import_table_push_func(LNK_ImportTable *imptab, LNK_ImportDLL *dll, struct LNK_Symbol *symbol);
-
-internal COFF_ObjSymbol * lnk_emit_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name);
-internal COFF_ObjSymbol * lnk_emit_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *imp_addr_ptr, COFF_ObjSymbol *tail_merge, String8 func_name);
-internal COFF_ObjSymbol * lnk_emit_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, String8 dll_name, COFF_ObjSymbol *dll_import_descriptor);
-
-internal String8 lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine);
-internal String8 lnk_build_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine);
-internal String8 lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine);
-
-internal void lnk_emit_dll_import_debug_symbols(COFF_ObjWriter *obj_writer, String8 dll_name);
-internal String8 lnk_obj_from_import_dll_static(Arena *arena, COFF_MachineType machine, LNK_ImportDLL *dll);
-internal String8 lnk_obj_from_import_dll_delayed(Arena *arena, COFF_MachineType machine, LNK_ImportDLL *dll, B32 emit_biat, B32 emit_uiat);
-
-internal String8Array lnk_make_import_dlls_static(Arena *arena, LNK_ImportTable *imptab, COFF_MachineType machine, String8 image_name);
-internal String8Array lnk_make_import_dlls_delayed(Arena *arena, LNK_ImportTable *imptab, COFF_MachineType machine, String8 image_name, B32 emit_biat, B32 emit_uiat);
-
diff --git a/src/natvis/base.natvis b/src/natvis/base.natvis
index 644b583c..ce938f33 100644
--- a/src/natvis/base.natvis
+++ b/src/natvis/base.natvis
@@ -151,6 +151,8 @@
+
+
{{ count={count} first={first} }}
- count
diff --git a/src/pe/pe_make_export_table.c b/src/pe/pe_make_export_table.c
new file mode 100644
index 00000000..e4d37e02
--- /dev/null
+++ b/src/pe/pe_make_export_table.c
@@ -0,0 +1,343 @@
+// Copyright (c) 2025 Epic Games Tools
+// Licensed under the MIT license (https://opensource.org/license/mit/)
+
+internal String8
+pe_name_from_export_parse(PE_ExportParse *exp)
+{
+ String8 name;
+ if (exp->is_forwarder) {
+ name = exp->alias;
+ } else if (exp->alias.size) {
+ name = exp->alias;
+ } else {
+ name = exp->name;
+ }
+ return name;
+}
+
+internal PE_ExportParsePtrArray
+pe_array_from_export_list(Arena *arena, PE_ExportParseList list)
+{
+ PE_ExportParsePtrArray result = {0};
+ result.v = push_array_no_zero(arena, PE_ExportParse *, list.count);
+ for (PE_ExportParseNode *exp = list.first; exp != 0; exp = exp->next) {
+ result.v[result.count++] = &exp->data;
+ }
+ return result;
+}
+
+internal void
+pe_export_parse_list_push_node(PE_ExportParseList *list, PE_ExportParseNode *node)
+{
+ SLLQueuePush(list->first, list->last, node);
+ list->count += 1;
+}
+
+internal PE_ExportParseNode *
+pe_export_parse_list_push(Arena *arena, PE_ExportParseList *list, PE_ExportParse data)
+{
+ PE_ExportParseNode *node = push_array(arena, PE_ExportParseNode, 1);
+ node->data = data;
+ pe_export_parse_list_push_node(list, node);
+ return node;
+}
+
+internal void
+pe_export_parse_list_concat_in_place(PE_ExportParseList *list, PE_ExportParseList *to_concat)
+{
+ if (to_concat->count) {
+ if (list->count) {
+ list->last->next = to_concat->first;
+ list->last = to_concat->last;
+ } else {
+ list->first = to_concat->first;
+ list->last = to_concat->last;
+ }
+ list->count += to_concat->count;
+ MemoryZeroStruct(to_concat);
+ }
+}
+
+internal int
+pe_named_export_is_before(void *raw_a, void *raw_b)
+{
+ PE_ExportParse *a = *(PE_ExportParse **)raw_a;
+ PE_ExportParse *b = *(PE_ExportParse **)raw_b;
+ int cmp = str8_compar_case_sensitive(&a->name, &b->name);
+ return cmp < 0;
+}
+
+internal int
+pe_ordinal_export_is_before(void *raw_a, void *raw_b)
+{
+ PE_ExportParse *a = raw_a;
+ PE_ExportParse *b = raw_b;
+ return a->ordinal < b->ordinal;
+}
+
+internal PE_FinalizedExports
+pe_finalize_export_list(Arena *arena, PE_ExportParseList export_list)
+{
+ // compute max ordinal and used ordinal flag array
+ U64 ordinal_low = max_U64;
+ B8 *is_ordinal_used = push_array(arena, B8, max_U16);
+ for (PE_ExportParseNode *exp_n = export_list.first; exp_n != 0; exp_n = exp_n->next) {
+ PE_ExportParse *exp = &exp_n->data;
+ if (exp->is_ordinal_assigned) {
+ ordinal_low = Min(ordinal_low, exp->ordinal);
+ is_ordinal_used[exp->ordinal] = 1;
+ }
+ }
+
+ PE_ExportParsePtrArray named_exports = {0};
+ PE_ExportParsePtrArray ordinal_exports = {0};
+ PE_ExportParsePtrArray forwarder_exports = {0};
+ {
+ // group exports based on flags
+ PE_ExportParseList named_exports_list = {0};
+ PE_ExportParseList ordinal_exports_list = {0};
+ PE_ExportParseList forwarder_exports_list = {0};
+ for (PE_ExportParseNode *exp_n = export_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) {
+ exp_n_next = exp_n->next;
+ if (exp_n->data.is_forwarder) {
+ pe_export_parse_list_push_node(&forwarder_exports_list, exp_n);
+ } else if (exp_n->data.is_noname_present) {
+ AssertAlways(exp_n->data.is_ordinal_assigned);
+ pe_export_parse_list_push_node(&ordinal_exports_list, exp_n);
+ } else {
+ pe_export_parse_list_push_node(&named_exports_list, exp_n);
+ }
+ }
+
+ // list -> array
+ named_exports = pe_array_from_export_list(arena, named_exports_list);
+ forwarder_exports = pe_array_from_export_list(arena, forwarder_exports_list);
+ ordinal_exports = pe_array_from_export_list(arena, ordinal_exports_list);
+
+ // sort exports
+ radsort(named_exports.v, named_exports.count, pe_named_export_is_before);
+ radsort(ordinal_exports.v, ordinal_exports.count, pe_ordinal_export_is_before);
+ radsort(forwarder_exports.v, forwarder_exports.count, pe_named_export_is_before);
+
+ MemoryZeroStruct(&export_list);
+ pe_export_parse_list_concat_in_place(&export_list, &named_exports_list);
+ pe_export_parse_list_concat_in_place(&export_list, &forwarder_exports_list);
+ pe_export_parse_list_concat_in_place(&export_list, &ordinal_exports_list);
+ }
+
+ // assign omitted ordinals
+ {
+ U16 last_ordinal = ordinal_low;
+ for (U64 exp_idx = 0; exp_idx < named_exports.count; exp_idx += 1) {
+ PE_ExportParse *exp = named_exports.v[exp_idx];
+ if (!exp->is_ordinal_assigned) {
+ for (; last_ordinal < max_U16 && is_ordinal_used[last_ordinal] != 0; last_ordinal += 1);
+ exp->ordinal = last_ordinal;
+ exp->is_ordinal_assigned = 1;
+ is_ordinal_used[last_ordinal] = 1;
+ }
+ }
+ for (U64 exp_idx = 0; exp_idx < forwarder_exports.count; exp_idx += 1) {
+ PE_ExportParse *exp = forwarder_exports.v[exp_idx];
+ if (!exp->is_ordinal_assigned) {
+ for (; last_ordinal < max_U16 && is_ordinal_used[last_ordinal] != 0; last_ordinal += 1);
+ exp->ordinal = last_ordinal;
+ exp->is_ordinal_assigned = 1;
+ is_ordinal_used[last_ordinal] = 1;
+ }
+ }
+ for (U64 exp_idx = 0; exp_idx < ordinal_exports.count; exp_idx += 1) {
+ PE_ExportParse *exp = ordinal_exports.v[exp_idx];
+ if (!exp->is_ordinal_assigned) {
+ exp->ordinal = last_ordinal;
+ exp->is_ordinal_assigned = 1;
+ is_ordinal_used[last_ordinal] = 1;
+ }
+ }
+ }
+
+ // assign hints
+ {
+ U64 hint = 0;
+ for (U64 exp_idx = 0; exp_idx < named_exports.count; exp_idx += 1, hint += 1) {
+ named_exports.v[exp_idx]->hint = hint;
+ }
+ for (U64 exp_idx = 0; exp_idx < forwarder_exports.count; exp_idx += 1, hint += 1) {
+ forwarder_exports.v[exp_idx]->hint = hint;
+ }
+ }
+
+ PE_FinalizedExports result = {0};
+ result.named_exports = named_exports;
+ result.forwarder_exports = forwarder_exports;
+ result.ordinal_exports = ordinal_exports;
+
+ return result;
+}
+
+internal String8
+pe_make_edata_obj(Arena *arena,
+ String8 image_name,
+ COFF_TimeStamp time_stamp,
+ COFF_MachineType machine,
+ PE_FinalizedExports finalized_exports)
+{
+ Temp scratch = scratch_begin(&arena, 1);
+
+ COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
+
+ // push sections
+ COFF_ObjSection *voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$2"), PE_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
+ COFF_ObjSection *name_voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$3"), PE_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
+ COFF_ObjSection *ordinal_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$4"), PE_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
+ COFF_ObjSection *string_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$5"), PE_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
+ COFF_ObjSection *image_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$6"), PE_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, push_cstr(obj_writer->arena, image_name));
+
+ ProfBegin("Virtual Offset Table");
+ {
+ B8 *is_ordinal_bound = push_array(scratch.arena, B8, max_U16);
+
+ for (U64 arr_idx = 0; arr_idx < ArrayCount(finalized_exports.all); arr_idx += 1) {
+ for (U64 exp_idx = 0; exp_idx < finalized_exports.all[arr_idx].count; exp_idx += 1) {
+ PE_ExportParse *exp = finalized_exports.all[arr_idx].v[exp_idx];
+ if (is_ordinal_bound[exp->ordinal] == 0) {
+ // alloc only one slot per ordinal, so it's possible to map ordinal to a virtual offset
+ is_ordinal_bound[exp->ordinal] = 1;
+
+ // create slot for the ordinal virtual offset
+ U64 voff_offset = voff_table_sect->data.total_size;
+ U32 *voff = push_array(obj_writer->arena, U32, 1);
+ str8_list_push(obj_writer->arena, &voff_table_sect->data, str8_struct(voff));
+
+ COFF_ObjSymbol *exp_symbol;
+ if (exp->is_forwarder) {
+ U64 forwarder_name_offset = string_table_sect->data.total_size;
+ String8 forwarder_name_cstr = push_cstr(obj_writer->arena, exp->name);
+ str8_list_push(obj_writer->arena, &string_table_sect->data, forwarder_name_cstr);
+ // symbol to the name string
+ exp_symbol = coff_obj_writer_push_symbol_static(obj_writer, exp->name, forwarder_name_offset, string_table_sect);
+ } else {
+ // function or global var symbol
+ exp_symbol = coff_obj_writer_push_symbol_undef(obj_writer, exp->name);
+ }
+
+ U16 ordinal_nb = exp->ordinal - finalized_exports.ordinal_low;
+ coff_obj_writer_section_push_reloc_voff(obj_writer, voff_table_sect, ordinal_nb*sizeof(U32), exp_symbol);
+ }
+ }
+ }
+ }
+ ProfEnd();
+
+ ProfBegin("Named & Forwarder Exports");
+ {
+ for (U64 arr_idx = 0; arr_idx < ArrayCount(finalized_exports.exports_with_names); arr_idx += 1) {
+ PE_ExportParsePtrArray exports = finalized_exports.exports_with_names[arr_idx];
+ for (U64 exp_idx = 0; exp_idx < exports.count; exp_idx += 1) {
+ PE_ExportParse *exp = exports.v[exp_idx];
+
+ String8 name = pe_name_from_export_parse(exp);
+
+ // store symbol name string
+ U64 export_name_offset = string_table_sect->data.total_size;
+ String8 export_name_cstr = push_cstr(obj_writer->arena, name);
+ str8_list_push(obj_writer->arena, &string_table_sect->data, export_name_cstr);
+
+ // create symbol for the name string
+ String8 export_name_symbol_name = push_str8f(obj_writer->arena, "RAD_NAME:%S", name);
+ COFF_ObjSymbol *export_name_symbol = coff_obj_writer_push_symbol_extern(obj_writer, export_name_symbol_name, export_name_offset, string_table_sect);
+
+ // create slot for export virtual offset
+ U64 export_name_voff_offset = name_voff_table_sect->data.total_size;
+ U8 *export_name_voff = push_array(obj_writer->arena, U8, sizeof(U32));
+ str8_list_push(obj_writer->arena, &name_voff_table_sect->data, str8_array(export_name_voff, sizeof(U32)));
+
+ // write string's virtual offset
+ coff_obj_writer_section_push_reloc_voff(obj_writer, name_voff_table_sect, export_name_voff_offset, export_name_symbol);
+
+ // create and store export's ordinal
+ U16 *ordinal = push_array(obj_writer->arena, U16, 1);
+ *ordinal = exp->ordinal - finalized_exports.ordinal_low;
+ str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
+ }
+ }
+ }
+ ProfEnd();
+
+ ProfBegin("Ordinal Exports");
+ {
+ for (U64 exp_idx = 0; exp_idx < finalized_exports.ordinal_exports.count; exp_idx += 1) {
+ // create and store export's ordinal
+ PE_ExportParse *exp = finalized_exports.ordinal_exports.v[exp_idx];
+ U16 *ordinal = push_array(obj_writer->arena, U16, 1);
+ *ordinal = exp->ordinal - finalized_exports.ordinal_low;
+ str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
+ }
+ }
+ ProfEnd();
+
+ // fill out export table header
+ PE_ExportTableHeader *header = push_array(obj_writer->arena, PE_ExportTableHeader, 1);
+ header->time_stamp = time_stamp;
+ header->ordinal_base = safe_cast_u16(finalized_exports.ordinal_low);
+ header->export_address_table_count = safe_cast_u32(voff_table_sect->data.node_count);
+ header->name_pointer_table_count = safe_cast_u32(name_voff_table_sect->data.node_count);
+
+ // push header field's symbols
+ COFF_ObjSymbol *image_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_NAME_VOFF"), 0, image_name_sect);
+ COFF_ObjSymbol *address_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_ADDRESS_TABLE_VOFF"), 0, voff_table_sect);
+ COFF_ObjSymbol *name_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_NAME_POINTER_VOFF"), 0, name_voff_table_sect);
+ COFF_ObjSymbol *ordinal_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_ORDINAL_TABLE_VOFF"), 0, ordinal_table_sect);
+
+ // push export table header section
+ COFF_ObjSection *header_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$1"), PE_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_struct(header));
+ coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_HEADER"), 0, header_sect);
+
+ // patch export table header
+ coff_obj_writer_section_push_reloc_voff(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_voff), image_name_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, export_address_table_voff), address_table_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_pointer_table_voff), name_table_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, ordinal_table_voff), ordinal_table_symbol);
+
+ String8 obj = coff_obj_writer_serialize(arena, obj_writer);
+ coff_obj_writer_release(&obj_writer);
+
+ scratch_end(scratch);
+ return obj;
+}
+
+internal String8List
+pe_make_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, String8 debug_symbols, PE_ExportParseList export_list)
+{
+ ProfBeginFunction();
+
+ COFF_LibWriter *lib_writer = coff_lib_writer_alloc();
+
+ // These objects appear in first three members of any lib that linker produces with /dll.
+ // Objects are used by MSVC linker to build import table.
+ String8 import_entry_obj = pe_make_import_entry_obj(lib_writer->arena, dll_name, time_stamp, machine, debug_symbols);
+ String8 null_import_descriptor_obj = pe_make_null_import_descriptor_obj(lib_writer->arena, time_stamp, machine, debug_symbols);
+ String8 null_thunk_data_obj = pe_make_null_thunk_data_obj(lib_writer->arena, dll_name, time_stamp, machine, debug_symbols);
+
+ // push import table nulls
+ coff_lib_writer_push_obj(lib_writer, dll_name, import_entry_obj);
+ coff_lib_writer_push_obj(lib_writer, dll_name, null_import_descriptor_obj);
+ coff_lib_writer_push_obj(lib_writer, dll_name, null_thunk_data_obj);
+
+ // push exports
+ for (PE_ExportParseNode *exp_n = export_list.first; exp_n != 0; exp_n = exp_n->next) {
+ PE_ExportParse *exp = &exp_n->data;
+ if (exp->is_private) {
+ continue;
+ }
+ String8 name = pe_name_from_export_parse(exp);
+ coff_lib_writer_push_export_by_name(lib_writer, machine, time_stamp, dll_name, exp->type, name, exp->hint);
+ }
+
+ // serialize lib
+ String8List lib = coff_lib_writer_serialize(arena, lib_writer, COFF_TimeStamp_Max, 0, /* emit second member: */ 1);
+ coff_lib_writer_release(&lib_writer);
+
+ ProfEnd();
+ return lib;
+}
diff --git a/src/pe/pe_make_export_table.h b/src/pe/pe_make_export_table.h
new file mode 100644
index 00000000..e5a5e6ad
--- /dev/null
+++ b/src/pe/pe_make_export_table.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2025 Epic Games Tools
+// Licensed under the MIT license (https://opensource.org/license/mit/)
+
+#ifndef PE_MAKE_EXPORT_TABLE_H
+#define PE_MAKE_EXPORT_TABLE_H
+
+typedef struct PE_ExportParse
+{
+ String8 obj_path;
+ String8 lib_path;
+ String8 name;
+ String8 alias;
+ COFF_ImportType type;
+ U16 ordinal;
+ U16 hint;
+ B32 is_ordinal_assigned;
+ B32 is_noname_present;
+ B32 is_private;
+ B32 is_forwarder;
+} PE_ExportParse;
+
+typedef struct PE_ExportParseNode
+{
+ PE_ExportParse data;
+ struct PE_ExportParseNode *next;
+} PE_ExportParseNode;
+
+typedef struct PE_ExportParseList
+{
+ U64 count;
+ PE_ExportParseNode *first;
+ PE_ExportParseNode *last;
+} PE_ExportParseList;
+
+typedef struct PE_ExportParsePtrArray
+{
+ U64 count;
+ PE_ExportParse **v;
+} PE_ExportParsePtrArray;
+
+typedef struct PE_FinalizedExports
+{
+ U64 ordinal_low;
+ union {
+ struct {
+ PE_ExportParsePtrArray named_exports;
+ PE_ExportParsePtrArray forwarder_exports;
+ PE_ExportParsePtrArray ordinal_exports;
+ };
+ PE_ExportParsePtrArray exports_with_names[2];
+ PE_ExportParsePtrArray all[3];
+ };
+} PE_FinalizedExports;
+
+////////////////////////////////
+
+internal PE_ExportParsePtrArray pe_array_from_export_list(Arena *arena, PE_ExportParseList list);
+internal PE_ExportParseNode * pe_export_parse_list_push(Arena *arena, PE_ExportParseList *list, PE_ExportParse data);
+internal String8List pe_make_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, String8 debug_symbols, PE_ExportParseList export_list);
+
+#endif // COFF_EXPORT_TABLE_H
diff --git a/src/linker/lnk_import_table.c b/src/pe/pe_make_import_table.c
similarity index 51%
rename from src/linker/lnk_import_table.c
rename to src/pe/pe_make_import_table.c
index 9beccc87..8935e0a9 100644
--- a/src/linker/lnk_import_table.c
+++ b/src/pe/pe_make_import_table.c
@@ -1,58 +1,8 @@
// Copyright (c) 2025 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
-internal LNK_ImportTable *
-lnk_import_table_alloc(void)
-{
- Arena *arena = arena_alloc();
- LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1);
- imptab->arena = arena;
- imptab->dll_ht = hash_table_init(arena, 512);
- return imptab;
-}
-
-internal void
-lnk_import_table_release(LNK_ImportTable **imptab_ptr)
-{
- ProfBeginFunction();
- arena_release((*imptab_ptr)->arena);
- *imptab_ptr = 0;
- ProfEnd();
-}
-
-internal LNK_ImportDLL *
-lnk_import_table_push_dll(LNK_ImportTable *imptab, String8 dll_name, COFF_MachineType machine)
-{
- LNK_ImportDLL *dll = push_array(imptab->arena, LNK_ImportDLL, 1);
-
- // update list
- SLLQueuePush(imptab->first_dll, imptab->last_dll, dll);
-
- // update name -> dll hash table
- hash_table_push_path_raw(imptab->arena, imptab->dll_ht, dll->name, dll);
-
- return dll;
-}
-
-internal LNK_ImportDLL *
-lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 dll_name)
-{
- LNK_ImportDLL *dll = 0;
- hash_table_search_string_raw(imptab->dll_ht, dll_name, &dll);
- return dll;
-}
-
-internal LNK_ImportFunc *
-lnk_import_table_push_func(LNK_ImportTable *imptab, LNK_ImportDLL *dll, struct LNK_Symbol *symbol)
-{
- LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1);
- func->symbol = symbol;
- lnk_import_table_push_func_node(imptab, dll, func);
- return func;
-}
-
internal COFF_ObjSymbol *
-lnk_emit_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name)
+pe_make_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name)
{
ProfBeginFunction();
@@ -74,7 +24,7 @@ lnk_emit_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *co
}
internal COFF_ObjSymbol *
-lnk_emit_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *imp_addr_ptr, COFF_ObjSymbol *tail_merge, String8 func_name)
+pe_make_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *imp_addr_ptr, COFF_ObjSymbol *tail_merge, String8 func_name)
{
ProfBeginFunction();
@@ -105,7 +55,7 @@ lnk_emit_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect,
}
internal COFF_ObjSymbol *
-lnk_emit_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, String8 dll_name, COFF_ObjSymbol *dll_import_descriptor)
+pe_make_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, String8 dll_name, String8 delay_load_helper_name, COFF_ObjSymbol *dll_import_descriptor)
{
ProfBeginFunction();
@@ -143,7 +93,7 @@ lnk_emit_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_
static const U64 LEA_OPERAND_OFFSET = 54;
coff_obj_writer_section_push_reloc(obj_writer, code_sect, tail_merge_off + LEA_OPERAND_OFFSET, dll_import_descriptor, COFF_Reloc_X64_Rel32);
- COFF_ObjSymbol *delay_load_helper = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME));
+ COFF_ObjSymbol *delay_load_helper = coff_obj_writer_push_symbol_undef(obj_writer, delay_load_helper_name);
// patch call __delayLoadHelper2
static const U64 CALL_OPERAND_OFFSET = 59;
@@ -158,10 +108,9 @@ lnk_emit_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_
}
internal String8
-lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine)
+pe_make_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
{
ProfBeginFunction();
- Temp scratch = scratch_begin(&arena, 1);
Assert(machine == COFF_MachineType_X64);
Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
@@ -170,18 +119,10 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_s
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
- String8 debug_symbols;
- {
- CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
- String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
- cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
- debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
- }
-
String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
- COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
- COFF_ObjSection *idata2 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), LNK_DATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
- COFF_ObjSection *idata6 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), LNK_DATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
+ COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
+ COFF_ObjSection *idata2 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), PE_DATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
+ COFF_ObjSection *idata6 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), PE_DATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static);
{
@@ -210,30 +151,20 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_s
coff_obj_writer_release(&obj_writer);
- scratch_end(scratch);
ProfEnd();
return obj;
}
internal String8
-lnk_build_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine)
+pe_make_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
{
ProfBeginFunction();
- Temp scratch = scratch_begin(&arena, 1);
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
- String8 debug_symbols;
- {
- CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
- String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
- cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
- debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
- }
-
PE_ImportEntry *import_desc = push_array(obj_writer->arena, PE_ImportEntry, 1);
- COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
- COFF_ObjSection *idata3 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$3"), LNK_DATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(import_desc));
+ COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
+ COFF_ObjSection *idata3 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$3"), PE_DATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(import_desc));
coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x01018175, COFF_SymStorageClass_Static);
coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR"), 0, idata3);
@@ -242,30 +173,20 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, CO
coff_obj_writer_release(&obj_writer);
- scratch_end(scratch);
ProfEnd();
return obj;
}
internal String8
-lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine)
+pe_make_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
{
ProfBeginFunction();
- Temp scratch = scratch_begin(&arena, 1);
Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
- String8 debug_symbols;
- {
- CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
- String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
- cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
- debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
- }
-
- COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
+ COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
COFF_ObjSection *idata4 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$4"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite, str8_zero());
COFF_ObjSection *idata5 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite, str8_zero());
@@ -291,74 +212,38 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp tim
coff_obj_writer_release(&obj_writer);
- scratch_end(scratch);
ProfEnd();
return obj;
}
-internal void
-lnk_emit_dll_import_debug_symbols(COFF_ObjWriter *obj_writer, String8 dll_name)
-{
- Temp scratch = scratch_begin(0,0);
-
- CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
-
- // S_OBJ
- String8 obj_data = cv_make_obj_name(scratch.arena, dll_name, 0);
- cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_OBJNAME, obj_data);
-
- // S_COMPILE3
- String8 comp3_data = lnk_make_linker_compile3(scratch.arena, obj_writer->machine);
- cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
-
- // S_END
- cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_END, str8_zero());
-
- // TODO: add thunks
-
- // serialize symbols
- String8 debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
-
- coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS, debug_symbols);
-
- scratch_end(scratch);
-}
-
internal String8
-lnk_obj_from_import_dll_static(Arena *arena, COFF_MachineType machine, LNK_ImportDLL *dll)
+pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, String8List import_headers)
{
- COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, machine);
+ COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
- U64 import_size = coff_word_size_from_machine(machine);
+ U64 import_size = coff_word_size_from_machine(machine);
COFF_SectionFlags import_align = coff_section_flag_from_align_size(import_size);
- PE_ImportEntry *impdesc = push_array(obj_writer->arena, PE_ImportEntry, 1);
- String8 dll_name_cstr = push_cstr(obj_writer->arena, dll->name);
+ PE_ImportEntry *impdesc = push_array(obj_writer->arena, PE_ImportEntry, 1);
+ String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
- COFF_ObjSection *dll_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), LNK_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(impdesc));
- COFF_ObjSection *ilt_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$4"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero());
- COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero());
- COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), LNK_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
- COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$7"), LNK_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
- COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$i"), LNK_TEXT_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
+ COFF_ObjSection *dll_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(impdesc));
+ COFF_ObjSection *ilt_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$4"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
+ COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
+ COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
+ COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$7"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
+ COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$i"), PE_TEXT_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
COFF_ObjSymbol *ilt_symbol = coff_obj_writer_push_symbol_static(obj_writer, ilt_sect->name, 0, ilt_sect);
COFF_ObjSymbol *iat_symbol = coff_obj_writer_push_symbol_static(obj_writer, iat_sect->name, 0, iat_sect);
COFF_ObjSymbol *dll_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll_name_sect->name, 0, dll_name_sect);
-
- switch (machine) {
- case COFF_MachineType_Unknown: {} break;
- case COFF_MachineType_X64: {
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, lookup_table_voff), ilt_symbol, COFF_Reloc_X64_Addr32Nb);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, name_voff), dll_name_symbol, COFF_Reloc_X64_Addr32Nb);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, import_addr_table_voff), iat_symbol, COFF_Reloc_X64_Addr32Nb);
- } break;
- default: { NotImplemented; } break;
- }
- for (LNK_ImportFunc *func = dll->first_func; func != 0; func = func->next) {
- LNK_Symbol *import_symbol = func->symbol;
- COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_symbol->u.coff_import);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, lookup_table_voff), ilt_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, name_voff), dll_name_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, import_addr_table_voff), iat_symbol);
+
+ for (String8Node *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) {
+ COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->string);
String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name);
U64 iat_offset = iat_sect->data.total_size;
@@ -391,8 +276,8 @@ lnk_obj_from_import_dll_static(Arena *arena, COFF_MachineType machine, LNK_Impor
iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_offset, iat_sect);
// patch IAT and ILT
- coff_obj_writer_section_push_reloc(obj_writer, ilt_sect, ilt_offset, int_symbol, COFF_Reloc_X64_Addr32Nb);
- coff_obj_writer_section_push_reloc(obj_writer, iat_sect, iat_offset, int_symbol, COFF_Reloc_X64_Addr32Nb);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, ilt_sect, ilt_offset, int_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, iat_sect, iat_offset, int_symbol);
} break;
case COFF_ImportBy_Undecorate: {
NotImplemented;
@@ -407,7 +292,7 @@ lnk_obj_from_import_dll_static(Arena *arena, COFF_MachineType machine, LNK_Impor
if (import_header.type == COFF_ImportHeader_Code) {
switch (import_header.machine) {
case COFF_MachineType_Unknown: {} break;
- case COFF_MachineType_X64: { jmp_thunk_symbol = lnk_emit_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); } break;
+ case COFF_MachineType_X64: { jmp_thunk_symbol = pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); } break;
default: { NotImplemented; } break;
}
}
@@ -419,73 +304,72 @@ lnk_obj_from_import_dll_static(Arena *arena, COFF_MachineType machine, LNK_Impor
}
internal String8
-lnk_obj_from_import_dll_delayed(Arena *arena, COFF_MachineType machine, LNK_ImportDLL *dll, B32 emit_biat, B32 emit_uiat)
+pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, String8List import_headers, B32 emit_biat, B32 emit_uiat)
{
- COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, machine);
+ COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
// import descriptor
PE_DelayedImportEntry *impdesc = push_array(obj_writer->arena, PE_DelayedImportEntry, 1);
- impdesc->attributes = 1;
+ impdesc->attributes = 1;
// DLL name cstring
- String8 dll_name_cstr = push_cstr(obj_writer->arena, dll->name);
+ String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
// DLL handle
U64 handle_size = coff_word_size_from_machine(machine);
- U8 *handle = push_array(obj_writer->arena, U8, handle_size);
+ U8 *handle = push_array(obj_writer->arena, U8, handle_size);
// import align
- U64 import_size = coff_word_size_from_machine(machine);
+ U64 import_size = coff_word_size_from_machine(machine);
COFF_SectionFlags import_align = coff_section_flag_from_align_size(import_size);
- COFF_ObjSection *dll_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$2"), LNK_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(impdesc));
- COFF_ObjSection *ilt_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$4"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero());
- COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$5"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero());
- COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$6"), LNK_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
- COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$7"), LNK_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
- COFF_ObjSection *biat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$8"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero());
- COFF_ObjSection *uiat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$9"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero());
- COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$i"), LNK_TEXT_SECTION_FLAGS, str8_zero());
- COFF_ObjSection *handle_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$h"), LNK_DATA_SECTION_FLAGS, str8_array(handle, handle_size));
+ // push sections
+ COFF_ObjSection *dll_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$2"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(impdesc));
+ COFF_ObjSection *ilt_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$4"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
+ COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$5"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
+ COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
+ COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$7"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
+ COFF_ObjSection *biat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$8"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
+ COFF_ObjSection *uiat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$9"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
+ COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$i"), PE_TEXT_SECTION_FLAGS, str8_zero());
+ COFF_ObjSection *handle_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$h"), PE_DATA_SECTION_FLAGS, str8_array(handle, handle_size));
+ COFF_ObjSection *debug_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
+ // sections symbols
COFF_ObjSymbol *dll_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll_sect->name, 0, dll_sect);
COFF_ObjSymbol *dll_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll_name_sect->name, 0, dll_name_sect);
COFF_ObjSymbol *handle_symbol = coff_obj_writer_push_symbol_static(obj_writer, handle_sect->name, 0, handle_sect);
COFF_ObjSymbol *iat_symbol = coff_obj_writer_push_symbol_static(obj_writer, iat_sect->name, 0, iat_sect);
COFF_ObjSymbol *ilt_symbol = coff_obj_writer_push_symbol_static(obj_writer, ilt_sect->name, 0, ilt_sect);
- switch (machine) {
- case COFF_MachineType_Unknown: {} break;
- case COFF_MachineType_X64: {
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, name_voff), dll_name_symbol, COFF_Reloc_X64_Addr32Nb);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol, COFF_Reloc_X64_Addr32Nb);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_symbol, COFF_Reloc_X64_Addr32Nb);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, name_table_voff), ilt_symbol, COFF_Reloc_X64_Addr32Nb);
- } break;
- default: { NotImplemented; } break;
- }
+ // patch virutal offsets in import header
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, name_voff), dll_name_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, name_table_voff), ilt_symbol);
+ // patch BIAT virtual offset in import header
if (emit_biat) {
COFF_ObjSymbol *biat_symbol = coff_obj_writer_push_symbol_static(obj_writer, biat_sect->name, 0, biat_sect);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol, COFF_Reloc_X64_Addr32Nb);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol);
}
+
+ // patch UIAT virtual offset in import header
if (emit_uiat) {
COFF_ObjSymbol *uiat_symbol = coff_obj_writer_push_symbol_static(obj_writer, uiat_sect->name, 0, uiat_sect);
- coff_obj_writer_section_push_reloc(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol, COFF_Reloc_X64_Addr32Nb);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol);
}
// emit tail merge
COFF_ObjSymbol *tail_merge_symbol = 0;
switch (machine) {
case COFF_MachineType_Unknown: {} break;
- case COFF_MachineType_X64: { tail_merge_symbol = lnk_emit_tail_merge_thunk_x64(obj_writer, code_sect, dll->name, dll_symbol); } break;
+ case COFF_MachineType_X64: { tail_merge_symbol = pe_make_tail_merge_thunk_x64(obj_writer, code_sect, dll_name, delay_load_helper_name, dll_symbol); } break;
default: { NotImplemented; } break;
}
- for (LNK_ImportFunc *func = dll->first_func; func != 0; func = func->next) {
-#if 0
- LNK_Symbol *import_symbol = func->symbol;
- COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_symbol->u.coff_import);
+ for (String8Node *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) {
+ COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->string);
// emit thunks
COFF_ObjSymbol *jmp_thunk_symbol = 0;
@@ -493,146 +377,91 @@ lnk_obj_from_import_dll_delayed(Arena *arena, COFF_MachineType machine, LNK_Impo
if (import_header.type == COFF_ImportHeader_Code) {
switch (machine) {
case COFF_MachineType_X64: {
- String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", header->func_name);
+ String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name);
coff_obj_writer_push_symbol_undef(obj_writer, iat_symbol_name);
// emit jmp thunk
- jmp_thunk_symbol = lnk_emit_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name);
+ jmp_thunk_symbol = pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name);
// emit load thunk
- load_thunk_chunk = lnk_emit_load_thunk_x64(code_sect, code_table_chunk, iat_symbol, dll->tail_merge_symbol);
+ load_thunk_symbol = pe_make_load_thunk_x64(obj_writer, code_sect, iat_symbol, tail_merge_symbol, import_header.func_name);
} break;
- default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
+ default: { NotImplemented; } break;
}
}
- U64 import_size = coff_word_size_from_machine(machine);
-
- switch (header->import_by) {
+ switch (import_header.import_by) {
case COFF_ImportBy_Ordinal: {
+ U64 iat_offset = iat_sect->data.total_size;
String8 ordinal_data = coff_ordinal_data_from_hint(obj_writer->arena, import_header.machine, import_header.hint_or_ordinal);
str8_list_push(obj_writer->arena, &ilt_sect->data, ordinal_data);
str8_list_push(obj_writer->arena, &iat_sect->data, ordinal_data);
+ String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name);
iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_offset, iat_sect);
+
if (emit_biat) {
- biat_chunk = lnk_section_push_chunk_bss(data_sect, biat_table_chunk, import_size, sort_index);
- lnk_section_push_reloc(data_sect, biat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
- lnk_section_associate_chunks(data_sect, iat_chunk, biat_chunk);
+ U64 import_size = coff_word_size_from_machine(machine);
+ U64 biat_offset = biat_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &biat_sect->data, str8(0,import_size));
+ coff_obj_writer_section_push_reloc_addr(obj_writer, biat_sect, biat_offset, load_thunk_symbol);
}
if (emit_uiat) {
- uiat_chunk = lnk_section_push_chunk_bss(data_sect, uiat_table_chunk, import_size, sort_index);
- lnk_section_push_reloc(data_sect, uiat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
- lnk_section_associate_chunks(data_sect, iat_chunk, uiat_chunk);
+ U64 import_size = coff_word_size_from_machine(machine);
+ U64 uiat_offset = uiat_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &biat_sect->data, str8(0,import_size));
+ coff_obj_writer_section_push_reloc_addr(obj_writer, uiat_sect, uiat_offset, load_thunk_symbol);
}
} break;
case COFF_ImportBy_Name: {
// put together name look up entry
- String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint_or_ordinal, header->func_name);
- LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
+ String8 int_data = coff_make_import_lookup(obj_writer->arena, import_header.hint_or_ordinal, import_header.func_name);
+ U64 int_data_offset = int_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &int_sect->data, int_data);
// create symbol for lookup chunk
- String8 int_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.name.delayed", dll->name, header->func_name);
- int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
+ String8 int_symbol_name = push_str8f(obj_writer->arena, "%S.%S.name.delayed", dll_name, import_header.func_name);
+ COFF_ObjSymbol *int_symbol = coff_obj_writer_push_symbol_static(obj_writer, int_symbol_name, int_data_offset, int_sect);
+
+ U64 import_size = coff_word_size_from_machine(machine);
// dynamic linker patches this voff on DLL load event
- ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
- lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "ILT entry (delayed) %S.%S", dll->name, header->func_name);
+ U64 ilt_data_offset = ilt_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &ilt_sect->data, str8(0, import_size));
// patch-in ILT with import voff
- lnk_section_push_reloc(data_sect, ilt_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol);
+ coff_obj_writer_section_push_reloc_voff(obj_writer, ilt_sect, ilt_data_offset, int_symbol);
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
- iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index);
- lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IAT entre (delayed) %S.%S", dll->name, header->func_name);
-
- // associate chunks
- lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk);
- lnk_section_associate_chunks(data_sect, iat_chunk, int_chunk);
+ U64 iat_data_offset = iat_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &iat_sect->data, str8(0, import_size));
// patch-in thunk address
- lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
+ coff_obj_writer_section_push_reloc_addr(obj_writer, iat_sect, iat_data_offset, load_thunk_symbol);
- if (imptab->flags & LNK_ImportTableFlag_EmitBiat) {
- biat_chunk = lnk_section_push_chunk_bss(data_sect, biat_table_chunk, import_size, sort_index);
- lnk_chunk_set_debugf(data_sect->arena, biat_chunk, "%S.biat.%S (delayed)", dll->name, header->func_name);
+ if (emit_biat) {
+ U64 biat_data_offset = biat_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &biat_sect->data, str8(0, import_size));
// patch-in thunk address
- lnk_section_push_reloc(data_sect, biat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
+ coff_obj_writer_section_push_reloc_addr(obj_writer, biat_sect, biat_data_offset, load_thunk_symbol);
}
- if (imptab->flags & LNK_ImportTableFlag_EmitUiat) {
- uiat_chunk = lnk_section_push_chunk_bss(data_sect, uiat_table_chunk, import_size, sort_index);
- lnk_chunk_set_debugf(data_sect->arena, uiat_chunk, "%S.uiat.%S (delayed)", dll->name, header->func_name);
+ if (emit_uiat) {
+ U64 uiat_data_offset = uiat_sect->data.total_size;
+ str8_list_push(obj_writer->arena, &uiat_sect->data, str8(0, import_size));
// patch-in thunk address
- lnk_section_push_reloc(data_sect, uiat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
+ coff_obj_writer_section_push_reloc_addr(obj_writer, uiat_sect, uiat_data_offset, load_thunk_symbol);
}
} break;
- case COFF_ImportBy_Undecorate: {
- lnk_not_implemented("TODO: COFF_ImportBy_Undecorate");
- } break;
- case COFF_ImportBy_NameNoPrefix: {
- lnk_not_implemented("TODO: COFF_ImportBy_NameNoPrefix");
- } break;
+ case COFF_ImportBy_Undecorate: { NotImplemented; } break;
+ case COFF_ImportBy_NameNoPrefix: { NotImplemented; } break;
}
-
- if (jmp_thunk_chunk) {
- lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk);
- }
- if (load_thunk_chunk) {
- lnk_section_associate_chunks(data_sect, iat_chunk, load_thunk_chunk);
- }
-
- String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
- LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
-
- String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.ilt.delayed", dll->name, header->func_name);
- LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
-#endif
}
- return str8_zero();
+ String8 obj = coff_obj_writer_serialize(arena, obj_writer);
+ coff_obj_writer_release(&obj_writer);
+ return obj;
}
-
-internal String8Array
-lnk_make_import_dlls_static(Arena *arena, LNK_ImportTable *imptab, COFF_MachineType machine, String8 image_name)
-{
- String8Array objs = {0};
- if (imptab->dll_count) {
- objs.v = push_array(arena, String8, imptab->dll_count + 3);
-
- // make objs for each DLL
- for (LNK_ImportDLL *dll = imptab->first_dll; dll != 0; dll = dll->next) {
- objs.v[objs.count++] = lnk_obj_from_import_dll_static(arena, machine, dll);
- }
-
- // make null terminator objs
- objs.v[objs.count++] = lnk_build_import_entry_obj(arena, image_name, COFF_TimeStamp_Max, machine);
- objs.v[objs.count++] = lnk_build_null_import_descriptor_obj(arena, COFF_TimeStamp_Max, machine);
- objs.v[objs.count++] = lnk_build_null_thunk_data_obj(arena, image_name, COFF_TimeStamp_Max, machine);
- }
- return objs;
-}
-
-internal String8Array
-lnk_make_import_dlls_delayed(Arena *arena, LNK_ImportTable *imptab, COFF_MachineType machine, String8 image_name, B32 emit_biat, B32 emit_uiat)
-{
- String8Array objs = {0};
- if (imptab->dll_count) {
- objs.v = push_array(arena, String8, imptab->dll_count + 3);
-
- // make objs for each DLL
- for (LNK_ImportDLL *dll = imptab->first_dll; dll != 0; dll = dll->next) {
- objs.v[objs.count++] = lnk_obj_from_import_dll_delayed(arena, machine, dll, emit_biat, emit_uiat);
- }
-
- // make null terminator objs
- objs.v[objs.count++] = lnk_build_import_entry_obj(arena, image_name, COFF_TimeStamp_Max, machine);
- objs.v[objs.count++] = lnk_build_null_import_descriptor_obj(arena, COFF_TimeStamp_Max, machine);
- objs.v[objs.count++] = lnk_build_null_thunk_data_obj(arena, image_name, COFF_TimeStamp_Max, machine);
- }
- return objs;
-}
-
diff --git a/src/pe/pe_make_import_table.h b/src/pe/pe_make_import_table.h
new file mode 100644
index 00000000..b88d3905
--- /dev/null
+++ b/src/pe/pe_make_import_table.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2025 Epic Games Tools
+// Licensed under the MIT license (https://opensource.org/license/mit/)
+
+#ifndef PE_MAKE_IMPORT_TABLE_H
+#define PE_MAKE_IMPORT_TABLE_H
+
+internal COFF_ObjSymbol * pe_make_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name);
+internal COFF_ObjSymbol * pe_make_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *imp_addr_ptr, COFF_ObjSymbol *tail_merge, String8 func_name);
+internal COFF_ObjSymbol * pe_make_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, String8 dll_name, String8 delay_load_helper_name, COFF_ObjSymbol *dll_import_descriptor);
+
+internal String8 pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stmap, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, String8List import_headers);
+internal String8 pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, String8List import_headers, B32 emit_biat, B32 emit_uiat);
+
+internal String8 pe_make_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols);
+internal String8 pe_make_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols);
+internal String8 pe_make_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols);
+
+#endif // PE_MAKE_IMPORT_TABLE_H
\ No newline at end of file
diff --git a/src/pe/pe_section_flags.h b/src/pe/pe_section_flags.h
new file mode 100644
index 00000000..4d9fdf54
--- /dev/null
+++ b/src/pe/pe_section_flags.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2025 Epic Games Tools
+// Licensed under the MIT license (https://opensource.org/license/mit/)
+
+#ifndef PE_SECTION_FLAGS_H
+#define PE_SECTION_FLAGS_H
+
+#define PE_TEXT_SECTION_FLAGS (COFF_SectionFlag_CntCode|COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead)
+#define PE_DATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
+#define PE_RDATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead)
+#define PE_BSS_SECTION_FLAGS (COFF_SectionFlag_CntUninitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
+#define PE_IDATA_SECTION_FLAGS PE_DATA_SECTION_FLAGS
+#define PE_DEBUG_DIR_SECTION_FLAGS PE_DATA_SECTION_FLAGS
+#define PE_RSRC_SECTION_FLAGS PE_DATA_SECTION_FLAGS
+#define PE_RSRC1_SECTION_FLAGS (PE_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
+#define PE_RSRC2_SECTION_FLAGS (PE_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
+#define PE_XDATA_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_PDATA_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_EDATA_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_GFIDS_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_GIATS_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_GLJMP_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_GEHCONT_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
+#define PE_RELOC_SECTION_FLAGS (PE_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
+#define PE_DEBUG_SECTION_FLAGS (PE_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
+
+#endif // PE_SECTION_FLAGS_H
+
diff --git a/src/torture/torture.c b/src/torture/torture.c
index 64127fec..a8dd2135 100644
--- a/src/torture/torture.c
+++ b/src/torture/torture.c
@@ -1478,7 +1478,7 @@ t_import_export(void)
coff_obj_writer_push_directive(obj_writer, str8_lit("/export:baf=baz.#1"));
coff_obj_writer_push_directive(obj_writer, str8_lit("/export:ord,@5"));
coff_obj_writer_push_directive(obj_writer, str8_lit("/export:ord2,@6,DATA"));
- coff_obj_writer_push_directive(obj_writer, str8_lit("/export:ord3,@7,NONAME"));
+ coff_obj_writer_push_directive(obj_writer, str8_lit("/export:ord3,@7,NONAME,PRIVATE"));
coff_obj_writer_push_directive(obj_writer, str8_lit("/export:ord4,@8,NONAME,DATA"));
COFF_ObjSection *text_sect = t_push_text_section(obj_writer, str8_array_fixed(export_text));
coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("_DllMainCRTStartup"), 0, text_sect);