WIP move export and import table make code to appropriate layers

This commit is contained in:
Nikita Smith
2025-05-13 23:08:19 -07:00
committed by Ryan Fleury
parent 69d5010245
commit f467ff8822
27 changed files with 992 additions and 1040 deletions
+11
View File
@@ -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
+1
View File
@@ -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
-12
View File
@@ -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)
{
-1
View File
@@ -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
+13 -14
View File
@@ -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
+5 -5
View File
@@ -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
+42 -27
View File
@@ -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 = &sect_n->v;
sect->name = name;
sect->flags = flags;
if (data.size) {
str8_list_push(obj_writer->arena, &sect->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 = &sect_n->v;
sect->name = name;
sect->flags = flags;
if (data.size) {
str8_list_push(obj_writer->arena, &sect->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)
{
+19 -4
View File
@@ -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
-11
View File
@@ -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)
{
+13
View File
@@ -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)
{
+1
View File
@@ -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);
+168 -90
View File
@@ -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();
-21
View File
@@ -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
+118 -2
View File
@@ -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;
+4 -1
View File
@@ -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);
+39
View File
@@ -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;
}
-451
View File
@@ -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;
}
-46
View File
@@ -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);
-26
View File
@@ -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)
-51
View File
@@ -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);
+2
View File
@@ -151,6 +151,8 @@
<AlternativeType Name="Rng1S64List"/>
<AlternativeType Name="DW_AttribList"/>
<AlternativeType Name="DW_LocList"/>
<AlternativeType Name="COFF_LibWriterSymbolList"/>
<AlternativeType Name="COFF_LibWriterMemberList"/>
<DisplayString>{{ count={count} first={first} }} </DisplayString>
<Expand>
<Item Name="[count]">count</Item>
+343
View File
@@ -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;
}
+61
View File
@@ -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
@@ -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;
}
+18
View File
@@ -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
+27
View File
@@ -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
+1 -1
View File
@@ -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);