diff --git a/src/linker/lnk.c b/src/linker/lnk.c index c3946fe1..5b1660b4 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2369,37 +2369,18 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S // build obj section map for (U64 obj_idx = 0; obj_idx < objs_count; obj_idx += 1) { - LNK_Obj *obj = objs[obj_idx]; - COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str; - String8 string_table = str8_substr(obj->data, obj->header.string_table_range); - - String8 *symlinks = push_array(scratch.arena, String8, obj->header.section_count_no_null); - { - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular) { - if (symbol.storage_class == COFF_SymStorageClass_External) { - U64 sect_idx = symbol.section_number-1; - COFF_SectionHeader *sect_header = §ion_table[sect_idx]; - if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { - // TODO: check that we don't override COMDAT symbol link - symlinks[sect_idx] = symbol.name; - } - } - } - } - } - - for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { - COFF_SectionHeader *sect_header = §ion_table[sect_idx]; - if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { - String8 comdat_name = symlinks[sect_idx]; - if (comdat_name.size) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, comdat_name); - COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx); - sect_map[obj_idx][sect_idx] = sect_map[defn->u.defined.obj->input_idx][symbol.section_number-1]; + LNK_Obj *obj = objs[obj_idx]; + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_Regular && symbol.storage_class == COFF_SymStorageClass_External && symbol.value == 0) { + COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); + if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { + // replace contrib with leader + LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol.name); + COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx); + sect_map[obj_idx][symbol.section_number - 1] = sect_map[defn->u.defined.obj->input_idx][symbol.section_number - 1]; } } } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index aa287a78..8446ca41 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -48,38 +48,38 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // // parse obj header // - COFF_FileHeaderInfo coff_info = coff_file_header_info_from_data(input->data); + COFF_FileHeaderInfo header = coff_file_header_info_from_data(input->data); // // set & check machine compatibility // - if (coff_info.machine != COFF_MachineType_Unknown) { - COFF_MachineType current_machine = ins_atomic_u32_eval_cond_assign(&task->machine, coff_info.machine, COFF_MachineType_Unknown); - if (current_machine != COFF_MachineType_Unknown && current_machine != coff_info.machine) { + if (header.machine != COFF_MachineType_Unknown) { + COFF_MachineType current_machine = ins_atomic_u32_eval_cond_assign(&task->machine, header.machine, COFF_MachineType_Unknown); + if (current_machine != COFF_MachineType_Unknown && current_machine != header.machine) { 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(current_machine), - coff_string_from_machine_type(coff_info.machine)); + coff_string_from_machine_type(header.machine)); } } // // extract COFF info // - String8 raw_coff_section_table = str8_substr(input->data, coff_info.section_table_range); - String8 raw_coff_symbol_table = str8_substr(input->data, coff_info.symbol_table_range); - String8 raw_coff_string_table = str8_substr(input->data, coff_info.string_table_range); + String8 raw_coff_section_table = str8_substr(input->data, header.section_table_range); + String8 raw_coff_symbol_table = str8_substr(input->data, header.symbol_table_range); + String8 raw_coff_string_table = str8_substr(input->data, header.string_table_range); // // error check: section table / symbol table / string table // - if (raw_coff_section_table.size != dim_1u64(coff_info.section_table_range)) { + if (raw_coff_section_table.size != dim_1u64(header.section_table_range)) { lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "corrupted file, unable to read section header table"); } - if (raw_coff_symbol_table.size != dim_1u64(coff_info.symbol_table_range)) { + if (raw_coff_symbol_table.size != dim_1u64(header.symbol_table_range)) { lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "corrupted file, unable to read symbol table"); } - if (raw_coff_string_table.size != dim_1u64(coff_info.string_table_range)) { + if (raw_coff_string_table.size != dim_1u64(header.string_table_range)) { lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "corrupted file, unable to read string table"); } @@ -87,7 +87,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // error check section headers // COFF_SectionHeader *coff_section_table = (COFF_SectionHeader *)raw_coff_section_table.str; - for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) { + for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *coff_sect_header = &coff_section_table[sect_idx]; // read name @@ -97,16 +97,16 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) if (coff_sect_header->fsize > 0) { Rng1U64 sect_range = rng_1u64(coff_sect_header->foff, coff_sect_header->foff + coff_sect_header->fsize); - if (contains_1u64(coff_info.header_range, coff_sect_header->foff) || - (coff_sect_header->fsize > 0 && contains_1u64(coff_info.header_range, sect_range.max-1))) { + if (contains_1u64(header.header_range, coff_sect_header->foff) || + (coff_sect_header->fsize > 0 && contains_1u64(header.header_range, sect_range.max-1))) { lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into file header)", sect_name, sect_idx+1); } - if (contains_1u64(coff_info.section_table_range, coff_sect_header->foff) || - (coff_sect_header->fsize > 0 && contains_1u64(coff_info.section_table_range, sect_range.max-1))) { + if (contains_1u64(header.section_table_range, coff_sect_header->foff) || + (coff_sect_header->fsize > 0 && contains_1u64(header.section_table_range, sect_range.max-1))) { lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into section header table)", sect_name, sect_idx+1); } - if (contains_1u64(coff_info.symbol_table_range, coff_sect_header->foff) || - (coff_sect_header->fsize > 0 && contains_1u64(coff_info.symbol_table_range, sect_range.max-1))) { + if (contains_1u64(header.symbol_table_range, coff_sect_header->foff) || + (coff_sect_header->fsize > 0 && contains_1u64(header.symbol_table_range, sect_range.max-1))) { lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into symbol table)", sect_name, sect_idx+1); } if (dim_1u64(sect_range) != coff_sect_header->fsize) { @@ -116,12 +116,59 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } } + // + // create symbol links to COMDAT sections + // + U32 *comdats; + { + comdats = push_array_no_zero(arena, U32, header.section_count_no_null); + MemorySet(comdats, 0xff, header.section_count_no_null * sizeof(comdats[0])); + + String8 string_table = str8_substr(input->data, header.string_table_range); + String8 symbol_table = str8_substr(input->data, header.symbol_table_range); + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + if (header.is_big_obj) { + symbol = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + symbol_idx); + } else { + symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx); + } + + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_Regular) { + if (symbol.storage_class == COFF_SymStorageClass_Static) { + if (symbol.section_number > 0 && symbol.section_number <= header.section_count_no_null) { + COFF_SectionHeader *sect_header = &coff_section_table[symbol.section_number-1]; + if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { + if (symbol.aux_symbol_count) { + U32 section_length = 0; + coff_parse_secdef(symbol, header.is_big_obj, 0, 0, §ion_length, 0); + if (sect_header->fsize == section_length) { + if (comdats[symbol.section_number-1] == ~0) { + comdats[symbol.section_number-1] = symbol_idx; + } else { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "section definition symbo (No. 0x%llx) tries to ovewrite comdat", symbol_idx); + } + } else { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "section size specified by section definition symbol (No 0x%llx) doesn't match size in section header (No. 0x%x); expected 0x%x got 0x%x", symbol_idx, symbol.section_number, section_length, sect_header->fsize); + } + } + } + } else { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "section definition symbol (No. 0x%llx) has out of bounds section number 0x%x", symbol_idx, symbol.section_number); + } + } + } + } + } + // fill out obj obj->data = input->data; obj->path = push_str8_copy(arena, input->path); obj->lib_path = push_str8_copy(arena, input->lib_path); obj->input_idx = obj_idx; - obj->header = coff_info; + obj->header = header; + obj->comdats = comdats; } internal LNK_ObjNodeArray diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index c0c15ea5..093a1334 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -12,6 +12,7 @@ typedef struct LNK_Obj String8 lib_path; U64 input_idx; COFF_FileHeaderInfo header; + U32 *comdats; } LNK_Obj; typedef struct LNK_ObjNode @@ -100,6 +101,7 @@ internal U32 lnk_obj_get_vol_md(LNK_Obj *obj); internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff(LNK_Obj *obj, void *coff_symbol); internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx); +internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number); //////////////////////////////// diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index b5053581..2ae0f775 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -237,25 +237,27 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) { COFF_ComdatSelectType dst_select; - U32 dst_section_length; - U32 dst_check_sum; + U32 dst_section_length; + U32 dst_check_sum; if (dst_interp == COFF_SymbolValueInterp_Regular) { - coff_parse_secdef(dst_parsed, dst_obj->header.is_big_obj, &dst_select, 0, &dst_section_length, &dst_check_sum); + COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(dst_obj, dst_obj->comdats[dst_parsed.section_number-1]); + coff_parse_secdef(secdef, dst_obj->header.is_big_obj, &dst_select, 0, &dst_section_length, &dst_check_sum); } else { - dst_select = COFF_ComdatSelect_Largest; + dst_select = COFF_ComdatSelect_Largest; dst_section_length = dst_parsed.value; - dst_check_sum = 0; + dst_check_sum = 0; } COFF_ComdatSelectType src_select; - U32 src_section_length; - U32 src_check_sum; + U32 src_section_length; + U32 src_check_sum; if (src_interp == COFF_SymbolValueInterp_Regular) { - coff_parse_secdef(src_parsed, src_obj->header.is_big_obj, &src_select, 0, &src_section_length, &src_check_sum); + COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(src_obj, src_obj->comdats[src_parsed.section_number-1]); + coff_parse_secdef(secdef, src_obj->header.is_big_obj, &src_select, 0, &src_section_length, &src_check_sum); } else { - src_select = COFF_ComdatSelect_Largest; + src_select = COFF_ComdatSelect_Largest; src_section_length = src_parsed.value; - src_check_sum = 0; + src_check_sum = 0; } // handle objs compiled with /GR- and /GR @@ -332,6 +334,12 @@ lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) if (dst->type == LNK_Symbol_Lib && src->type == LNK_Symbol_Lib) { dst->u.lib = src->u.lib; } else if (dst->type == LNK_Symbol_Defined && src->type == LNK_Symbol_Defined) { + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx); + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx); + COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->u.defined.obj, dst_parsed.section_number); + COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->u.defined.obj, src_parsed.section_number); + AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); + dst_sect->flags |= COFF_SectionFlag_LnkRemove; dst->u.defined = src->u.defined; } else { InvalidPath; diff --git a/src/pe/pe_make_export_table.c b/src/pe/pe_make_export_table.c index 7edb4fe5..edf1d0cd 100644 --- a/src/pe/pe_make_export_table.c +++ b/src/pe/pe_make_export_table.c @@ -139,7 +139,7 @@ pe_finalize_export_list(Arena *arena, PE_ExportParseList export_list) } } if (ordinal_low == max_U64) { - ordinal_low = 0; + ordinal_low = 1; } // assign omitted ordinals @@ -262,7 +262,7 @@ pe_make_edata_obj(Arena *arena, str8_list_push(obj_writer->arena, &string_table_sect->data, export_name_cstr); // create symbol for the name string - String8 export_name_symbol_name = push_str8f(obj_writer->arena, "RADNAME:%S", name); + String8 export_name_symbol_name = push_str8f(obj_writer->arena, "%S", name); COFF_ObjSymbol *export_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, export_name_symbol_name, export_name_offset, string_table_sect); // create slot for export virtual offset