mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
WIP move export and import table make code to appropriate layers
This commit is contained in:
committed by
Ryan Fleury
parent
69d5010245
commit
f467ff8822
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -16,6 +16,24 @@ coff_obj_writer_release(COFF_ObjWriter **obj_writer)
|
||||
*obj_writer = 0;
|
||||
}
|
||||
|
||||
internal COFF_ObjSection *
|
||||
coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
|
||||
{
|
||||
COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
|
||||
SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
|
||||
obj_writer->sect_count += 1;
|
||||
|
||||
COFF_ObjSection *sect = §_n->v;
|
||||
sect->name = name;
|
||||
sect->flags = flags;
|
||||
|
||||
if (data.size) {
|
||||
str8_list_push(obj_writer->arena, §->data, data);
|
||||
}
|
||||
|
||||
return sect;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class)
|
||||
{
|
||||
@@ -104,15 +122,6 @@ coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = { COFF_SymbolLocation_Undef };
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, flags, loc, type, COFF_SymStorageClass_Section);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
|
||||
{
|
||||
@@ -159,24 +168,6 @@ coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSection *
|
||||
coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
|
||||
{
|
||||
COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
|
||||
SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
|
||||
obj_writer->sect_count += 1;
|
||||
|
||||
COFF_ObjSection *sect = §_n->v;
|
||||
sect->name = name;
|
||||
sect->flags = flags;
|
||||
|
||||
if (data.size) {
|
||||
str8_list_push(obj_writer->arena, §->data, data);
|
||||
}
|
||||
|
||||
return sect;
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc*
|
||||
coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type)
|
||||
{
|
||||
@@ -192,6 +183,30 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *
|
||||
return reloc;
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user