diff --git a/src/coff/coff.h b/src/coff/coff.h index 6c0c8828..aa88b9b9 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -21,6 +21,7 @@ read_only global U8 g_coff_thin_archive_sig[8] = "!\n"; #pragma pack(push, 1) +#define COFF_TimeStamp_Max max_U32 typedef U32 COFF_TimeStamp; typedef U16 COFF_FileHeaderFlags; @@ -135,6 +136,20 @@ enum COFF_SectionFlag_MemPreload = (1 << 19), COFF_SectionFlag_AlignShift = 20, COFF_SectionFlag_AlignMask = 0xf, + COFF_SectionFlag_Align1Bytes = (COFF_SectionAlign_1Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align2Bytes = (COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align4Bytes = (COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align8Bytes = (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align16Bytes = (COFF_SectionAlign_16Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align32Bytes = (COFF_SectionAlign_32Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align64Bytes = (COFF_SectionAlign_64Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align128Bytes = (COFF_SectionAlign_128Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align256Bytes = (COFF_SectionAlign_256Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align512Bytes = (COFF_SectionAlign_512Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align1024Bytes = (COFF_SectionAlign_1024Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align2048Bytes = (COFF_SectionAlign_2048Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align4096Bytes = (COFF_SectionAlign_4096Bytes << COFF_SectionFlag_AlignShift), + COFF_SectionFlag_Align8192Bytes = (COFF_SectionAlign_8192Bytes << COFF_SectionFlag_AlignShift), COFF_SectionFlag_LnkNRelocOvfl = (1 << 24), COFF_SectionFlag_MemDiscardable = (1 << 25), COFF_SectionFlag_MemNotCached = (1 << 26), @@ -144,7 +159,6 @@ enum COFF_SectionFlag_MemRead = (1 << 30), COFF_SectionFlag_MemWrite = (1 << 31) }; -#define COFF_SectionFlags_PackAlign(f) ((f) << COFF_SectionFlag_AlignShift) #define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask) #define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 20caa69d..9d715603 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -17,7 +17,7 @@ coff_obj_writer_release(COFF_ObjWriter **obj_writer) } internal COFF_ObjSymbol * -coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section, COFF_SymbolType type, COFF_SymStorageClass storage_class) +coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class) { COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1); SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n); @@ -26,7 +26,7 @@ coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSymbol *s = &n->v; s->name = name; s->value = value; - s->section = section; + s->loc = loc; s->type = type; s->storage_class = storage_class; s->idx = obj_writer->symbol_count-1; @@ -35,16 +35,41 @@ coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, } internal COFF_ObjSymbol * -coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section) +coff_obj_writer_push_symbol_external(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section) { - COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, section, (COFF_SymbolType){0}, COFF_SymStorageClass_Static); + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Section; + loc.u.section = section; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_External); return s; } internal COFF_ObjSymbol * -coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, COFF_SymStorageClass storage_class, U32 value) +coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section) { - COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, 0, (COFF_SymbolType){0}, storage_class); + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Section; + loc.u.section = section; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_Static); + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class) +{ + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Abs; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, storage_class); + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name) +{ + COFF_SymbolType type = {0}; + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Undef; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External); return s; } @@ -53,7 +78,34 @@ coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name) { COFF_SymbolType type = {0}; type.u.msb = COFF_SymDType_Func; - COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, 0, type, COFF_SymStorageClass_External); + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Undef; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External); + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value) +{ + COFF_SymbolType type = {0}; + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Undef; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_Section); + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect) +{ + COFF_SymbolType type = {0}; + COFF_SymbolLocation loc = {0}; + loc.type = COFF_SymbolLocation_Section; + loc.u.section = sect; + + // strip align flags + COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift); + + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section); return s; } @@ -67,7 +119,6 @@ coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_Sect COFF_ObjSection *sect = §_n->v; sect->name = name; sect->flags = flags; - sect->symbol = coff_obj_writer_push_symbol_static(obj_writer, name, 0, sect); str8_list_push(obj_writer->arena, §->data, data); @@ -234,10 +285,11 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) AssertAlways(s->aux_symbols.node_count <= max_U8); d->name = name; d->value = s->value; - if (s->section == 0) { - d->section_number = COFF_Symbol_AbsSection16; - } else { - d->section_number = safe_cast_u16(s->section->section_number); + switch (s->loc.type) { + case COFF_SymbolLocation_Null: break; + case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break; + case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break; + case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break; } d->type = s->type; d->storage_class = s->storage_class; diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h index 67297401..9a85357c 100644 --- a/src/coff/coff_obj_writer.h +++ b/src/coff/coff_obj_writer.h @@ -1,11 +1,27 @@ #ifndef COFF_OBJ_WRITER_H #define COFF_OBJ_WRITER_H +typedef enum +{ + COFF_SymbolLocation_Null, + COFF_SymbolLocation_Section, + COFF_SymbolLocation_Abs, + COFF_SymbolLocation_Undef +} COFF_SymbolLocationType; + +typedef struct COFF_SymbolLocation +{ + COFF_SymbolLocationType type; + union { + struct COFF_ObjSection *section; + } u; +} COFF_SymbolLocation; + typedef struct COFF_ObjSymbol { String8 name; U32 value; - struct COFF_ObjSection *section; + COFF_SymbolLocation loc; COFF_SymbolType type; COFF_SymStorageClass storage_class; String8List aux_symbols; @@ -36,7 +52,6 @@ typedef struct COFF_ObjSection String8 name; String8List data; COFF_SectionFlags flags; - COFF_ObjSymbol *symbol; U64 reloc_count; COFF_ObjRelocNode *reloc_first; @@ -71,7 +86,7 @@ typedef struct COFF_ObjWriter internal COFF_ObjWriter* coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine_type); 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_ObjSection *section, COFF_SymbolType type, COFF_SymStorageClass storage_class); +internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class); internal COFF_ObjReloc* coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type); #endif // COFF_OBJ_WRITER_H diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 436dcf44..a89acec9 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -121,6 +121,7 @@ #include "lnk_reloc.h" #include "lnk_symbol_table.h" #include "lnk_section_table.h" +#include "lnk_debug_helper.h" #include "lnk_obj.h" #include "lnk_import_table.h" #include "lnk_export_table.h" @@ -139,6 +140,7 @@ #include "lnk_symbol_table.c" #include "lnk_section_table.c" #include "lnk_obj.c" +#include "lnk_debug_helper.c" #include "lnk_import_table.c" #include "lnk_export_table.c" #include "lnk_lib.c" @@ -763,27 +765,16 @@ lnk_make_linker_coff_obj(Arena *arena, { Temp scratch = scratch_begin(&arena, 1); - String8 debug_s_data = {0}; + String8 debug_symbols = {0}; { - CV_SymbolList symbol_list = {0}; - symbol_list.signature = CV_Signature_C13; + CV_SymbolList symbol_list = { .signature = CV_Signature_C13 }; // S_OBJ String8 obj_data = cv_make_obj_name(scratch.arena, obj_name, 0); cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_OBJNAME, obj_data); // S_COMPILE3 - CV_Arch cv_arch = cv_arch_from_coff_machine(machine); - U64 ver_fe_major = 0; - U64 ver_fe_minor = 0; - U64 ver_fe_build = 0; - U64 ver_feqfe = 0; - U64 ver_major = 14; - U64 ver_minor = 36; - U64 ver_build = 32537; - U64 ver_qfe = 0; - String8 version_string = push_str8f(scratch.arena, "Epic Games Tools (R) RAD Linker"); - String8 comp3_data = cv_make_comp3(scratch.arena, 0, CV_Language_LINK, cv_arch, ver_fe_major, ver_fe_minor, ver_fe_build, ver_feqfe, ver_major, ver_minor, ver_build, ver_qfe, version_string); + String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine); cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data); // S_ENVBLOCK @@ -798,28 +789,18 @@ lnk_make_linker_coff_obj(Arena *arena, str8_list_push(scratch.arena, &env_list, cmd_line); str8_list_push(scratch.arena, &env_list, str8_lit("")); str8_list_push(scratch.arena, &env_list, str8_lit("")); - String8 env_data = cv_make_envblock(scratch.arena, env_list); - cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_ENVBLOCK, env_data); + 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 - String8List symbol_data_list = cv_data_from_symbol_list(scratch.arena, symbol_list, CV_SymbolAlign); - - CV_DebugS debug_s = {0}; - - String8List *symbols_list_ptr = cv_sub_section_ptr_from_debug_s(&debug_s, CV_C13SubSectionKind_Symbols); - *symbols_list_ptr = symbol_data_list; - - B32 include_sig = 1; - String8List debug_s_data_list = cv_data_c13_from_debug_s(scratch.arena, &debug_s, include_sig); - debug_s_data = str8_list_join(scratch.arena, &debug_s_data_list, 0); + debug_symbols = lnk_make_debug_s(scratch.arena, symbol_list); } String8 obj; { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine); - coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS, debug_s_data); + coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols); obj = coff_obj_writer_serialize(arena, obj_writer); coff_obj_writer_release(&obj_writer); } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 1a146b2a..ba3e3281 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -89,8 +89,8 @@ #define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS #define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS #define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS -#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlags_PackAlign(COFF_SectionAlign_4Bytes)) -#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlags_PackAlign(COFF_SectionAlign_4Bytes)) +#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes) +#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes) #define LNK_XDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS #define LNK_PDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS #define LNK_EDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index d8b9c37b..a884bba8 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -536,352 +536,143 @@ lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, return lib; } -internal String8List -lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType machine) +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)); - - String8List list = {0}; - - COFF_FileHeader *file_header = push_array(arena, COFF_FileHeader, 1); - file_header->machine = machine; - str8_list_push(arena, &list, str8_struct(file_header)); - - file_header->section_count = 2; - COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, file_header->section_count); - str8_list_push(arena, &list, str8_array(coff_sect_header_array, file_header->section_count)); - - PE_ImportEntry *import_entry = push_array(arena, PE_ImportEntry, 1); - U64 import_entry_off = list.total_size; - str8_list_push(arena, &list, str8_struct(import_entry)); - - String8 dll_name_cstr = push_cstr(arena, dll_name); - U64 dll_name_off = list.total_size; - str8_list_push(arena, &list, dll_name_cstr); - - U32 import_entry_reloc_count = 3; - COFF_Reloc *import_entry_reloc_array = push_array(arena, COFF_Reloc, import_entry_reloc_count); - U64 import_entry_reloc_off = list.total_size; - str8_list_push(arena, &list, str8_array(import_entry_reloc_array, import_entry_reloc_count)); - - file_header->symbol_count = 7; - COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, file_header->symbol_count); - file_header->symbol_table_foff = safe_cast_u32(list.total_size); - str8_list_push(arena, &list, str8_array(symbol_array, file_header->symbol_count)); - - U64 string_table_base = list.total_size; - U32 *string_table_size_ptr = push_array(arena, U32, 1); - str8_list_push(arena, &list, str8_struct(string_table_size_ptr)); - - // PE_ImportEntry + + 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; { - COFF_SectionHeader *sect = &coff_sect_header_array[0]; - sect->name[0] = '.'; - sect->name[1] = 'i'; - sect->name[2] = 'd'; - sect->name[3] = 'a'; - sect->name[4] = 't'; - sect->name[5] = 'a'; - sect->name[6] = '$'; - sect->name[7] = '2'; - sect->fsize = sizeof(PE_ImportEntry); - sect->foff = import_entry_off; - sect->reloc_count = import_entry_reloc_count; - sect->relocs_foff = import_entry_reloc_off; - sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; + 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); { - COFF_Reloc *lookup_table_voff_reloc = &import_entry_reloc_array[0]; - lookup_table_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, lookup_table_voff); - lookup_table_voff_reloc->isymbol = 3; - lookup_table_voff_reloc->type = COFF_Reloc_X64_Addr32Nb; - - COFF_Reloc *name_voff_reloc = &import_entry_reloc_array[1]; - name_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, name_voff); - name_voff_reloc->isymbol = 2; - name_voff_reloc->type = COFF_Reloc_X64_Addr32Nb; - - COFF_Reloc *import_addr_table_voff = &import_entry_reloc_array[2]; - import_addr_table_voff->apply_off = OffsetOf(PE_ImportEntry, import_addr_table_voff); - import_addr_table_voff->isymbol = 4; - import_addr_table_voff->type = COFF_Reloc_X64_Addr32Nb; - } - - // dll name - { - COFF_SectionHeader *sect = &coff_sect_header_array[1]; - sect->name[0] = '.'; - sect->name[1] = 'i'; - sect->name[2] = 'd'; - sect->name[3] = 'a'; - sect->name[4] = 't'; - sect->name[5] = 'a'; - sect->name[6] = '$'; - sect->name[7] = '6'; - sect->fsize = dll_name_cstr.size; - sect->foff = dll_name_off; - sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; - } - - // import descriptor - { - String8 dll_name_no_ext = str8_substr(dll_name, r1u64(0, dll_name.size - 4)); String8 symbol_name = push_str8f(arena, "__IMPORT_DESCRIPTOR_%S", dll_name_no_ext); - - U64 symbol_name_off = (list.total_size - string_table_base); - str8_list_push(arena, &list, push_cstr(arena, symbol_name)); - - COFF_Symbol16 *symbol = &symbol_array[0]; - symbol->name.long_name.zeroes = 0; - symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_External; + coff_obj_writer_push_symbol_external(obj_writer, symbol_name, 0, idata2); } - - // .idata$2 + 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")); { - COFF_Symbol16 *symbol = &symbol_array[1]; - symbol->name.short_name[0] = '.'; - symbol->name.short_name[1] = 'i'; - symbol->name.short_name[2] = 'd'; - symbol->name.short_name[3] = 'a'; - symbol->name.short_name[4] = 't'; - symbol->name.short_name[5] = 'a'; - symbol->name.short_name[6] = '$'; - symbol->name.short_name[7] = '2'; - symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_Section; - } - - // .idata$6 - { - COFF_Symbol16 *symbol = &symbol_array[2]; - symbol->name.short_name[0] = '.'; - symbol->name.short_name[1] = 'i'; - symbol->name.short_name[2] = 'd'; - symbol->name.short_name[3] = 'a'; - symbol->name.short_name[4] = 't'; - symbol->name.short_name[5] = 'a'; - symbol->name.short_name[6] = '$'; - symbol->name.short_name[7] = '6'; - symbol->section_number = 2; - symbol->storage_class = COFF_SymStorageClass_Static; - } - - // .idata$4 - { - COFF_Symbol16 *symbol = &symbol_array[3]; - symbol->name.short_name[0] = '.'; - symbol->name.short_name[1] = 'i'; - symbol->name.short_name[2] = 'd'; - symbol->name.short_name[3] = 'a'; - symbol->name.short_name[4] = 't'; - symbol->name.short_name[5] = 'a'; - symbol->name.short_name[6] = '$'; - symbol->name.short_name[7] = '4'; - symbol->section_number = COFF_Symbol_UndefinedSection; - symbol->storage_class = COFF_SymStorageClass_Section; - } - - // .idata$5 - { - COFF_Symbol16 *symbol = &symbol_array[4]; - symbol->name.short_name[0] = '.'; - symbol->name.short_name[1] = 'i'; - symbol->name.short_name[2] = 'd'; - symbol->name.short_name[3] = 'a'; - symbol->name.short_name[4] = 't'; - symbol->name.short_name[5] = 'a'; - symbol->name.short_name[6] = '$'; - symbol->name.short_name[7] = '5'; - symbol->section_number = COFF_Symbol_UndefinedSection; - symbol->storage_class = COFF_SymStorageClass_Section; - } - - // __NULL_IMPORT_DESCRIPTOR - { - U64 symbol_name_off = (list.total_size - string_table_base); - str8_list_push(arena, &list, push_cstr(arena, str8_lit("__NULL_IMPORT_DESCRIPTOR"))); - - COFF_Symbol16 *symbol = &symbol_array[5]; - symbol->name.long_name.zeroes = 0; - symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = COFF_Symbol_UndefinedSection; - symbol->storage_class = COFF_SymStorageClass_External; - } - - // NULL_THUNK_DATA - { - String8 dll_name_no_ext = str8_substr(dll_name, r1u64(0, dll_name.size - 4)); String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext); - - U64 symbol_name_off = (list.total_size - string_table_base); - str8_list_push(arena, &list, push_cstr(arena, symbol_name)); - - COFF_Symbol16 *symbol = &symbol_array[6]; - symbol->name.long_name.zeroes = 0; - symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = COFF_Symbol_UndefinedSection; - symbol->storage_class = COFF_SymStorageClass_External; + coff_obj_writer_push_symbol_undef(obj_writer, symbol_name); } - - // update string table size - *string_table_size_ptr = (list.total_size - string_table_base); - + + { + 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 list; + return obj; } -internal String8List -lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine) +internal String8 +lnk_build_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine) { ProfBeginFunction(); - - String8List list = {0}; - - COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1); - coff_header->machine = machine; - str8_list_push(arena, &list, str8_struct(coff_header)); - - coff_header->section_count = 1; - COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, coff_header->section_count); - str8_list_push(arena, &list, str8_array(coff_sect_header_array, coff_header->section_count)); - - U64 null_import_data_size = 20; - U8 *null_import_data = push_array(arena, U8, null_import_data_size); - U64 null_import_data_off = list.total_size; - str8_list_push(arena, &list, str8(null_import_data, null_import_data_size)); - - coff_header->symbol_count = 1; - COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, coff_header->symbol_count); - coff_header->symbol_table_foff = safe_cast_u32(list.total_size); - str8_list_push(arena, &list, str8_array(symbol_array, coff_header->symbol_count)); - - U64 string_table_base = list.total_size; - U32 *string_table_size_ptr = push_array(arena, U32, 1); - str8_list_push(arena, &list, str8_struct(string_table_size_ptr)); - + Temp scratch = scratch_begin(&arena, 1); + + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine); + + String8 debug_symbols; { - COFF_SectionHeader *sect = &coff_sect_header_array[0]; - sect->name[0] = '.'; - sect->name[1] = 'i'; - sect->name[2] = 'd'; - sect->name[3] = 'a'; - sect->name[4] = 't'; - sect->name[5] = 'a'; - sect->name[6] = '$'; - sect->name[7] = '3'; - sect->fsize = null_import_data_size; - sect->foff = null_import_data_off; - sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; + 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); } - - { - U64 symbol_name_off = list.total_size - string_table_base; - str8_list_push(arena, &list, push_cstr(arena, str8_lit("__NULL_IMPORT_DESCRIPTOR"))); - - COFF_Symbol16 *symbol = &symbol_array[0]; - symbol->name.long_name.zeroes = 0; - symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_External; - } - - // update string table size - *string_table_size_ptr = (list.total_size - string_table_base); - + + 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 list; + return obj; } -internal String8List -lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType machine) +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)); - - String8List list = {0}; - - COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1); - coff_header->machine = machine; - str8_list_push(arena, &list, str8_struct(coff_header)); - - coff_header->section_count = 2; - COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, coff_header->section_count); - str8_list_push(arena, &list, str8_array(coff_sect_header_array, coff_header->section_count)); - - U64 lookup_entry_data_size = 8; - U8 *lookup_entry_data = push_array(arena, U8, lookup_entry_data_size); - U64 lookup_entry_data_off = list.total_size; - str8_list_push(arena, &list, str8(lookup_entry_data, lookup_entry_data_size)); - - U64 null_thunk_data_size = 8; - U8 *null_thunk_data = push_array(arena, U8, null_thunk_data_size); - U64 null_thunk_data_off = list.total_size; - str8_list_push(arena, &list, str8(null_thunk_data, null_thunk_data_size)); - - coff_header->symbol_count = 1; - COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, coff_header->symbol_count); - coff_header->symbol_table_foff = safe_cast_u32(list.total_size); - str8_list_push(arena, &list, str8_array(symbol_array, coff_header->symbol_count)); - - U64 string_table_base = list.total_size; - U32 *string_table_size_ptr = push_array(arena, U32, 1); - str8_list_push(arena, &list, str8_struct(string_table_size_ptr)); - + + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine); + + String8 debug_symbols; { - COFF_SectionHeader *sect = &coff_sect_header_array[0]; - sect->name[0] = '.'; - sect->name[1] = 'i'; - sect->name[2] = 'd'; - sect->name[3] = 'a'; - sect->name[4] = 't'; - sect->name[5] = 'a'; - sect->name[6] = '$'; - sect->name[7] = '5'; - sect->fsize = lookup_entry_data_size; - sect->foff = lookup_entry_data_off; - sect->flags = COFF_SectionFlag_CntInitializedData | (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|(COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite); + 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); { - COFF_SectionHeader *sect = &coff_sect_header_array[1]; - sect->name[0] = '.'; - sect->name[1] = 'i'; - sect->name[2] = 'd'; - sect->name[3] = 'a'; - sect->name[4] = 't'; - sect->name[5] = 'a'; - sect->name[6] = '$'; - sect->name[7] = '4'; - sect->fsize = null_thunk_data_size; - sect->foff = null_thunk_data_off; - sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite; - } - - { - String8 dll_name_no_ext = str8_substr(dll_name, r1u64(0, dll_name.size - 4)); + 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); - - U64 symbol_name_off = list.total_size - string_table_base; - str8_list_push(arena, &list, push_cstr(arena, symbol_name)); - - COFF_Symbol16 *symbol = &symbol_array[0]; - symbol->name.long_name.zeroes = 0; - symbol->name.long_name.string_table_offset = symbol_name_off; - symbol->section_number = 1; - symbol->storage_class = COFF_SymStorageClass_External; + coff_obj_writer_push_symbol_external(obj_writer, symbol_name, 0, idata5); } + + String8 obj = coff_obj_writer_serialize(arena, obj_writer); - // update string table size - *string_table_size_ptr = (list.total_size - string_table_base); - + coff_obj_writer_release(&obj_writer); + + scratch_end(scratch); ProfEnd(); - return list; + return obj; } internal String8 @@ -924,28 +715,28 @@ lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, // These objects appear in first three members of any lib that linker produces with /dll. // Objects are used by MSVC linker to build import table. - String8List import_obj_array[3]; - import_obj_array[0] = lnk_build_import_entry_obj(scratch.arena, dll_name, machine); - import_obj_array[1] = lnk_build_null_import_descriptor_obj(scratch.arena, machine); - import_obj_array[2] = lnk_build_null_thunk_data_obj(scratch.arena, dll_name, machine); + String8 import_obj_array[3]; + import_obj_array[0] = lnk_build_import_entry_obj(scratch.arena, dll_name, time_stamp, machine); + import_obj_array[1] = lnk_build_null_import_descriptor_obj(scratch.arena, time_stamp, machine); + import_obj_array[2] = lnk_build_null_thunk_data_obj(scratch.arena, dll_name, time_stamp, machine); // build input list LNK_InputObjList input_obj_list = {0}; for (U64 i = 0; i < ArrayCount(import_obj_array); ++i) { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->data = str8_list_join(scratch.arena, &import_obj_array[i], 0); + input->data = import_obj_array[i]; input->path = dll_name; input->lib_path = lib_name; } LNK_InputObj **inputs = lnk_array_from_input_obj_list(scratch.arena, input_obj_list); - LNK_SectionTable *sectab = lnk_section_table_alloc(0,0,0); + LNK_SectionTable *sectab = lnk_section_table_alloc(0,0,0); LNK_ObjList obj_list = {0}; lnk_obj_list_push_parallel(tp, arena, &obj_list, sectab, 0, machine, input_obj_list.count, inputs); LNK_LibBuild import_lib = lnk_build_lib(scratch.arena, machine, time_stamp, dll_name, obj_list, exptab); - B32 emit_second_member = 0; // MSVC linker refuses to link with lib that has the second member. - String8List coff_archive_data = lnk_coff_archive_from_lib_build(arena->v[0], &import_lib, emit_second_member, time_stamp, /* -rw-r--r-- */ 644); + B32 emit_second_member = 1; + String8List coff_archive_data = lnk_coff_archive_from_lib_build(arena->v[0], &import_lib, emit_second_member, COFF_TimeStamp_Max, 0); // cleanup memory lnk_section_table_release(§ab); diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index af87ae84..2c07ec1e 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -128,9 +128,9 @@ 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 String8List lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType machine); -internal String8List lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine); -internal String8List lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType machine); +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 225f2491..b77d2d73 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -751,12 +751,17 @@ lnk_symbol_array_from_coff(Arena *arena, if (symbol.section_number == 0 || symbol.section_number > sect_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number); } - if (symbol.value > section_table[symbol.section_number-1].fsize) { - lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, symbol.value); + + U32 section_offset = 0; + if (symbol.storage_class == COFF_SymStorageClass_External || symbol.storage_class == COFF_SymStorageClass_Static) { + section_offset = symbol.value; + } + if (section_offset > section_table[symbol.section_number-1].fsize) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, section_offset); } LNK_Chunk *chunk = chunk_table[symbol.section_number-1]; - if (symbol.value > 0) { + if (section_offset > 0) { // convert leaf to list // // there is no way to know up front how many splits we have, @@ -796,7 +801,7 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_ChunkNode *current = chunk->u.list->last; for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { Assert(c->data->type == LNK_Chunk_Leaf); - if (offset_cursor + c->data->u.leaf.size >= symbol.value) { + if (offset_cursor + c->data->u.leaf.size >= section_offset) { current = c; break; } @@ -804,9 +809,9 @@ lnk_symbol_array_from_coff(Arena *arena, } Assert(current->data->type == LNK_Chunk_Leaf); - if (offset_cursor < symbol.value) { + if (offset_cursor < section_offset) { // bifurcate chunk at symbol offset - U64 split_pos = symbol.value - offset_cursor; + U64 split_pos = section_offset - offset_cursor; Rng1U64 left_data_range = rng_1u64(0, split_pos); Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size); String8 left_data = str8_substr(current->data->u.leaf, left_data_range); @@ -865,142 +870,147 @@ lnk_symbol_array_from_coff(Arena *arena, COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); switch (interp) { - case COFF_SymbolValueInterp_Regular: { - if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) { - lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number); - } - if (parsed_symbol.value > section_table[parsed_symbol.section_number-1].fsize) { - lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, parsed_symbol.value, parsed_symbol.section_number); - } + case COFF_SymbolValueInterp_Regular: { + if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number); + } + + U32 section_offset = 0; + if (parsed_symbol.storage_class == COFF_SymStorageClass_External || + parsed_symbol.storage_class == COFF_SymStorageClass_Static) { + section_offset = parsed_symbol.value; + } + + if (section_offset > section_table[parsed_symbol.section_number-1].fsize) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, section_offset, parsed_symbol.section_number); + } + + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; + if (parsed_symbol.storage_class == COFF_SymStorageClass_External) { + visibility = LNK_DefinedSymbolVisibility_Extern; + } + LNK_DefinedSymbolFlags flags = 0; + if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { + flags |= LNK_DefinedSymbolFlag_IsFunc; + } - LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (parsed_symbol.storage_class == COFF_SymStorageClass_External) { - visibility = LNK_DefinedSymbolVisibility_Extern; - } - LNK_DefinedSymbolFlags flags = 0; - if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { - flags |= LNK_DefinedSymbolFlag_IsFunc; - } + LNK_Chunk *chunk = chunk_table[parsed_symbol.section_number-1]; + COFF_ComdatSelectType selection = COFF_ComdatSelect_Any; + U64 check_sum = 0; - LNK_Chunk *chunk = chunk_table[parsed_symbol.section_number-1]; - U64 offset = parsed_symbol.value; - COFF_ComdatSelectType selection = COFF_ComdatSelect_Any; - U64 check_sum = 0; + B32 is_comdat = (section_table[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) && + parsed_symbol.value == 0 && + parsed_symbol.aux_symbol_count > 0 && + parsed_symbol.type.u.lsb == COFF_SymType_Null && + parsed_symbol.storage_class == COFF_SymStorageClass_Static; + if (is_comdat) { + COFF_SymbolSecDef *secdef = aux_symbols; + selection = secdef->selection; + check_sum = secdef->check_sum; - B32 is_comdat = (section_table[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) && - parsed_symbol.value == 0 && - parsed_symbol.aux_symbol_count > 0 && - parsed_symbol.type.u.lsb == COFF_SymType_Null && - parsed_symbol.storage_class == COFF_SymStorageClass_Static; - if (is_comdat) { - COFF_SymbolSecDef *secdef = aux_symbols; + // create association link between chunks + if (secdef->selection == COFF_ComdatSelect_Associative) { + U32 secdef_number = secdef->number_lo; - selection = secdef->selection; - check_sum = secdef->check_sum; + // promote secdef number to 32 bits + if (is_big_obj) { + secdef_number |= (U32)secdef->number_hi << 16; + } - // create association link between chunks - if (secdef->selection == COFF_ComdatSelect_Associative) { - U32 secdef_number = secdef->number_lo; - - // promote secdef number to 32 bits - if (is_big_obj) { - secdef_number |= (U32)secdef->number_hi << 16; - } - - // associate chunks - if (secdef_number > 0 && secdef_number <= sect_count) { - LNK_Chunk *head_chunk = chunk_table[secdef_number-1]; - LNK_Chunk *associate_chunk = chunk_table[parsed_symbol.section_number-1]; - lnk_chunk_associate(head_chunk, associate_chunk); - } else { - lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number); - } + // associate chunks + if (secdef_number > 0 && secdef_number <= sect_count) { + LNK_Chunk *head_chunk = chunk_table[secdef_number-1]; + LNK_Chunk *associate_chunk = chunk_table[parsed_symbol.section_number-1]; + lnk_chunk_associate(head_chunk, associate_chunk); + } else { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number); } } + } - if (chunk->type == LNK_Chunk_List) { - LNK_Chunk *closest_chunk = chunk->u.list->last->data; - U64 offset_cursor = 0; - for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { - if (offset_cursor + c->data->u.leaf.size > offset) { - closest_chunk = c->data; - break; - } - offset_cursor += c->data->u.leaf.size; + if (chunk->type == LNK_Chunk_List) { + LNK_Chunk *closest_chunk = chunk->u.list->last->data; + U64 offset_cursor = 0; + for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { + if (offset_cursor + c->data->u.leaf.size > section_offset) { + closest_chunk = c->data; + break; } - Assert(offset >= offset_cursor); - offset -= offset_cursor; - chunk = closest_chunk; + offset_cursor += c->data->u.leaf.size; } - Assert(chunk->type == LNK_Chunk_Leaf); + Assert(section_offset >= offset_cursor); + section_offset -= offset_cursor; + chunk = closest_chunk; + } + Assert(chunk->type == LNK_Chunk_Leaf); - lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, offset, selection, check_sum); - symbol_array.v[symbol_idx].obj = obj; - } break; - case COFF_SymbolValueInterp_Weak: { - if (parsed_symbol.aux_symbol_count == 0) { - lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx); - } - - COFF_SymbolWeakExt *weak_ext = aux_symbols; - if (weak_ext->tag_index >= symbol_count) { - lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx); - } + lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, section_offset, selection, check_sum); + symbol_array.v[symbol_idx].obj = obj; + } break; + case COFF_SymbolValueInterp_Weak: { + if (parsed_symbol.aux_symbol_count == 0) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx); + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index]; - lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol); + COFF_SymbolWeakExt *weak_ext = aux_symbols; + if (weak_ext->tag_index >= symbol_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx); + } - symbol->obj = obj; - fallback_symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_Undefined: { - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_Common: { - // :common_block - // - // TODO: sort chunks on size to reduce bss usage - LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1); - chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes - chunk->type = LNK_Chunk_Leaf; - chunk->flags = master_common_block->flags; - chunk->u.leaf = str8(0, parsed_symbol.value); - chunk->obj = obj; - lnk_chunk_set_debugf(arena, chunk, "common block %S", parsed_symbol.name); - lnk_chunk_list_push(arena, master_common_block->u.list, chunk); + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index]; + lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol); - LNK_DefinedSymbolFlags flags = 0; - if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { - flags |= LNK_DefinedSymbolFlag_IsFunc; - } + symbol->obj = obj; + fallback_symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_Undefined: { + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_Common: { + // :common_block + // + // TODO: sort chunks on size to reduce bss usage + LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1); + chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes + chunk->type = LNK_Chunk_Leaf; + chunk->flags = master_common_block->flags; + chunk->u.leaf = str8(0, parsed_symbol.value); + chunk->obj = obj; + lnk_chunk_set_debugf(arena, chunk, "common block %S", parsed_symbol.name); + lnk_chunk_list_push(arena, master_common_block->u.list, chunk); - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelect_Largest, 0); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_Abs: { - // Never code or data, synthetic symbol. COFF spec says bits in value are used - // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. - // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. + LNK_DefinedSymbolFlags flags = 0; + if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { + flags |= LNK_DefinedSymbolFlag_IsFunc; + } - LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (parsed_symbol.storage_class == COFF_SymStorageClass_External) { - visibility = LNK_DefinedSymbolVisibility_Extern; - } + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelect_Largest, 0); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_Abs: { + // Never code or data, synthetic symbol. COFF spec says bits in value are used + // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. + // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_Debug: { - } break; + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; + if (parsed_symbol.storage_class == COFF_SymStorageClass_External) { + visibility = LNK_DefinedSymbolVisibility_Extern; + } + + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_Debug: { + } break; } }