diff --git a/src/coff/coff.c b/src/coff/coff.c index 81ec2bf8..5b65582a 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -205,6 +205,27 @@ coff_make_ordinal64(U16 hint) return ordinal; } +internal String8 +coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint) +{ + String8 ordinal_data = {0}; + switch (machine) { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { + U64 *ordinal = push_array(arena, U64, 1); + *ordinal = coff_make_ordinal64(hint); + ordinal_data = str8_struct(ordinal); + } break; + case COFF_MachineType_X86: { + U32 *ordinal = push_array(arena, U32, 1); + *ordinal = coff_make_ordinal32(hint); + ordinal_data = str8_struct(ordinal); + } break; + default: { NotImplemented; } break; + } + return ordinal_data; +} + internal String8 coff_make_import_header_by_name(Arena *arena, String8 dll_name, diff --git a/src/coff/coff.h b/src/coff/coff.h index aa88b9b9..34475016 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -601,6 +601,7 @@ internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x); internal U32 coff_make_ordinal32(U16 hint); internal U64 coff_make_ordinal64(U16 hint); +internal String8 coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint); internal String8 coff_make_import_lookup (Arena *arena, U16 hint, String8 name); internal String8 coff_make_import_header_by_name (Arena *arena, String8 dll_name, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 name, U16 hint, COFF_ImportType type); diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 9d715603..d804e2cd 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -1,11 +1,11 @@ internal COFF_ObjWriter* -coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine_type) +coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine) { Arena *arena = arena_alloc(); COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1); obj_writer->arena = arena; obj_writer->time_stamp = time_stamp; - obj_writer->machine_type = machine_type; + obj_writer->machine = machine; return obj_writer; } @@ -35,7 +35,7 @@ coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, } internal COFF_ObjSymbol * -coff_obj_writer_push_symbol_external(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section) +coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section) { COFF_SymbolLocation loc = {0}; loc.type = COFF_SymbolLocation_Section; @@ -182,7 +182,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) // file header // COFF_FileHeader *file_header = push_array(scratch.arena, COFF_FileHeader, 1); - file_header->machine = obj_writer->machine_type; + file_header->machine = obj_writer->machine; file_header->section_count = obj_sections_count; file_header->time_stamp = obj_writer->time_stamp; file_header->symbol_table_foff = 0; diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h index 9a85357c..6a203d60 100644 --- a/src/coff/coff_obj_writer.h +++ b/src/coff/coff_obj_writer.h @@ -70,7 +70,7 @@ typedef struct COFF_ObjWriter { Arena *arena; COFF_TimeStamp time_stamp; - COFF_MachineType machine_type; + COFF_MachineType machine; U64 symbol_count; COFF_ObjSymbolNode *symbol_first; @@ -83,7 +83,7 @@ typedef struct COFF_ObjWriter //////////////////////////////// -internal COFF_ObjWriter* coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine_type); +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); diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index 29da28d3..16560c36 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -286,19 +286,21 @@ hash_table_search_string_raw(HashTable *ht, String8 key, void **value_out) //////////////////////////////// internal int -key_value_pair_is_before_u32(void *raw_a, void *raw_b) +key_value_pair_is_before_u32(void *a, void *b) { - KeyValuePair *a = raw_a; - KeyValuePair *b = raw_b; - return a->key_u32 < b->key_u32; + return ((KeyValuePair *)a)->key_u32 < ((KeyValuePair *)b)->key_u32; } internal int -key_value_pair_is_before_u64(void *raw_a, void *raw_b) +key_value_pair_is_before_u64(void *a, void *b) { - KeyValuePair *a = raw_a; - KeyValuePair *b = raw_b; - return a->key_u64 < b->key_u64; + return ((KeyValuePair *)a)->key_u64 < ((KeyValuePair *)b)->key_u64; +} + +internal int +key_value_pair_is_before_string_sensitive(void *a, void *b) +{ + return str8_compar_case_sensitive(((KeyValuePair*)a)->key_string, ((KeyValuePair*)b)->key_string) < 0; } internal U32 * @@ -366,6 +368,12 @@ sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count) radsort(pairs, count, key_value_pair_is_before_u64); } +internal void +sort_key_value_pairs_as_string_sensitive(KeyValuePair *pairs, U64 count) +{ + radsort(pairs, count, key_value_pair_is_before_string_sensitive); +} + internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr) { diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 4ea808ff..df557997 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -85,6 +85,7 @@ internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht); internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); +internal void sort_key_value_pairs_as_string_sensitive(KeyValuePair *pairs, U64 count); //////////////////////////////// diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a89acec9..cb2731d5 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -698,10 +698,7 @@ lnk_make_res_obj(Arena *arena, } internal String8 -lnk_obj_from_res_file_list(TP_Context *tp, - Arena *arena, - LNK_SectionTable *sectab, - LNK_SymbolTable *symtab, +lnk_obj_from_res_file_list(Arena *arena, String8List res_data_list, String8List res_path_list, COFF_MachineType machine, @@ -790,7 +787,7 @@ lnk_make_linker_coff_obj(Arena *arena, str8_list_push(scratch.arena, &env_list, str8_lit("")); str8_list_push(scratch.arena, &env_list, str8_lit("")); cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_ENVBLOCK, cv_make_envblock(scratch.arena, env_list)); - + // TODO: emit S_SECTION and S_COFFGROUP // TODO: emit S_TRAMPOLINE @@ -992,83 +989,67 @@ lnk_build_guard_data(Arena *arena, U64Array voff_arr, U64 stride) } internal void -lnk_push_pe_debug_data_directory(LNK_Section *sect, - LNK_Chunk *dir_array_chunk, - LNK_Symbol *data_symbol, +lnk_push_pe_debug_data_directory(COFF_ObjWriter *obj_writer, + COFF_ObjSymbol *data_symbol, PE_DebugDirectoryType type, COFF_TimeStamp time_stamp) { // init directory - PE_DebugDirectory *dir = push_array(sect->arena, PE_DebugDirectory, 1); + PE_DebugDirectory *dir = push_array(obj_writer->arena, PE_DebugDirectory, 1); dir->time_stamp = time_stamp; dir->type = type; //dir->voff = 0; // relocated through 'data_symbol' //dir->foff = 0; // relocated through 'data_symbol' //dir->size = 0; // relocated through 'data_symbol' - - // push chunk - LNK_Chunk *dir_entry_chunk = lnk_section_push_chunk_data(sect, dir_array_chunk, str8_struct(dir), str8_zero()); - lnk_chunk_set_debugf(sect->arena, dir_entry_chunk, "DebugDirectory[%u]", type); - - // push debug directory relocs - lnk_section_push_reloc(sect, dir_entry_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DebugDirectory, voff), data_symbol); - lnk_section_push_reloc(sect, dir_entry_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(PE_DebugDirectory, foff), data_symbol); - lnk_section_push_reloc(sect, dir_entry_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(PE_DebugDirectory, size), data_symbol); + COFF_ObjSection *debug_dir_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".RAD_LINKER_DEBUG_DIR$d"), LNK_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, LNK_COFF_RELOC_FILE_OFFSET32); + coff_obj_writer_section_push_reloc(obj_writer, debug_dir_sect, OffsetOf(PE_DebugDirectory, size), data_symbol, LNK_COFF_RELOC_SECT_SIZE32); } -internal void -lnk_build_debug_pdb(LNK_SectionTable *sectab, - LNK_SymbolTable *symtab, - LNK_Section *sect, - LNK_Chunk *dir_array_chunk, - COFF_TimeStamp time_stamp, - Guid guid, - U32 age, - String8 pdb_path) +internal LNK_InputObjList +lnk_build_debug_directory_objs(Arena *arena, LNK_Config *config) { - ProfBeginFunction(); - - // push chunks - String8 debug_pdb_data = pe_make_debug_header_pdb70(sect->arena, guid, age, pdb_path); - LNK_Chunk *debug_pdb_chunk = lnk_section_push_chunk_data(sect, sect->root, debug_pdb_data, str8(0, 0)); - lnk_chunk_set_debugf(sect->arena, debug_pdb_chunk, LNK_CV_HEADER_PDB70_SYMBOL_NAME); - - // push symbols - LNK_Symbol *debug_pdb_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_PDB70_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_pdb_chunk, 0, 0, 0); - LNK_Symbol *guid_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_GUID_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_pdb_chunk, OffsetOf(PE_CvHeaderPDB70, guid), 0, 0); - - // push debug directory - lnk_push_pe_debug_data_directory(sect, dir_array_chunk, debug_pdb_symbol, PE_DebugDirectoryType_CODEVIEW, time_stamp); - - ProfEnd(); -} + LNK_InputObjList result = {0}; -internal void -lnk_build_debug_rdi(LNK_SectionTable *sectab, - LNK_SymbolTable *symtab, - LNK_Section *debug_sect, - LNK_Chunk *debug_dir_array_chunk, - COFF_TimeStamp time_stamp, - Guid guid, - String8 rdi_path) -{ - ProfBeginFunction(); - - LNK_Section *rdi_sect = lnk_section_table_push(sectab, str8_lit(".raddbg"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead); - - // push chunks - String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path); - LNK_Chunk *debug_rdi_chunk = lnk_section_push_chunk_data(rdi_sect, rdi_sect->root, debug_rdi, str8_zero()); - lnk_chunk_set_debugf(rdi_sect->arena, debug_rdi_chunk, LNK_CV_HEADER_RDI_SYMBOL_NAME); - - // push symbols - LNK_Symbol *debug_rdi_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_RDI_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, 0, 0, 0); - LNK_Symbol *guid_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_GUID_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, OffsetOf(PE_CvHeaderRDI, guid), 0, 0); - - // push debug directory - lnk_push_pe_debug_data_directory(debug_sect, debug_dir_array_chunk, debug_rdi_symbol, PE_DebugDirectoryType_CODEVIEW, time_stamp); - - ProfEnd(); + B32 build_pdb_header = config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null; + B32 build_rdi_header = config->rad_debug == LNK_SwitchState_Yes; + + if (build_pdb_header || build_rdi_header) { + 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()); + + // marker symbols for debug directory patcher + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("RAD_LINKER_DEBUG_SECTION_A"), 0, sect_a); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("RAD_LINKER_DEBUG_SECTION_Z"), 0, sect_z); + + // debug entry for PDB + if (build_pdb_header) { + 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_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, PE_DebugDirectoryType_CODEVIEW, config->time_stamp); + } + + // debug entry for RDI + if (build_rdi_header) { + 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_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, PE_DebugDirectoryType_CODEVIEW, config->time_stamp); + } + + LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); + input->path = str8_lit("* Debug Directory *"); + input->dedup_id = input->path; + input->data = coff_obj_writer_serialize(arena, obj_writer); + + coff_obj_writer_release(&obj_writer); + } + + return result; } internal void @@ -2067,7 +2048,7 @@ THREAD_POOL_TASK_FUNC(lnk_undef_symbol_finder) LNK_Symbol *has_defn = lnk_symbol_table_search(task->symtab, undef->scope_flags, symbol->name); if (has_defn) { - Assert(LNK_Symbol_IsDefined(has_defn->type) || has_defn->type == LNK_Symbol_Weak); + Assert(LNK_Symbol_IsDefined(has_defn->type) || has_defn->type == LNK_Symbol_Weak || has_defn->type == LNK_Symbol_Import); continue; } @@ -2970,17 +2951,17 @@ lnk_run(int argc, char **argv) State_InputObjs, State_LookupUndef, State_LookupWeak, + State_BuildImportObjs, + State_BuildExportObjs, + State_BuildDebugDirectoryObjs, State_BuildAndInputLinkerObj, State_BuildAndInputResObj, State_PushDllHelperUndefSymbol, State_PushLinkerSymbols, State_PushLoadConfigUndefSymbol, State_SearchEntryPoint, - State_CheckUnusedDelayLoads, State_ReportUnresolvedSymbols, State_DiscardMetaDataSections, - State_BuildDebugDirectory, - State_BuildExportTable, State_MergeSections, State_BuildCFGuards, State_BuildBaseRelocs, @@ -3040,12 +3021,20 @@ lnk_run(int argc, char **argv) // input command line libs input_libs[LNK_InputSource_CmdLine] = config->input_list[LNK_Input_Lib]; input_libs[LNK_InputSource_Default] = config->input_default_lib_list; + + LNK_ImportTableFlags imptab_flags = 0; + if (config->flags & LNK_ConfigFlag_DelayUnload) { + imptab_flags |= LNK_ImportTableFlag_EmitUiat; + } + if (config->flags & LNK_ConfigFlag_DelayBind) { + imptab_flags |= LNK_ImportTableFlag_EmitUiat; + } // state LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena); LNK_SectionTable *sectab = lnk_init_section_table(symtab, config->section_virt_off, config->sect_align, config->file_align); - LNK_ImportTable *imptab_static = 0; - LNK_ImportTable *imptab_delayed = 0; + LNK_ImportTable *imptab_static = lnk_import_table_alloc(0); + LNK_ImportTable *imptab_delayed = lnk_import_table_alloc(imptab_flags); LNK_ExportTable *exptab = lnk_export_table_alloc(); Arena *ht_arena = arena_alloc(); HashTable *disallow_lib_ht = hash_table_init(scratch.arena, 0x100); @@ -3060,15 +3049,15 @@ lnk_run(int argc, char **argv) U64 entry_search_attempts = 0; B32 build_debug_info = lnk_do_debug_info(config); B32 build_linker_obj = build_debug_info; - B32 build_debug_directory = build_debug_info; + B32 build_debug_directory_objs = build_debug_info; + B32 build_import_objs = 1; + B32 build_export_objs = 1; B32 build_res_obj = 1; B32 discard_meta_data_sections = 1; B32 merge_sections = !!(config->flags & LNK_ConfigFlag_Merge); B32 build_cf_guards = 0; // (config->flags != LNK_Guard_NONE); - B32 build_export_table = 1; B32 build_base_relocs = !(config->flags & LNK_ConfigFlag_Fixed); B32 report_unresolved_symbols = 1; - B32 check_unused_delay_loads = !!(config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll); B32 build_imp_lib = config->build_imp_lib; B32 build_rad_chunk_map = (config->rad_chunk_map == LNK_SwitchState_Yes); LNK_ObjList obj_list = {0}; @@ -3285,37 +3274,49 @@ lnk_run(int argc, char **argv) ProfBegin("Input Imports"); for (LNK_InputImport *input = input_import_list.first; input != 0; input = input->next) { COFF_ParsedArchiveImportHeader *import_header = &input->import_header; - KeyValuePair *is_delayed = hash_table_search_path(delay_load_dll_ht, import_header->dll_name); + if (import_header->machine != config->machine) { + lnk_error(LNK_Error_IncompatibleMachine, "symbol pulls in an import with incompatible machine %S (expected %S)", + coff_string_from_machine_type(input->import_header.machine), + coff_string_from_machine_type(config->machine)); + } + + KeyValuePair *is_delayed = hash_table_search_path(delay_load_dll_ht, import_header->dll_name); + + LNK_ImportDLL *dll; + LNK_ImportFunc *func; if (is_delayed) { - if (!imptab_delayed) { - Assert(config->machine != COFF_MachineType_Unknown); - B32 is_unloadable = !!(config->flags & LNK_ConfigFlag_DelayUnload); - B32 is_bindable = !!(config->flags & LNK_ConfigFlag_DelayBind); - imptab_delayed = lnk_import_table_alloc_delayed(sectab, symtab, config->machine, is_unloadable, is_bindable); - } - LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_delayed, import_header->dll_name); + dll = lnk_import_table_search_dll(imptab_delayed, import_header->dll_name); if (!dll) { - dll = lnk_import_table_push_dll_delayed(imptab_delayed, symtab, import_header->dll_name, import_header->machine); + dll = lnk_import_table_push_dll_delayed(imptab_delayed, import_header->dll_name, import_header->machine); } - LNK_ImportFunc *func = lnk_import_table_search_func(dll, import_header->func_name); + func = lnk_import_table_search_func(dll, import_header->func_name); if (!func) { - func = lnk_import_table_push_func_delayed(imptab_delayed, symtab, dll, import_header); + func = lnk_import_table_push_func_delayed(imptab_delayed, dll, import_header); } } else { - if (!imptab_static) { - Assert(config->machine != COFF_MachineType_Unknown); - imptab_static = lnk_import_table_alloc_static(sectab, symtab, config->machine); - } - LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_static, import_header->dll_name); + dll = lnk_import_table_search_dll(imptab_static, import_header->dll_name); if (!dll) { - dll = lnk_import_table_push_dll_static(imptab_static, symtab, import_header->dll_name, import_header->machine); + dll = lnk_import_table_push_dll_static(imptab_static, import_header->dll_name, import_header->machine); } - LNK_ImportFunc *func = lnk_import_table_search_func(dll, import_header->func_name); + func = lnk_import_table_search_func(dll, import_header->func_name); if (!func) { - func = lnk_import_table_push_func_static(imptab_static, symtab, dll, import_header); + func = lnk_import_table_push_func_static(imptab_static, dll, import_header); } } + + { + LNK_Symbol *thunk_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1); + thunk_symbol->name = func->thunk_symbol_name; + thunk_symbol->type = LNK_Symbol_Import; + + LNK_Symbol *iat_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1); + iat_symbol->name = func->iat_symbol_name; + iat_symbol->type = LNK_Symbol_Import; + + lnk_symbol_table_push(symtab, thunk_symbol); + lnk_symbol_table_push(symtab, iat_symbol); + } } // reset input @@ -3629,6 +3630,50 @@ lnk_run(int argc, char **argv) ProfEnd(); } break; + case State_BuildImportObjs: { + ProfBegin("Build Import Table"); + + 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); + } + } + } + } + + LNK_InputObjList static_imports = lnk_import_table_serialize(scratch.arena, imptab_static, str8_skip_last_slash(config->image_name), config->machine); + LNK_InputObjList delayed_imports = lnk_import_table_serialize(scratch.arena, imptab_delayed, str8_skip_last_slash(config->image_name), config->machine); + + lnk_input_obj_list_concat_in_place(&input_obj_list, &static_imports); + lnk_input_obj_list_concat_in_place(&input_obj_list, &delayed_imports); + + ProfEnd(); + } break; + case State_BuildExportObjs: { + ProfBegin("Build Export Table"); + + ProfBeginV("Push Exports [Count %u]", export_symbol_list.count); + for (LNK_ExportParse *exp_parse = export_symbol_list.first; exp_parse != 0; exp_parse = exp_parse->next) { + lnk_export_table_push_export(exptab, symtab, exp_parse); + } + ProfEnd(); + + LNK_InputObjList export_objs = lnk_export_table_serialize(scratch.arena, exptab, str8_skip_last_slash(config->image_name), config->machine); + lnk_input_obj_list_concat_in_place(&input_obj_list, &export_objs); + + ProfEnd(); + } break; + case State_BuildDebugDirectoryObjs: { + ProfBegin("Build Debug Directory"); + + LNK_InputObjList debug_objs = lnk_build_debug_directory_objs(scratch.arena, config); + lnk_input_obj_list_concat_in_place(&input_obj_list, &debug_objs); + + ProfEnd(); + } break; case State_BuildAndInputResObj: { String8List res_data_list = {0}; String8List res_path_list = {0}; @@ -3688,10 +3733,7 @@ lnk_run(int argc, char **argv) ProfBegin("Build * Resources *"); String8 obj_name = str8_lit("* Resources *"); - String8 obj_data = lnk_obj_from_res_file_list(tp, - tp_arena->v[0], - sectab, - symtab, + String8 obj_data = lnk_obj_from_res_file_list(scratch.arena, res_data_list, res_path_list, config->machine, @@ -3757,16 +3799,6 @@ lnk_run(int argc, char **argv) MemoryZeroStruct(&lookup_weak_list); ProfEnd(); } break; - case State_CheckUnusedDelayLoads: { - 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); - } - } - } - } break; case State_ReportUnresolvedSymbols: { // report unresolved symbols for (LNK_SymbolNode *node = unresolved_undef_list.first; node != 0; node = node->next) { @@ -3782,43 +3814,6 @@ lnk_run(int argc, char **argv) lnk_discard_meta_data_sections(sectab); ProfEnd(); } break; - case State_BuildDebugDirectory: { - ProfBegin("Build Debug Directory"); - - // push debug directory layout chunks - LNK_Section *debug_sect = lnk_section_table_search(sectab, str8_lit(".rdata")); - LNK_Chunk *debug_chunk = lnk_section_push_chunk_list(debug_sect, debug_sect->root, str8_zero()); - LNK_Chunk *debug_dir_array_chunk = lnk_section_push_chunk_list(debug_sect, debug_chunk, str8_zero()); - - // push symbols for PE directory patch - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_DEBUG_DIR_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_dir_array_chunk, 0, 0, 0); - - // debug entry for PDB - if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { - lnk_build_debug_pdb(sectab, symtab, debug_sect, debug_dir_array_chunk, config->time_stamp, config->guid, config->age, config->pdb_alt_path); - } - - // debug entry for RDI - if (config->rad_debug == LNK_SwitchState_Yes) { - lnk_build_debug_rdi(sectab, symtab, debug_sect, debug_dir_array_chunk, config->time_stamp, config->guid, config->rad_debug_alt_path); - } - - ProfEnd(); - } break; - case State_BuildExportTable: { - ProfBegin("Build Export Table"); - - ProfBeginV("Push Exports [Count %u]", export_symbol_list.count); - for (LNK_ExportParse *exp_parse = export_symbol_list.first; exp_parse != 0; exp_parse = exp_parse->next) { - lnk_export_table_push_export(exptab, symtab, exp_parse); - } - ProfEnd(); - - // build export table section - lnk_build_edata(exptab, sectab, symtab, config->image_name, config->machine); - - ProfEnd(); - } break; case State_MergeSections: { ProfBegin("Merge Sections"); lnk_section_table_merge(sectab, merge_list); @@ -4151,6 +4146,22 @@ lnk_run(int argc, char **argv) continue; } } + + if (build_import_objs) { + build_import_objs = 0; + state_list_push(scratch.arena, state_list, State_BuildImportObjs); + continue; + } + if (build_export_objs) { + build_export_objs = 0; + state_list_push(scratch.arena, state_list, State_BuildExportObjs); + continue; + } + if (build_debug_directory_objs) { + build_debug_directory_objs = 0; + state_list_push(scratch.arena, state_list, State_BuildDebugDirectoryObjs); + continue; + } if (build_res_obj) { build_res_obj = 0; state_list_push(scratch.arena, state_list, State_BuildAndInputResObj); @@ -4161,29 +4172,13 @@ lnk_run(int argc, char **argv) state_list_push(scratch.arena, state_list, State_BuildAndInputLinkerObj); continue; } - if (check_unused_delay_loads) { - check_unused_delay_loads = 0; - state_list_push(scratch.arena, state_list, State_CheckUnusedDelayLoads); - continue; - } - - /// --- inputs are ready --- - + + if (discard_meta_data_sections) { discard_meta_data_sections = 0; state_list_push(scratch.arena, state_list, State_DiscardMetaDataSections); continue; } - if (build_debug_directory) { - build_debug_directory = 0; - state_list_push(scratch.arena, state_list, State_BuildDebugDirectory); - continue; - } - if (build_export_table) { - build_export_table = 0; - state_list_push(scratch.arena, state_list, State_BuildExportTable); - continue; - } if (merge_sections) { merge_sections = 0; state_list_push(scratch.arena, state_list, State_MergeSections); @@ -4199,6 +4194,8 @@ lnk_run(int argc, char **argv) state_list_push(scratch.arena, state_list, State_BuildBaseRelocs); continue; } + + if (image_data.size == 0) { state_list_push(scratch.arena, state_list, State_FinalizeImage); continue; diff --git a/src/linker/lnk.h b/src/linker/lnk.h index ba3e3281..275fd652 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -103,6 +103,11 @@ //////////////////////////////// +#define LNK_COFF_RELOC_FILE_OFFSET32 0x1000 +#define LNK_COFF_RELOC_SECT_SIZE32 0x1001 + +//////////////////////////////// + typedef enum { LNK_InputSource_CmdLine, // specified on command line @@ -267,7 +272,7 @@ internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, Str internal void lnk_serialize_pe_resource_tree(COFF_ObjWriter *obj_writer, PE_ResourceDir *root_dir); internal void lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array); internal String8 lnk_make_res_obj(Arena *arena, PE_ResourceDir *root_dir, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 path, String8 cwd_path, String8 exe_path, String8List res_file_list, MD5Hash *res_hash_array); -internal String8 lnk_obj_from_res_file_list(TP_Context *tp, Arena *arena, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); +internal String8 lnk_obj_from_res_file_list(Arena *arena, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); //////////////////////////////// // Debug diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index ad6dd4ba..761579ea 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -16,7 +16,7 @@ typedef enum LNK_Error_IllData, LNK_Error_IllExport, LNK_Error_IncomatibleCmdOptions, - LNK_Error_IncompatibleObj, + LNK_Error_IncompatibleMachine, LNK_Error_InvalidPrecompLeafCount, LNK_Error_InvalidStartIndex, LNK_Error_NoAccess, diff --git a/src/linker/lnk_export_table.c b/src/linker/lnk_export_table.c index c8112392..d2f9fc10 100644 --- a/src/linker/lnk_export_table.c +++ b/src/linker/lnk_export_table.c @@ -170,17 +170,11 @@ lnk_export_array_from_list(Arena *arena, LNK_ExportList list) return arr; } -internal void -lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 image_name, COFF_MachineType machine) +internal LNK_InputObjList +lnk_export_table_serialize(Arena *arena, LNK_ExportTable *exptab, String8 image_name, COFF_MachineType machine) { - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - // is export table empty? - if (exptab->name_export_ht->count == 0 && exptab->noname_export_ht->count == 0) { - goto exit; - } - + Temp scratch = scratch_begin(&arena, 1); + // compute ordinal bounds U64 ordinal_low; for (ordinal_low = 0; ordinal_low < exptab->max_ordinal; ++ordinal_low) { @@ -195,96 +189,117 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *sectab, LNK_SymbolTab } } - LNK_Section *edata = lnk_section_table_search(sectab, str8_lit(".edata")); - - // push header - PE_ExportTableHeader *header = push_array(edata->arena, PE_ExportTableHeader, 1); + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, machine); + + // fill out export table header + PE_ExportTableHeader *header = push_array(obj_writer->arena, PE_ExportTableHeader, 1); header->ordinal_base = safe_cast_u16(ordinal_low + 1); header->export_address_table_count = safe_cast_u32(exptab->name_export_ht->count + exptab->noname_export_ht->count); header->name_pointer_table_count = safe_cast_u32(exptab->name_export_ht->count); - - String8 header_data = str8((U8*)header, sizeof(*header)); - String8 image_name_cstr = push_cstr(edata->arena, str8_skip_last_slash(image_name)); - - // push edata chunks - LNK_Chunk *header_chunk = lnk_section_push_chunk_data(edata, edata->root, header_data, str8_lit("a")); - LNK_Chunk *voff_table_chunk = lnk_section_push_chunk_list(edata, edata->root, str8_lit("b")); - LNK_Chunk *name_voff_table_chunk = lnk_section_push_chunk_list(edata, edata->root, str8_lit("c")); - LNK_Chunk *ordinal_table_chunk = lnk_section_push_chunk_list(edata, edata->root, str8_lit("d")); - LNK_Chunk *string_buffer_chunk = lnk_section_push_chunk_list(edata, edata->root, str8_lit("e")); - LNK_Chunk *image_name_chunk = lnk_section_push_chunk_data(edata, string_buffer_chunk, image_name_cstr, str8(0,0)); - lnk_chunk_set_debugf(edata->arena, header_chunk, "EXPORT_HEADER"); - lnk_chunk_set_debugf(edata->arena, voff_table_chunk, "EXPORT_ADDRESS_TABLE"); - lnk_chunk_set_debugf(edata->arena, name_voff_table_chunk, "EXPORT_NAME_VOFF_TABLE"); - lnk_chunk_set_debugf(edata->arena, ordinal_table_chunk, "EXPORT_ORDINAL_TABLE"); - lnk_chunk_set_debugf(edata->arena, string_buffer_chunk, "EXPORT_STRING_BUFFER"); - lnk_chunk_set_debugf(edata->arena, image_name_chunk, "EXPORT_IMAGE_NAME"); - - LNK_Symbol *image_name_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0); - LNK_Symbol *address_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0); - LNK_Symbol *name_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0); - LNK_Symbol *ordinal_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0); - - // patch header fields - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTableHeader, name_voff), image_name_symbol); - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTableHeader, export_address_table_voff), address_table_symbol); - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTableHeader, name_pointer_table_voff), name_table_symbol); - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTableHeader, ordinal_table_voff), ordinal_table_symbol); - - // reserve virtual offset chunks - LNK_Chunk **ordinal_voff_map = push_array(scratch.arena, LNK_Chunk *, exptab->max_ordinal); - for (U32 i = ordinal_low; i <= ordinal_high; i += 1) { - String8 sort_index = str8_from_bits_u32(edata->arena, i); - LNK_Chunk *voff_chunk = lnk_section_push_chunk_bss(edata, voff_table_chunk, exptab->voff_size, sort_index); - ordinal_voff_map[i] = voff_chunk; + + + // make iamge name c-string + String8 image_name_cstr = push_cstr(obj_writer->arena, image_name); + + // push sections + COFF_ObjSection *header_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$1"), LNK_EDATA_SECTION_FLAGS, str8_struct(header)); + COFF_ObjSection *voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$2"), LNK_EDATA_SECTION_FLAGS, str8_zero()); + COFF_ObjSection *name_voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$3"), LNK_EDATA_SECTION_FLAGS, str8_zero()); + COFF_ObjSection *ordinal_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$4"), LNK_EDATA_SECTION_FLAGS, str8_zero()); + COFF_ObjSection *string_buffer_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$5"), LNK_EDATA_SECTION_FLAGS, str8_zero()); + COFF_ObjSection *image_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$6"), LNK_EDATA_SECTION_FLAGS, image_name_cstr); + + // push symbols + COFF_ObjSymbol *image_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_NAME_VOFF"), 0, image_name_sect); + COFF_ObjSymbol *address_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_ADDRESS_TABLE_VOFF"), 0, voff_table_sect); + COFF_ObjSymbol *name_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_NAME_POINTER_VOFF"), 0, name_voff_table_sect); + COFF_ObjSymbol *ordinal_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_ORDINAL_TABLE_VOFF"), 0, ordinal_table_sect); + + // patch export table header + switch (machine) { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { + coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_voff), image_name_symbol, COFF_Reloc_X64_Addr32Nb); + coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, export_address_table_voff), address_table_symbol, COFF_Reloc_X64_Addr32Nb); + coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_pointer_table_voff), name_table_symbol, COFF_Reloc_X64_Addr32Nb); + coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, ordinal_table_voff), ordinal_table_symbol, COFF_Reloc_X64_Addr32Nb); + } break; + default: { NotImplemented; } break; } - + + B8 *is_ordinal_bound = push_array(scratch.arena, B8, exptab->max_ordinal); HashTable *exp_ht_arr[] = { exptab->name_export_ht, exptab->noname_export_ht }; - for (HashTable **ht_ptr = &exp_ht_arr[0], **ht_opl = ht_ptr + ArrayCount(exp_ht_arr); - ht_ptr < ht_opl; - ht_ptr += 1) { - KeyValuePair *kv_arr = key_value_pairs_from_hash_table(scratch.arena, *ht_ptr); - for (U64 i = 0; i < (*ht_ptr)->count; ++i) { - LNK_Export *exp = kv_arr[i].value_raw; - String8 name_cstr = push_cstr(edata->arena, exp->name); - - // push name string - LNK_Chunk *name_chunk = lnk_section_push_chunk_data(edata, string_buffer_chunk, name_cstr, str8(0,0)); - lnk_chunk_set_debugf(edata->arena, name_chunk, "export: %S", name_cstr); - - // push name symbol - String8 name_export_name = push_str8f(symtab->arena->v[0], "export.%S", name_cstr); - LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); - - // name voff - LNK_Chunk *voff_chunk = lnk_section_push_chunk_bss(edata, name_voff_table_chunk, exptab->voff_size, /* export table must be sorted lexically: */ name_cstr); - lnk_chunk_set_debugf(edata->arena, voff_chunk, "voff for export name %S", name_cstr); - - // link reloc with name symbol - lnk_section_push_reloc(edata, voff_chunk, LNK_Reloc_VIRT_OFF_32, 0, name_symbol); + for (U64 ht_idx = 0; ht_idx < ArrayCount(exp_ht_arr); ht_idx += 1) { + HashTable *ht = exp_ht_arr[ht_idx]; - // make ordinal relative - U16 *ordinal_ptr = push_array(edata->arena, U16, 1); - *ordinal_ptr = (exp->ordinal - ordinal_low); - - // ordinal - LNK_Chunk *ordinal_chunk = lnk_section_push_chunk_raw(edata, ordinal_table_chunk, ordinal_ptr, sizeof(*ordinal_ptr), /* ordinal table is parallel to the name table: */ name_cstr); - lnk_chunk_set_debugf(edata->arena, ordinal_chunk, "ordinal %u for %S", exp->ordinal, exp->name); - - // (ordinal - ordinal_low) -> export virtual offset - if ( ! is_ordinal_bound[exp->ordinal]) { - is_ordinal_bound[exp->ordinal] = 1; - LNK_Chunk *export_func_voff_chunk = ordinal_voff_map[exp->ordinal]; - lnk_section_push_reloc(edata, export_func_voff_chunk, LNK_Reloc_VIRT_OFF_32, 0, exp->symbol); + KeyValuePair *kv_arr = key_value_pairs_from_hash_table(scratch.arena, exptab->name_export_ht); + + // named exports must be lexically sorted + if (ht_idx == 0) { + sort_key_value_pairs_as_string_sensitive(kv_arr, exptab->name_export_ht->count); + } + + for (U64 i = 0; i < ht->count; i += 1) { + LNK_Export *exp = kv_arr[i].value_raw; + + { + U64 export_name_offset = string_buffer_sect->data.total_size; + String8 export_name_cstr = push_cstr(obj_writer->arena, exp->name); + str8_list_push(obj_writer->arena, &string_buffer_sect->data, export_name_cstr); + + String8 export_name_symbol_name = push_str8f(obj_writer->arena, "EXPORT.%S", exp->name); + COFF_ObjSymbol *export_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, export_name_symbol_name, export_name_offset, string_buffer_sect); + + U64 export_name_voff_offset = name_voff_table_sect->data.total_size; + U64 export_name_voff_size = sizeof(U32); + U8 *export_name_voff = push_array(obj_writer->arena, U8, export_name_voff_size); + str8_list_push(obj_writer->arena, &name_voff_table_sect->data, str8_array(export_name_voff, export_name_voff_size)); + + switch (machine) { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { coff_obj_writer_section_push_reloc(obj_writer, name_voff_table_sect, export_name_voff_offset, export_name_symbol, COFF_Reloc_X64_Addr32Nb); } break; + default: { NotImplemented; } break; + } + } + + { + 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)); + + if ( ! is_ordinal_bound[exp->ordinal]) { + is_ordinal_bound[exp->ordinal] = 1; + + 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 *symbol = coff_obj_writer_push_symbol_undef(obj_writer, exp->name); + switch (machine) { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { coff_obj_writer_section_push_reloc(obj_writer, voff_table_sect, voff_offset, symbol, COFF_Reloc_X64_Addr32Nb); } break; + default: { NotImplemented; } break; + } + } } } } - -exit:; + + + String8 obj = coff_obj_writer_serialize(arena, obj_writer); + coff_obj_writer_release(&obj_writer); + + LNK_InputObjList result = {0}; + LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); + input->path = str8_lit("* Exports *"); + input->dedup_id = input->path; + input->data = obj; + scratch_end(scratch); - ProfEnd(); + return result; } + diff --git a/src/linker/lnk_export_table.h b/src/linker/lnk_export_table.h index e0ccb8ed..42cd3ed7 100644 --- a/src/linker/lnk_export_table.h +++ b/src/linker/lnk_export_table.h @@ -40,5 +40,5 @@ typedef struct LNK_ExportTable internal LNK_ExportTable * lnk_export_table_alloc(void); internal void lnk_export_table_release(LNK_ExportTable **exptab_ptr); internal LNK_Export * lnk_export_table_search(LNK_ExportTable *exptab, String8 name); -internal void lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 image_name, COFF_MachineType machine); +internal LNK_InputObjList lnk_export_table_serialize(Arena *arena, LNK_ExportTable *exptab, String8 image_name, COFF_MachineType machine); diff --git a/src/linker/lnk_import_table.c b/src/linker/lnk_import_table.c index c1973f30..6b474897 100644 --- a/src/linker/lnk_import_table.c +++ b/src/linker/lnk_import_table.c @@ -2,120 +2,20 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal LNK_ImportTable * -lnk_import_table_alloc_static(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine) +lnk_import_table_alloc(LNK_ImportTableFlags flags) { ProfBeginFunction(); - - LNK_Section *data_sect = lnk_section_table_push(sectab, str8_lit(".idata"), LNK_IDATA_SECTION_FLAGS); - LNK_Section *code_sect = lnk_section_table_search(sectab, str8_lit(".text")); - - LNK_Chunk *dll_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *int_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *iat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *ilt_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, code_sect->root, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, dll_table_chunk, "DLL_TABLE" ); - lnk_chunk_set_debugf(data_sect->arena, int_chunk, "IMPORT_NAME_TABLE" ); - lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IMPORT_ADDRESS_TABLE"); - lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "IMPORT_LOOKUP_TABLE" ); - lnk_chunk_set_debugf(data_sect->arena, code_chunk, "IMPORT_TABLE_CODE" ); - LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_ImportEntry)), str8_lit("zzzzz")); - lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR"); - - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); - Arena *arena = arena_alloc(); LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1); - imptab->machine = machine; imptab->arena = arena; - imptab->data_sect = data_sect; - imptab->code_sect = code_sect; - imptab->dll_table_chunk = dll_table_chunk; - imptab->int_chunk = int_chunk; - imptab->iat_chunk = iat_chunk; - imptab->ilt_chunk = ilt_chunk; - imptab->code_chunk = code_chunk; + imptab->flags = flags; imptab->dll_ht = hash_table_init(arena, LNK_IMPORT_DLL_HASH_TABLE_BUCKET_COUNT); ProfEnd(); return imptab; } -internal LNK_ImportTable * -lnk_import_table_alloc_delayed(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable) -{ - ProfBeginFunction(); - - LNK_Section *data_sect = lnk_section_table_push(sectab, str8_lit(".didat"), LNK_DEBUG_DIR_SECTION_FLAGS); - LNK_Section *code_sect = lnk_section_table_search(sectab, str8_lit(".text")); - - LNK_Chunk *dll_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *int_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *handle_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *iat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *ilt_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *biat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *uiat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); - LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, code_sect->root, str8_zero()); - - LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_DelayedImportEntry)), str8_lit("~0")); - lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR"); - - if (is_unloadable) { - U64 import_size = coff_word_size_from_machine(machine); - LNK_Chunk *null_uiat_chunk = lnk_section_push_chunk_bss(data_sect, uiat_chunk, import_size, str8_lit("~1")); - lnk_chunk_set_debugf(data_sect->arena, null_uiat_chunk, "UIAT_TERMINATOR"); - } - - if (is_bindable) { - U64 import_size = coff_word_size_from_machine(machine); - LNK_Chunk *null_biat_chunk = lnk_section_push_chunk_bss(data_sect, biat_chunk, import_size, str8_lit("~2")); - lnk_chunk_set_debugf(data_sect->arena, null_biat_chunk, "BIAT_TERMINATOR"); - } - - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0); - lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); - - LNK_ImportTableFlags flags = 0; - if (is_unloadable) { - flags |= LNK_ImportTableFlag_EmitUiat; - } - if (is_bindable) { - flags |= LNK_ImportTableFlag_EmitBiat; - } - - Arena *arena = arena_alloc(); - LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1); - imptab->arena = arena; - imptab->machine = machine; - imptab->data_sect = data_sect; - imptab->code_sect = code_sect; - imptab->dll_table_chunk = dll_table_chunk; - imptab->int_chunk = int_chunk; - imptab->handle_table_chunk = handle_table_chunk; - imptab->iat_chunk = iat_chunk; - imptab->ilt_chunk = ilt_chunk; - imptab->biat_chunk = biat_chunk; - imptab->uiat_chunk = uiat_chunk; - imptab->code_chunk = code_chunk; - imptab->flags = flags; - imptab->dll_ht = hash_table_init(arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT); - - ProfEnd(); - return imptab; -} - internal void lnk_import_table_release(LNK_ImportTable **imptab_ptr) { @@ -148,88 +48,61 @@ lnk_import_table_push_func_node(LNK_ImportTable *imptab, LNK_ImportDLL *dll, LNK internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name) { - KeyValuePair *kv = hash_table_search_path(imptab->dll_ht, name); - if (kv) { - Assert(kv->value_raw); - return kv->value_raw; - } - return 0; + return hash_table_search_path_raw(imptab->dll_ht, name); } internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name) { - KeyValuePair *kv = hash_table_search_string(dll->func_ht, name); - if (kv) { - Assert(kv->value_raw); - return kv->value_raw; - } - return 0; + LNK_ImportFunc *func = 0; + hash_table_search_string_raw(dll->func_ht, name, &func); + return func; } internal LNK_ImportDLL * -lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine) +lnk_import_table_push_dll_static(LNK_ImportTable *imptab, String8 dll_name, COFF_MachineType machine) { ProfBeginFunction(); - // TODO: error handle - Assert(imptab->machine == machine); + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, 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); + + 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_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); - LNK_Section *data_sect = imptab->data_sect; - LNK_Section *code_sect = imptab->code_sect; - - LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, str8_zero()); - LNK_Chunk *ilt_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->ilt_chunk, str8_zero()); - LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero()); - LNK_Chunk *code_table_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, int_table_chunk, "%S.INT", dll_name); - lnk_chunk_set_debugf(data_sect->arena, ilt_table_chunk, "%S.ILT", dll_name); - lnk_chunk_set_debugf(data_sect->arena, iat_table_chunk, "%S.IAT", dll_name); - lnk_chunk_set_debugf(data_sect->arena, code_table_chunk, "%S.CODE", dll_name); - - String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.lookup_table_voff", dll_name); - LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0); - - String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "%S.import_addr_table_voff", dll_name); - LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); - - String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name); - LNK_Chunk *dll_name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, dll_name_cstr, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, dll_name_chunk, "DLL name chunk (%S)", dll_name); - - String8 dll_name_voff_name = push_str8f(symtab->arena->v[0], "%S.name_voff", dll_name); - LNK_Symbol *dll_name_voff_symbol = lnk_symbol_table_push_defined_chunk(symtab, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0); - - // chunk for dll directory entry - PE_ImportEntry *dir = push_array(imptab->arena, PE_ImportEntry, 1); - LNK_Chunk *dll_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, str8_struct(dir), str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, dll_chunk, "DLL Directory for %S", dll_name); - - // patch dll import fields - lnk_section_push_reloc(data_sect, dll_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ImportEntry, lookup_table_voff), ilt_symbol); - lnk_section_push_reloc(data_sect, dll_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ImportEntry, name_voff), dll_name_voff_symbol); - lnk_section_push_reloc(data_sect, dll_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ImportEntry, import_addr_table_voff), iat_symbol); - - U64 import_size = coff_word_size_from_machine(machine); - - // null entry to terminate import lookup table array - LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, str8(0, import_size), str8_lit("zzzzzz")); - lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name); - - // null entry to terminate import address table array - LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, str8(0, import_size), str8_lit("zzzzzz")); - lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name); + 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; + } // push to list - LNK_ImportDLL *dll = push_array(imptab->arena, LNK_ImportDLL, 1); - dll->name = push_str8_copy(imptab->arena, dll_name); - dll->dll_chunk = dll_chunk; - dll->int_table_chunk = int_table_chunk; - dll->ilt_table_chunk = ilt_table_chunk; - dll->iat_table_chunk = iat_table_chunk; - dll->code_table_chunk = code_table_chunk; - dll->machine = machine; - dll->func_ht = hash_table_init(imptab->arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT); + LNK_ImportDLL *dll = push_array(imptab->arena, LNK_ImportDLL, 1); + dll->obj_writer = obj_writer; + dll->name = push_str8_copy(imptab->arena, dll_name); + dll->dll_sect = dll_sect; + dll->int_sect = int_sect; + dll->ilt_sect = ilt_sect; + dll->iat_sect = iat_sect; + dll->code_sect = code_sect; + dll->func_ht = hash_table_init(imptab->arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT); lnk_import_table_push_dll_node(imptab, dll); @@ -238,150 +111,82 @@ lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symta } internal LNK_ImportDLL * -lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine) +lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, String8 dll_name, COFF_MachineType machine) { ProfBeginFunction(); - Assert(imptab->machine == machine); - + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, machine); + + // import descriptor + PE_DelayedImportEntry *impdesc = push_array(obj_writer->arena, PE_DelayedImportEntry, 1); + impdesc->attributes = 1; + + // DLL name cstring + String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name); + + // DLL handle U64 handle_size = coff_word_size_from_machine(machine); - U64 import_size = coff_word_size_from_machine(machine); - - // shortcuts - LNK_Section *data_sect = imptab->data_sect; - LNK_Section *code_sect = imptab->code_sect; - - // init DLL entry - PE_DelayedImportEntry *imp_desc = push_array(data_sect->arena, PE_DelayedImportEntry, 1); - imp_desc->attributes = 1; - imp_desc->name_voff = 0; // relocated - imp_desc->module_handle_voff = 0; // relocated - imp_desc->iat_voff = 0; // relocated - imp_desc->name_table_voff = 0; // relocated - imp_desc->bound_table_voff = 0; // relocated - imp_desc->unload_table_voff = 0; // relocated - imp_desc->time_stamp = 0; - - // emit entry chunk - String8 imp_desc_data = str8_struct(imp_desc); - LNK_Chunk *imp_desc_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, imp_desc_data, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, imp_desc_chunk, "%S.IMP_DESC", dll_name); - - // emit entry symbol - String8 imp_desc_name = push_str8f(symtab->arena->v[0], "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name); - LNK_Symbol *imp_desc_symbol = lnk_symbol_table_push_defined_chunk(symtab, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0); - - // emit string table chunk - LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, int_table_chunk, "%S.DELAY_INT", dll_name); - - String8 int_table_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.int", dll_name); - LNK_Symbol *int_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0); - - LNK_Chunk *null_string_chunk = lnk_section_push_chunk_list(data_sect, int_table_chunk, str8_lit("zzzzz")); - lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "%S.STRING_TABLE_NULL", dll_name); - - // emit DLL name chunk - String8 name_chunk_data = push_cstr(data_sect->arena, dll_name); - LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, name_chunk, "%S.DELAY_NAME", dll_name); - - String8 name_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.name", dll_name); - LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); - - // patch DLL name voff - lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_voff), name_symbol); - - // emit DLL handle chunk - LNK_Chunk *handle_chunk = lnk_section_push_chunk_bss(data_sect, imptab->handle_table_chunk, handle_size, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, handle_chunk, "%S.DELAY_HANDLE", dll_name); - - String8 handle_name = push_str8f(symtab->arena->v[0], "delayed.%S.handle", dll_name); - LNK_Symbol *handle_symbol = lnk_symbol_table_push_defined_chunk(symtab, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0); - - // patch DLL handle voff - lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol); - - // emit IAT chunk - LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, iat_table_chunk, "%S.DELAY_IAT", dll_name); - - String8 iat_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.iat", dll_name); - LNK_Symbol *iat_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); - - LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, str8_lit("zzzzzz")); - lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S.DELAY_IAT_TERMINATOR", dll_name); - - // emit ILT chunk - LNK_Chunk *ilt_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->ilt_chunk, str8_zero()); - - LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, str8_lit("zzzzzz")); - lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S.DELAY_ILT_TERMINATOR", dll_name); - - String8 ilt_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.ilt", dll_name); - LNK_Symbol *ilt_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0); - - // patch import address table voff - lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_table_symbol); - - // patch string table voff - lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_table_voff), ilt_table_symbol); - - // emit bound table chunk - LNK_Chunk *biat_chunk = 0; + U8 *handle = push_array(obj_writer->arena, U8, handle_size); + + // import align + 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(".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 *biat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$8"), LNK_IDATA_SECTION_FLAGS|import_align, str8_zero()); + COFF_ObjSection *uiat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$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)); + + 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; + } + if (imptab->flags & LNK_ImportTableFlag_EmitBiat) { - biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, biat_chunk, "%S.DELAY_BIAT", dll_name); - - String8 biat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.BIAT", dll_name); - LNK_Symbol *biat_symbol = lnk_symbol_table_push_defined_chunk(symtab, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0); - - // patch BIAT field off - lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol); + 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); } - - // emit unload table chunk - LNK_Chunk *uiat_chunk = NULL; if (imptab->flags & LNK_ImportTableFlag_EmitUiat) { - uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero()); - lnk_chunk_set_debugf(data_sect->arena, uiat_chunk, "%S.DELAY_UIAT", dll_name); - - String8 uiat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.UIAT", dll_name); - LNK_Symbol *uiat_symbol = lnk_symbol_table_push_defined_chunk(symtab, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0); - - // patch UIAT field voff - lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol); + 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); } - // emit chunk for DLL thunk/load code - LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero()); - lnk_chunk_set_debugf(code_sect->arena, code_chunk, "%S.DLAY_CODE", dll_name); - // emit tail merge - LNK_Chunk *tail_merge_chunk = 0; + COFF_ObjSymbol *tail_merge_symbol = 0; switch (machine) { - case COFF_MachineType_X64: { - LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main); - tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol); - lnk_chunk_set_debugf(code_sect->arena, code_chunk, "%S.X64_TAIL_MERGE", dll_name); - } break; - default: { - lnk_not_implemented("TODO: __tailMerge for %S", coff_string_from_machine_type(machine)); - } break; + 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; + default: { NotImplemented; } break; } // fill out result LNK_ImportDLL *dll = push_array(imptab->arena, LNK_ImportDLL, 1); - dll->dll_chunk = imp_desc_chunk; - dll->int_table_chunk = int_table_chunk; - dll->iat_table_chunk = iat_table_chunk; - dll->ilt_table_chunk = ilt_table_chunk; - dll->biat_table_chunk = biat_chunk; - dll->uiat_table_chunk = uiat_chunk; - dll->code_table_chunk = code_chunk; - dll->tail_merge_symbol = lnk_emit_tail_merge_symbol(symtab, tail_merge_chunk, dll_name); + dll->dll_sect = dll_sect; + dll->int_sect = int_sect; + dll->iat_sect = iat_sect; + dll->ilt_sect = ilt_sect; + dll->biat_sect = biat_sect; + dll->uiat_sect = uiat_sect; + dll->code_sect = code_sect; + dll->tail_merge_symbol = tail_merge_symbol; dll->name = push_str8_copy(imptab->arena, dll_name); - dll->machine = machine; dll->func_ht = hash_table_init(imptab->arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT); lnk_import_table_push_dll_node(imptab, dll); @@ -391,91 +196,61 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt } internal LNK_ImportFunc * -lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header) +lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header) { ProfBeginFunction(); - - Assert(header->machine == dll->machine); // TODO: error handling - LNK_Section *data_sect = imptab->data_sect; - LNK_Section *code_sect = imptab->code_sect; - - LNK_Chunk *int_table_chunk = dll->int_table_chunk; - LNK_Chunk *ilt_table_chunk = dll->ilt_table_chunk; - LNK_Chunk *iat_table_chunk = dll->iat_table_chunk; - LNK_Chunk *code_table_chunk = dll->code_table_chunk; - - LNK_Chunk *ilt_chunk = g_null_chunk_ptr; - LNK_Chunk *iat_chunk = g_null_chunk_ptr; - - U64 import_size = coff_word_size_from_machine(dll->machine); - - // generate sort index (optional) - String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint_or_ordinal); + COFF_ObjWriter *obj_writer = dll->obj_writer; + String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", header->func_name); + U64 iat_offset = dll->iat_sect->data.total_size; + U64 ilt_offset = dll->ilt_sect->data.total_size; + U64 int_offset = dll->int_sect->data.total_size; + + COFF_ObjSymbol *iat_symbol = 0; switch (header->import_by) { case COFF_ImportBy_Ordinal: { - String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint_or_ordinal); - ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index); - iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, ordinal_data, sort_index); - lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "ILT entry for %S.%u", dll->name, header->hint_or_ordinal); - lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IAT entry for %S.%u", dll->name, header->hint_or_ordinal); + String8 ordinal_data = coff_ordinal_data_from_hint(obj_writer->arena, header->machine, header->hint_or_ordinal); + str8_list_push(obj_writer->arena, &dll->ilt_sect->data, ordinal_data); + str8_list_push(obj_writer->arena, &dll->iat_sect->data, ordinal_data); - // associate chunks - lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk); + iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_offset, dll->iat_sect); } 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()); - lnk_chunk_set_debugf(data_sect->arena, int_chunk, "INT entry for %S.%S (Hint: %u)", dll->name, header->func_name, header->hint_or_ordinal); - - // create symbol for lookup chunk - String8 int_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.name", dll->name, header->func_name); - LNK_Symbol *int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); - - // in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses. - ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index); - iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index); - lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "ILT entry for %S.%S", dll->name, header->func_name); - lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IAT entry for %S.%S", dll->name, header->func_name); + String8 int_data = coff_make_import_lookup(obj_writer->arena, header->hint_or_ordinal, header->func_name); + str8_list_push(obj_writer->arena, &dll->int_sect->data, int_data); - // associate chunks - lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk); - lnk_section_associate_chunks(data_sect, iat_chunk, int_chunk); + // create symbol for lookup entry + COFF_ObjSymbol *int_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll->int_sect->name, int_offset, dll->int_sect); + + // in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses + U64 import_size = coff_word_size_from_machine(header->machine); + U8 *import_entry = push_array(obj_writer->arena, U8, import_size); + str8_list_push(obj_writer->arena, &dll->ilt_sect->data, str8_array(import_entry, import_size)); + str8_list_push(obj_writer->arena, &dll->iat_sect->data, str8_array(import_entry, import_size)); + + iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_offset, dll->iat_sect); // patch IAT and ILT - lnk_section_push_reloc(data_sect, ilt_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol); - lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol); + coff_obj_writer_section_push_reloc(obj_writer, dll->ilt_sect, ilt_offset, int_symbol, COFF_Reloc_X64_Addr32Nb); + coff_obj_writer_section_push_reloc(obj_writer, dll->iat_sect, iat_offset, int_symbol, COFF_Reloc_X64_Addr32Nb); } break; case COFF_ImportBy_Undecorate: { - lnk_not_implemented("TODO: COFF_ImportBy_Undecorate"); + NotImplemented; } break; case COFF_ImportBy_NameNoPrefix: { - lnk_not_implemented("TODO: COFF_ImportBy_NameNoPrefix"); + NotImplemented; } break; } - - String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.ilt", dll->name, header->func_name); - String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", 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); - LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); // generate thunks - LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; + COFF_ObjSymbol *jmp_thunk_symbol = 0; if (header->type == COFF_ImportHeader_Code) { - switch (dll->machine) { - case COFF_MachineType_X64: { - // generate jump thunk - LNK_Chunk *jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol); - lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk); - lnk_chunk_set_debugf(data_sect->arena, jmp_thunk_chunk, "Jump thunk to %S.%S", dll->name, iat_symbol->name); - - // push jump thunk symbol - String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena->v[0], header->func_name); - jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, jmp_thunk_symbol_name); - } break; - default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break; + switch (header->machine) { + case COFF_MachineType_Unknown: {} break; + case COFF_MachineType_X64: { jmp_thunk_symbol = lnk_emit_indirect_jump_thunk_x64(obj_writer, dll->code_sect, iat_symbol, header->func_name); } break; + default: { NotImplemented; } break; } } @@ -483,7 +258,7 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1); func->name = push_str8_copy(imptab->arena, header->func_name); func->thunk_symbol_name = push_str8_copy(imptab->arena, jmp_thunk_symbol->name); - func->iat_symbol_name = push_str8_copy(imptab->arena, iat_symbol->name); + func->iat_symbol_name = iat_symbol_name; lnk_import_table_push_func_node(imptab, dll, func); @@ -492,34 +267,18 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt } internal LNK_ImportFunc * -lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header) +lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header) { +#if 0 ProfBeginFunction(); + COFF_ObjWriter *obj_writer = dll->obj_writer; Assert(dll->machine == header->machine); // TODO: error handle U64 import_size = coff_word_size_from_machine(dll->machine); - LNK_Section *data_sect = imptab->data_sect; - LNK_Section *code_sect = imptab->code_sect; - - LNK_Chunk *int_table_chunk = dll->int_table_chunk; - LNK_Chunk *ilt_table_chunk = dll->ilt_table_chunk; - LNK_Chunk *iat_table_chunk = dll->iat_table_chunk; - LNK_Chunk *biat_table_chunk = dll->biat_table_chunk; - LNK_Chunk *uiat_table_chunk = dll->uiat_table_chunk; - LNK_Chunk *code_table_chunk = dll->code_table_chunk; - - LNK_Chunk *ilt_chunk = g_null_chunk_ptr; - LNK_Chunk *iat_chunk = g_null_chunk_ptr; - LNK_Chunk *uiat_chunk = g_null_chunk_ptr; - LNK_Chunk *biat_chunk = g_null_chunk_ptr; - LNK_Symbol *int_symbol = 0; - // generate sort index (optional) - String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint_or_ordinal); - // generate thunks LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; LNK_Symbol *load_thunk_symbol = g_null_symbol_ptr; @@ -637,49 +396,34 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym ProfEnd(); return func; +#endif + return 0; } -internal String8 -lnk_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint) -{ - String8 ordinal_data = str8_zero(); - switch (machine) { - case COFF_MachineType_X64: { - U64 *ordinal = push_array(arena, U64, 1); - *ordinal = coff_make_ordinal64(hint); - ordinal_data = str8_struct(ordinal); - } break; - case COFF_MachineType_X86: { - U32 *ordinal = push_array(arena, U32, 1); - *ordinal = coff_make_ordinal32(hint); - ordinal_data = str8_struct(ordinal); - } break; - default: lnk_not_implemented("TODO: support for machine 0x%x", machine); - } - return ordinal_data; -} - -internal LNK_Chunk * -lnk_emit_indirect_jump_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *addr_ptr) +internal COFF_ObjSymbol * +lnk_emit_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name) { ProfBeginFunction(); static U8 thunk[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp [__imp_] // emit chunk - String8 jmp_data = push_str8_copy(sect->arena, str8_array_fixed(thunk)); - LNK_Chunk *jmp_chunk = lnk_section_push_chunk_data(sect, parent, jmp_data, str8_zero()); + String8 jmp_data = push_str8_copy(obj_writer->arena, str8_array_fixed(thunk)); + U64 jmp_data_offset = code_sect->data.total_size; + str8_list_push(obj_writer->arena, &code_sect->data, jmp_data); // patch thunk with imports address static const U64 JMP_OPERAND_OFFSET = 2; - lnk_section_push_reloc(sect, jmp_chunk, LNK_Reloc_REL32, JMP_OPERAND_OFFSET, addr_ptr); + coff_obj_writer_section_push_reloc(obj_writer, code_sect, jmp_data_offset + JMP_OPERAND_OFFSET, iat_symbol, COFF_Reloc_X64_Rel32); + COFF_ObjSymbol *jmp_thunk_symbol = coff_obj_writer_push_symbol_extern(obj_writer, thunk_name, jmp_data_offset, code_sect); + ProfEnd(); - return jmp_chunk; + return jmp_thunk_symbol; } -internal LNK_Chunk * -lnk_emit_load_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *imp_addr_ptr, LNK_Symbol *tail_merge) +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) { ProfBeginFunction(); @@ -689,23 +433,28 @@ lnk_emit_load_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *imp_ad }; // emit load thunk chunk - String8 load_thunk_data = push_str8_copy(sect->arena, str8_array_fixed(load_thunk)); - LNK_Chunk *load_thunk_chunk = lnk_section_push_chunk_data(sect, parent, load_thunk_data, str8_zero()); + U64 load_thunk_data_offset = code_sect->data.total_size; + String8 load_thunk_data = push_str8_copy(obj_writer->arena, str8_array_fixed(load_thunk)); + str8_list_push(obj_writer->arena, &code_sect->data, load_thunk_data); // patch lea with IAT entry static const U64 LEA_OPERAND_OFFSET = 3; - lnk_section_push_reloc(sect, load_thunk_chunk, LNK_Reloc_REL32, LEA_OPERAND_OFFSET, imp_addr_ptr); + coff_obj_writer_section_push_reloc(obj_writer, code_sect, load_thunk_data_offset + LEA_OPERAND_OFFSET, imp_addr_ptr, COFF_Reloc_X64_Rel32); // patch jmp __tailMerge_ static const U64 JMP_OPERAND_OFFSET = 8; - lnk_section_push_reloc(sect, load_thunk_chunk, LNK_Reloc_REL32, JMP_OPERAND_OFFSET, tail_merge); + coff_obj_writer_section_push_reloc(obj_writer, code_sect, load_thunk_data_offset + JMP_OPERAND_OFFSET, tail_merge, COFF_Reloc_X64_Rel32); + + // emit symbol + String8 thunk_name = push_str8f(obj_writer->arena, "__imp_load_%S", func_name); + COFF_ObjSymbol *load_thunk_symbol = coff_obj_writer_push_symbol_extern(obj_writer, thunk_name, load_thunk_data_offset, code_sect); ProfEnd(); - return load_thunk_chunk; + return load_thunk_symbol; } -internal LNK_Chunk * -lnk_emit_tail_merge_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *dll_import_descriptor, LNK_Symbol *delay_load_helper) +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) { ProfBeginFunction(); @@ -735,49 +484,257 @@ lnk_emit_tail_merge_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol * }; // emit tail merge chunk - String8 tail_merge_data = push_str8_copy(sect->arena, str8_array_fixed(tail_merge)); - LNK_Chunk *tail_merge_chunk = lnk_section_push_chunk_data(sect, parent, tail_merge_data, str8_zero()); + String8 tail_merge_data = push_str8_copy(obj_writer->arena, str8_array_fixed(tail_merge)); + U64 tail_merge_off = code_sect->data.total_size; + str8_list_push(obj_writer->arena, &code_sect->data, tail_merge_data); // patch lea __DELAY_IMPORT_DESCRIPTOR_ static const U64 LEA_OPERAND_OFFSET = 54; - lnk_section_push_reloc(sect, tail_merge_chunk, LNK_Reloc_REL32, LEA_OPERAND_OFFSET, dll_import_descriptor); + 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)); // patch call __delayLoadHelper2 static const U64 CALL_OPERAND_OFFSET = 59; - lnk_section_push_reloc(sect, tail_merge_chunk, LNK_Reloc_REL32, CALL_OPERAND_OFFSET, delay_load_helper); + coff_obj_writer_section_push_reloc(obj_writer, code_sect, tail_merge_off + CALL_OPERAND_OFFSET, delay_load_helper, COFF_Reloc_X64_Rel32); + + // emit symbol + String8 tail_merge_name = push_str8f(obj_writer->arena, "__tailMerge_%S", dll_name); + COFF_ObjSymbol *tail_merge_symbol = coff_obj_writer_push_symbol_extern(obj_writer, tail_merge_name, tail_merge_off, code_sect); - ProfEnd(); - return tail_merge_chunk; -} - -internal LNK_Symbol * -lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) -{ - ProfBeginFunction(); - // emit load thunk symbol - String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name); - LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_NoDuplicates, 0); - ProfEnd(); - return load_thunk_symbol; -} - -internal LNK_Symbol * -lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) -{ - ProfBeginFunction(); - String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name); - LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_Any, 0); - ProfEnd(); - return jmp_thunk_symbol; -} - -internal LNK_Symbol * -lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) -{ - ProfBeginFunction(); - String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name); - LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_NoDuplicates, 0); ProfEnd(); return tail_merge_symbol; } +internal String8 +lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine) +{ + 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)); + + String8 dll_name_no_ext = str8_chop_last_dot(dll_name); + + 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_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static); + { + String8 symbol_name = push_str8f(arena, "__IMPORT_DESCRIPTOR_%S", dll_name_no_ext); + coff_obj_writer_push_symbol_extern(obj_writer, symbol_name, 0, idata2); + } + COFF_ObjSymbol *idata2_symbol = coff_obj_writer_push_symbol_sect(obj_writer, idata2->name, idata2); + COFF_ObjSymbol *idata6_symbol = coff_obj_writer_push_symbol_static(obj_writer, idata6->name, 0, idata6); + COFF_ObjSymbol *idata4_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$4"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData); + COFF_ObjSymbol *idata5_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$5"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData); + coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR")); + { + String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext); + coff_obj_writer_push_symbol_undef(obj_writer, symbol_name); + } + + { + PE_ImportEntry *import_entry = push_array(obj_writer->arena, PE_ImportEntry, 1); + str8_list_push(obj_writer->arena, &idata2->data, str8_struct(import_entry)); + coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, name_voff), idata6_symbol, COFF_Reloc_X64_Addr32Nb); + coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, lookup_table_voff), idata4_symbol, COFF_Reloc_X64_Addr32Nb); + coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, import_addr_table_voff), idata5_symbol, COFF_Reloc_X64_Addr32Nb); + } + + String8 obj = coff_obj_writer_serialize(arena, obj_writer); + + 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) +{ + 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_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); + + String8 obj = coff_obj_writer_serialize(arena, obj_writer); + + 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) +{ + 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 *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()); + + U64 import_size = coff_word_size_from_machine(machine); + + U8 *null_thunk = push_array(obj_writer->arena, U8, import_size); + U8 *null_lookup = push_array(obj_writer->arena, U8, import_size); + + str8_list_push(obj_writer->arena, &idata5->data, str8_array(null_thunk, import_size)); + str8_list_push(obj_writer->arena, &idata4->data, str8_array(null_lookup, import_size)); + + idata4->flags |= coff_section_flag_from_align_size(import_size); + idata5->flags |= coff_section_flag_from_align_size(import_size); + + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static); + { + String8 dll_name_no_ext = str8_chop_last_dot(dll_name); + String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext); + coff_obj_writer_push_symbol_extern(obj_writer, symbol_name, 0, idata5); + } + + String8 obj = coff_obj_writer_serialize(arena, obj_writer); + + coff_obj_writer_release(&obj_writer); + + scratch_end(scratch); + ProfEnd(); + return obj; +} + +internal LNK_InputObjList +lnk_import_table_serialize(Arena *arena, LNK_ImportTable *imptab, String8 image_name, COFF_MachineType machine) +{ + Temp scratch = scratch_begin(&arena, 1); + + // append .debug$S + for (LNK_ImportDLL *dll = imptab->first_dll; dll != 0; dll = dll->next) { + String8 debug_symbols = {0}; + { + Temp temp = temp_begin(scratch.arena); + + CV_SymbolList symbol_list = { .signature = CV_Signature_C13 }; + + // S_OBJ + String8 obj_data = cv_make_obj_name(temp.arena, dll->name, 0); + cv_symbol_list_push_data(temp.arena, &symbol_list, CV_SymKind_OBJNAME, obj_data); + + // S_COMPILE3 + String8 comp3_data = lnk_make_linker_compile3(temp.arena, dll->obj_writer->machine); + cv_symbol_list_push_data(temp.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data); + + // S_END + cv_symbol_list_push_data(temp.arena, &symbol_list, CV_SymKind_END, str8_zero()); + + // TODO: add thunks + + // serialize symbols + debug_symbols = lnk_make_debug_s(dll->obj_writer->arena, symbol_list); + + temp_end(temp); + } + coff_obj_writer_push_section(dll->obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS, debug_symbols); + } + + LNK_InputObjList result = {0}; + + // serialize obj writers + for (LNK_ImportDLL *dll = imptab->first_dll; dll != 0; dll = dll->next) { + String8 obj = coff_obj_writer_serialize(arena, dll->obj_writer); + + LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); + input->data = obj; + input->path = push_str8f(arena, "Import:%S", dll->name); + input->dedup_id = input->path; + } + + // generate null terminator objs + String8 null_import_entry_obj = lnk_build_import_entry_obj(arena, image_name, COFF_TimeStamp_Max, machine); + String8 null_import_descriptor_obj = lnk_build_null_import_descriptor_obj(arena, COFF_TimeStamp_Max, machine); + String8 null_thunk_data_obj = lnk_build_null_thunk_data_obj(arena, image_name, COFF_TimeStamp_Max, machine); + + // pick null terminator obj paths + String8 null_import_path; + String8 null_import_descriptor_path; + String8 null_thunk_path; + if (imptab->flags & LNK_ImportTableFlag_Delayed) { + null_import_path = str8_lit("DELAYED_NULL_IMPORT_ENTRY_OBJ"); + null_import_descriptor_path = str8_lit("DELAYED_NULL_IMPORT_DESCRIPTOR_OBJ"); + null_thunk_path = str8_lit("DELAYED_NULL_THUNK_OBJ"); + } else { + null_import_path = str8_lit("NULL_IMPORT_ENTRY_OBJ"); + null_import_descriptor_path = str8_lit("NULL_IMPORT_DESCRIPTOR_OBJ"); + null_thunk_path = str8_lit("NULL_THUNK_OBJ"); + } + + os_write_data_to_file_path(str8_lit("null_import_entry.obj"), null_import_entry_obj); + os_write_data_to_file_path(str8_lit("null_import_descriptor.obj"), null_import_descriptor_obj); + os_write_data_to_file_path(str8_lit("null_thunk.obj"), null_thunk_data_obj); + + // append null terminators + { + LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); + input->data = null_import_entry_obj; + input->path = null_import_path; + input->dedup_id = input->path; + } + { + LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); + input->data = null_import_descriptor_obj; + input->path = null_import_descriptor_path; + input->dedup_id = input->path; + } + { + LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); + input->data = null_thunk_data_obj; + input->path = null_thunk_path; + input->dedup_id = input->path; + } + + scratch_end(scratch); + return result; +} + diff --git a/src/linker/lnk_import_table.h b/src/linker/lnk_import_table.h index 3bb9eb2f..14493218 100644 --- a/src/linker/lnk_import_table.h +++ b/src/linker/lnk_import_table.h @@ -19,23 +19,24 @@ typedef struct LNK_ImportDLL struct LNK_ImportDLL *next; struct LNK_ImportFunc *first_func; struct LNK_ImportFunc *last_func; - LNK_Chunk *dll_chunk; - LNK_Chunk *int_table_chunk; - LNK_Chunk *ilt_table_chunk; - LNK_Chunk *iat_table_chunk; - LNK_Chunk *biat_table_chunk; - LNK_Chunk *uiat_table_chunk; - LNK_Chunk *code_table_chunk; - LNK_Symbol *tail_merge_symbol; + COFF_ObjWriter *obj_writer; + COFF_ObjSection *dll_sect; + COFF_ObjSection *int_sect; + COFF_ObjSection *ilt_sect; + COFF_ObjSection *iat_sect; + COFF_ObjSection *biat_sect; + COFF_ObjSection *uiat_sect; + COFF_ObjSection *code_sect; + COFF_ObjSymbol *tail_merge_symbol; String8 name; - COFF_MachineType machine; HashTable *func_ht; } LNK_ImportDLL; enum { - LNK_ImportTableFlag_EmitBiat = (1 << 0), - LNK_ImportTableFlag_EmitUiat = (1 << 1), + LNK_ImportTableFlag_Delayed = (1 << 0), + LNK_ImportTableFlag_EmitBiat = (1 << 1), + LNK_ImportTableFlag_EmitUiat = (1 << 2), }; typedef U32 LNK_ImportTableFlags; @@ -45,37 +46,28 @@ typedef struct LNK_ImportTable COFF_MachineType machine; LNK_ImportDLL *first_dll; LNK_ImportDLL *last_dll; - LNK_Section *data_sect; - LNK_Section *code_sect; - LNK_Chunk *dll_table_chunk; - LNK_Chunk *int_chunk; - LNK_Chunk *handle_table_chunk; - LNK_Chunk *iat_chunk; - LNK_Chunk *ilt_chunk; - LNK_Chunk *biat_chunk; - LNK_Chunk *uiat_chunk; - LNK_Chunk *code_chunk; LNK_ImportTableFlags flags; HashTable *dll_ht; } LNK_ImportTable; -internal LNK_ImportTable * lnk_import_table_alloc_static(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine); -internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable); +//////////////////////////////// + +internal LNK_ImportTable * lnk_import_table_alloc(LNK_ImportTableFlags flags); internal void lnk_import_table_release(LNK_ImportTable **imptab); -internal LNK_ImportDLL * lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine); -internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine); -internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header); -internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header); +internal LNK_ImportDLL * lnk_import_table_push_dll_static(LNK_ImportTable *imptab, String8 dll_name, COFF_MachineType machine); +internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, String8 dll_name, COFF_MachineType machine); internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name); + +internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header); +internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header); internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name); -internal String8 lnk_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint); +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_desc); -internal LNK_Chunk * lnk_emit_indirect_jump_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *addr_ptr); -internal LNK_Chunk * lnk_emit_load_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *imp_addr_ptr, LNK_Symbol *tail_merge); -internal LNK_Chunk * lnk_emit_tail_merge_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *dll_import_descriptor, LNK_Symbol *delay_load_helper); - -internal LNK_Symbol * lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name); -internal LNK_Symbol * lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name); -internal LNK_Symbol * lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name); +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 LNK_InputObjList lnk_import_table_serialize(Arena *arena, LNK_ImportTable *imptab, String8 image_name, COFF_MachineType machine); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index a884bba8..93df67c7 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -536,145 +536,6 @@ lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, return lib; } -internal String8 -lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine) -{ - 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)); - - String8 dll_name_no_ext = str8_chop_last_dot(dll_name); - - 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_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static); - { - String8 symbol_name = push_str8f(arena, "__IMPORT_DESCRIPTOR_%S", dll_name_no_ext); - coff_obj_writer_push_symbol_external(obj_writer, symbol_name, 0, idata2); - } - COFF_ObjSymbol *idata2_symbol = coff_obj_writer_push_symbol_sect(obj_writer, idata2->name, idata2); - COFF_ObjSymbol *idata6_symbol = coff_obj_writer_push_symbol_static(obj_writer, idata6->name, 0, idata6); - COFF_ObjSymbol *idata4_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$4"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData); - COFF_ObjSymbol *idata5_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$5"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData); - coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR")); - { - String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext); - coff_obj_writer_push_symbol_undef(obj_writer, symbol_name); - } - - { - PE_ImportEntry *import_entry = push_array(obj_writer->arena, PE_ImportEntry, 1); - str8_list_push(obj_writer->arena, &idata2->data, str8_struct(import_entry)); - coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, name_voff), idata6_symbol, COFF_Reloc_X64_Addr32Nb); - coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, lookup_table_voff), idata4_symbol, COFF_Reloc_X64_Addr32Nb); - coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, import_addr_table_voff), idata5_symbol, COFF_Reloc_X64_Addr32Nb); - } - - String8 obj = coff_obj_writer_serialize(arena, obj_writer); - - 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) -{ - 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_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x01018175, COFF_SymStorageClass_Static); - coff_obj_writer_push_symbol_external(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR"), 0, idata3); - - String8 obj = coff_obj_writer_serialize(arena, obj_writer); - - 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) -{ - 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 *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()); - - U64 import_size = coff_word_size_from_machine(machine); - - U8 *null_thunk = push_array(obj_writer->arena, U8, import_size); - U8 *null_lookup = push_array(obj_writer->arena, U8, import_size); - - str8_list_push(obj_writer->arena, &idata5->data, str8_array(null_thunk, import_size)); - str8_list_push(obj_writer->arena, &idata4->data, str8_array(null_lookup, import_size)); - - idata4->flags |= coff_section_flag_from_align_size(import_size); - idata5->flags |= coff_section_flag_from_align_size(import_size); - - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static); - { - String8 dll_name_no_ext = str8_chop_last_dot(dll_name); - String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext); - coff_obj_writer_push_symbol_external(obj_writer, symbol_name, 0, idata5); - } - - String8 obj = coff_obj_writer_serialize(arena, obj_writer); - - coff_obj_writer_release(&obj_writer); - - scratch_end(scratch); - ProfEnd(); - return obj; -} - internal String8 lnk_build_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size) { diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 2c07ec1e..fe579bb5 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -128,9 +128,6 @@ internal String8List lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBu //////////////////////////////// internal LNK_LibBuild lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ObjList obj_list, LNK_ExportTable *exptab); -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 String8 lnk_build_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size); internal String8List lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 lib_name, String8 dll_name, LNK_ExportTable *exptab); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index b77d2d73..aaf9c583 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -317,7 +317,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } if (coff_info.machine != COFF_MachineType_Unknown && task->machine != coff_info.machine) { - lnk_error_with_loc(LNK_Error_IncompatibleObj, input->path, input->lib_path, + lnk_error_with_loc(LNK_Error_IncompatibleMachine, input->path, input->lib_path, "conflicting machine types expected %S but got %S", coff_string_from_machine_type(task->machine), coff_string_from_machine_type(coff_info.machine)); diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 79f6a3fe..ef027153 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -259,6 +259,9 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) lnk_supplement_error("%S", src->obj->path); } } + else if (dst->type == LNK_Symbol_Import) { + can_replace = 1; + } // defined VA vs defined chunk else if (LNK_Symbol_IsDefined(dst->type) && dst->u.defined.value_type == LNK_DefinedSymbolValue_VA && LNK_Symbol_IsDefined(src->type)) { @@ -556,6 +559,7 @@ lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol switch (symbol->type) { case LNK_Symbol_Null: break; + case LNK_Symbol_Import: case LNK_Symbol_DefinedExtern: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Defined][0], LNK_SymbolScopeIndex_Defined, hash, symbol); } break; diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 29326d6d..a6be9f8a 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -88,6 +88,7 @@ typedef enum LNK_Symbol_Weak, LNK_Symbol_Lazy, LNK_Symbol_Undefined, + LNK_Symbol_Import, } LNK_SymbolType; typedef struct LNK_Symbol