diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index b3ca7645..33da32fb 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -283,6 +283,15 @@ coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 return s; } +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section) +{ + COFF_SymbolType type = { .u.msb = COFF_SymDType_Func }; + COFF_SymbolLocation loc = { .type = COFF_SymbolLocation_Section, .u.section = section }; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_External); + return s; +} + internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section) { diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h index 9e6b9d68..9068822a 100644 --- a/src/coff/coff_obj_writer.h +++ b/src/coff/coff_obj_writer.h @@ -102,6 +102,7 @@ internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data); internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class); +internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section); internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section); internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section); internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 2b809166..f85db038 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -179,7 +179,6 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FunctionPadMin, "0"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); @@ -1491,9 +1490,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (obj_node_arr.v[obj_idx].data.header.machine != COFF_MachineType_Unknown) { config->machine = obj_node_arr.v[obj_idx].data.header.machine; - if (config->do_function_pad_min == LNK_SwitchState_Yes && config->function_pad_min == 0) { - config->function_pad_min = push_array(tp_arena->v[0], U64, 1); - *config->function_pad_min = lnk_get_default_function_pad_min(config->machine); + if (config->infer_function_pad_min) { + config->function_pad_min = lnk_get_default_function_pad_min(config->machine); } break; @@ -2348,15 +2346,17 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_contribs_task) ProfBeginV("Gather Section Contribs [%S]", obj->path); for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { - LNK_SectionContrib *sc = &g_null_sc; + LNK_SectionContrib *sc = &g_null_sc; COFF_SectionHeader *sect_header = §ion_table[sect_idx]; - if (~sect_header->flags & COFF_SectionFlag_LnkRemove) { - Temp temp = temp_begin(scratch.arena); - - String8 sect_name = coff_name_from_section_header(string_table, sect_header); - String8 sect_name_with_flags = lnk_make_name_with_flags(temp.arena, sect_name, sect_header->flags & ~COFF_SectionFlags_LnkFlags); - LNK_SectionContribChunk *sc_chunk = 0; - hash_table_search_string_raw(task->contribs_ht, sect_name_with_flags, &sc_chunk); + if (~sect_header->flags & COFF_SectionFlag_LnkRemove && sect_header->fsize > 0) { + LNK_SectionContribChunk *sc_chunk = 0; + { + Temp temp = temp_begin(scratch.arena); + String8 sect_name = coff_name_from_section_header(string_table, sect_header); + String8 sect_name_with_flags = lnk_make_name_with_flags(temp.arena, sect_name, sect_header->flags & ~COFF_SectionFlags_LnkFlags); + hash_table_search_string_raw(task->contribs_ht, sect_name_with_flags, &sc_chunk); + temp_end(temp); + } if (sc_chunk) { U16 sc_align = coff_align_size_from_section_flags(sect_header->flags); @@ -2368,8 +2368,6 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_contribs_task) sc->u.obj_idx = obj_idx; sc->u.obj_sect_idx = sect_idx; } - - temp_end(temp); } task->sect_map[obj_idx][sect_idx] = sc; } @@ -2402,6 +2400,43 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_task) ProfEnd(); } +internal +THREAD_POOL_TASK_FUNC(lnk_patch_comdats_task) +{ + LNK_BuildImageTask *task = raw_task; + U64 obj_idx = task_id; + LNK_Obj *obj = task->objs[obj_idx]; + + ProfBeginV("Patch COMDATs [%S]", obj->path); + 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) { + LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name); + + if (defn->u.defined.obj == obj && defn->u.defined.symbol_idx == symbol_idx) { + LNK_SectionContrib *sc = task->sect_map[obj_idx][symbol.section_number-1]; + if (obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol.raw_symbol; + symbol32->section_number = sc->u.sect_idx+1; + symbol32->value = safe_cast_u32(sc->u.off + symbol.value); + } else { + COFF_Symbol16 *symbol16 = symbol.raw_symbol; + symbol16->section_number = safe_cast_u16(sc->u.sect_idx+1); + symbol16->value = safe_cast_u32(sc->u.off + symbol.value); + } + + task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; + } + } + } + } + ProfEnd(); +} + internal THREAD_POOL_TASK_FUNC(lnk_split_func_contribs_task) { @@ -2414,6 +2449,7 @@ THREAD_POOL_TASK_FUNC(lnk_split_func_contribs_task) ProfBeginV("%S", obj->path); + U64List func_list = {0}; 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); @@ -2471,24 +2507,22 @@ THREAD_POOL_TASK_FUNC(lnk_split_func_contribs_task) } } } + + u64_list_push(scratch.arena, &func_list, symbol_idx); } } + U64 *sect_offset_map_counts = push_array(scratch.arena, U64, obj->header.section_count_no_null); + PairU64 **sect_offset_map = push_array(scratch.arena, PairU64 *, obj->header.section_count_no_null); for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx+1); - if (~section_header->flags & COFF_SectionFlag_CntCode) { continue; } - COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header); - COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off); - LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; + LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; U64 offset_map_count = 0; for (String8Node *data_n = &sc->first_data_node; data_n != 0; data_n = data_n->next) { offset_map_count += 1; } - if (offset_map_count <= 1) { continue; } - Temp temp = temp_begin(scratch.arena); - PairU64 *offset_map = push_array(temp.arena, PairU64, offset_map_count); + PairU64 *offset_map = push_array(scratch.arena, PairU64, offset_map_count); U64 data_node_idx = 0; U64 prev_cursor_offset = 0; U64 new_cursor_offset = 0; @@ -2499,19 +2533,43 @@ THREAD_POOL_TASK_FUNC(lnk_split_func_contribs_task) new_cursor_offset += Max(task->function_pad_min, data_n->string.size); } - for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; reloc_idx += 1) { - COFF_Reloc *reloc = &relocs[reloc_idx]; - U64 offset_idx = pair_u64_nearest_v0(offset_map, offset_map_count, reloc->apply_off); - if (offset_idx < offset_map_count) { - reloc->apply_off = offset_map[offset_idx].v1 + (reloc->apply_off - offset_map[offset_idx].v0); - } else { - InvalidPath; - } - } - temp_end(temp); + sect_offset_map_counts[sect_idx] = offset_map_count; + sect_offset_map[sect_idx] = offset_map; } - // TODO: update symbols with new offsets + for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx+1); + if (section_header->flags & COFF_SectionFlag_CntCode) { + COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header); + COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off); + LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; + U64 offset_map_count = sect_offset_map_counts[sect_idx]; + PairU64 *offset_map = sect_offset_map[sect_idx]; + if (offset_map_count > 0) { + for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; reloc_idx += 1) { + COFF_Reloc *reloc = &relocs[reloc_idx]; + U64 offset_idx = pair_u64_nearest_v0(offset_map, offset_map_count, reloc->apply_off); + if (offset_idx < offset_map_count) { + reloc->apply_off = offset_map[offset_idx].v1 + (reloc->apply_off - offset_map[offset_idx].v0); + } else { + InvalidPath; + } + } + } + } + } + + for (U64Node *func_n = func_list.first; func_n != 0; func_n = func_n->next) { + COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, func_n->data); + + U64 offset_map_count = sect_offset_map_counts[symbol.section_number-1]; + PairU64 *offset_map = sect_offset_map[symbol.section_number-1]; + U64 offset_idx = pair_u64_nearest_v0(offset_map, offset_map_count, symbol.value); + AssertAlways(offset_idx < offset_map_count); + + U32 *value_ptr = obj->header.is_big_obj ? &((COFF_Symbol32 *)symbol.raw_symbol)->value : &((COFF_Symbol16 *)symbol.raw_symbol)->value; + *value_ptr = offset_map[offset_idx].v1 + (*value_ptr - offset_map[offset_idx].v0); + } ProfEnd(); @@ -2608,15 +2666,17 @@ THREAD_POOL_TASK_FUNC(lnk_patch_regular_symbols_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { - U32 section_number = 0; - U32 value = 0; - { - COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); - if (~sect_header->flags & COFF_SectionFlag_LnkRemove) { - LNK_SectionContrib *sc = task->sect_map[obj_idx][symbol.section_number-1]; - section_number = safe_cast_u32(sc->u.sect_idx + 1); - value = sc->u.off + symbol.value; - } + COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); + + LNK_SectionContrib *sc = task->sect_map[obj_idx][symbol.section_number-1]; + U16 section_number; + U32 value; + if (sc == &g_null_sc) { + section_number = LNK_REMOVED_SECTION_NUMBER; + value = max_U32; + } else { + section_number = safe_cast_u32(sc->u.sect_idx + 1); + value = sc->u.off + symbol.value; } if (obj->header.is_big_obj) { @@ -3013,18 +3073,20 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) U32 symbol_secoff = 0; S64 symbol_voff = 0; { - COFF_ParsedSymbol symbol; - if (obj_header.is_big_obj) { - symbol = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + reloc->isymbol); - } else { - symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + reloc->isymbol); - } - + COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, reloc->isymbol); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { + if (symbol.section_number == LNK_REMOVED_SECTION_NUMBER) { + if (!lnk_is_coff_section_debug(obj, sect_idx)) { + String8 sect_name = coff_name_from_section_header(string_table, §ion_table[sect_idx]); + lnk_error_obj(LNK_Error_RelocationAgainstRemovedSection, obj, "relocating against symbol that is in a removed section (symbol: %S, reloc-section: %S 0x%llx, reloc: 0x%llx)", symbol.name, sect_name, sect_idx+1, reloc_idx); + } + continue; + } + symbol_secnum = symbol.section_number; symbol_secoff = symbol.value; - symbol_voff = safe_cast_u32((U64)task->image_section_table[symbol.section_number]->voff + (U64)symbol_secoff); + symbol_voff = safe_cast_u32((U64)task->image_section_table[symbol.section_number]->voff + (U64)symbol_secoff); } else if (interp == COFF_SymbolValueInterp_Abs) { // There aren't enough bits in COFF symbol to store full image base address, // so we special case __ImageBase. A better solution would be to add @@ -3035,7 +3097,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) symbol_secnum = 0; symbol_secoff = 0; - symbol_voff = (S64)symbol.value - (S64)task->image_base; + symbol_voff = (S64)symbol.value - (S64)task->image_base; } else if (interp == COFF_SymbolValueInterp_Weak) { // unresolved weak } else if (interp == COFF_SymbolValueInterp_Undefined) { @@ -3540,7 +3602,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_file_offsets_and_sizes_in_obj_section_headers_ta for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *sect_header = §ion_table[sect_idx]; B32 patch_section_header = (~sect_header->flags & COFF_SectionFlag_LnkRemove) && - !lnk_is_coff_section_debug(obj, sect_idx); + !lnk_is_coff_section_debug(obj, sect_idx); if (patch_section_header) { LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; LNK_Section *sect = task->image_sects.v[sc->u.sect_idx]; @@ -4007,7 +4069,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_BuildImageTask task = {0}; task.symtab = symtab; task.sectab = sectab; - task.function_pad_min = *config->function_pad_min; + task.function_pad_min = config->function_pad_min; task.default_align = coff_default_align_from_machine(config->machine); task.objs_count = objs_count; task.objs = objs; @@ -4153,10 +4215,6 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT ProfEnd(); } - ProfBegin("Set COMDAT Leaders"); - tp_for_parallel(tp, 0, objs_count, lnk_set_comdat_leaders_task, &task); - ProfEnd(); - // build common block // // TODO: build common block in .bss and merge with .data @@ -4213,7 +4271,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT radsort(common_block_contribs, common_block_contribs_count, lnk_common_block_contrib_is_before); // compute .bss virtual size - this marks start of the common block - lnk_finalize_section_layout(common_block_sect, config->file_align, *config->function_pad_min); + lnk_finalize_section_layout(common_block_sect, config->file_align, config->function_pad_min); U64 common_block_cursor = common_block_sect->vsize; // compute and assign offsets into the common block @@ -4253,7 +4311,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // assign contribs offsets, sizes, and section indices for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { - lnk_finalize_section_layout(§_n->data, config->file_align, *config->function_pad_min); + lnk_finalize_section_layout(§_n->data, config->file_align, config->function_pad_min); } // remove empty sections @@ -4277,16 +4335,15 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // assing layout offsets and sizes to merged sections for (LNK_SectionNode *sect_n = sectab->merge_list.first; sect_n != 0; sect_n = sect_n->next) { - LNK_Section *sect = §_n->data; - LNK_Section *final_sect = sect->merge_dst; - LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect); - LNK_SectionContrib *last_sc = lnk_get_last_section_contrib(sect); - U64 last_sc_size = lnk_size_from_section_contrib(last_sc); - sect->voff = final_sect->voff + first_sc->u.off; - sect->vsize = (last_sc->u.off - first_sc->u.off) + last_sc_size; - sect->foff = final_sect->foff + first_sc->u.off; - sect->fsize = (last_sc->u.off - first_sc->u.off) + last_sc_size; - sect->sect_idx = final_sect->sect_idx; + LNK_Section *sect = §_n->data; + LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect); + LNK_SectionContrib *last_sc = lnk_get_last_section_contrib(sect); + U64 last_sc_size = lnk_size_from_section_contrib(last_sc); + sect->voff = sect->merge_dst->voff + first_sc->u.off; + sect->vsize = (last_sc->u.off - first_sc->u.off) + last_sc_size; + sect->foff = sect->merge_dst->foff + first_sc->u.off; + sect->fsize = (last_sc->u.off - first_sc->u.off) + last_sc_size; + lnk_assign_section_index(sect, sect->merge_dst->sect_idx); } ProfEnd(); @@ -4309,6 +4366,14 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT task.u.patch_symtabs.common_block_contribs = common_block_contribs; ProfEnd(); + ProfBegin("Set COMDAT Leaders"); + tp_for_parallel(tp, 0, objs_count, lnk_set_comdat_leaders_task, &task); + ProfEnd(); + + ProfBegin("Patch COMDAT Leaders"); + tp_for_parallel(tp, 0, objs_count, lnk_patch_comdats_task, &task); + ProfEnd(); + ProfBegin("Patch Common Block Leaders"); tp_for_parallel(tp, 0, tp->worker_count, lnk_patch_common_block_leaders_task, &task); ProfEnd(); @@ -4369,10 +4434,10 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(first_sc_chunk, 1); sc->first_data_node = *base_relocs_data.first; sc->last_data_node = base_relocs_data.last; - sc->align = 1; - sc->u.obj_idx = max_U32; + sc->align = 1; + sc->u.obj_idx = max_U32; - lnk_finalize_section_layout(reloc, config->file_align, *config->function_pad_min); + lnk_finalize_section_layout(reloc, config->file_align, config->function_pad_min); lnk_assign_section_virtual_space(reloc, config->sect_align, &voff_cursor); lnk_assign_section_index(reloc, sectab->next_sect_idx++); @@ -4404,7 +4469,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT image_header_sc->first_data_node = *image_header_data.first; image_header_sc->last_data_node = image_header_data.last; - lnk_finalize_section_layout(image_header_sect, config->file_align, *config->function_pad_min); + lnk_finalize_section_layout(image_header_sect, config->file_align, config->function_pad_min); } ProfBegin("Patch Section Symbols"); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index b5f44e12..84c07ce2 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -16,6 +16,8 @@ typedef struct LNK_LinkContext // -- Image -------------------------------------------------------------------- +#define LNK_REMOVED_SECTION_NUMBER (U16)-3 + typedef struct LNK_ImageContext { String8 image_data; diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index fda0eba0..55d156f2 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1202,10 +1202,10 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_FunctionPadMin: { if (value_strings.node_count == 0) { - config->function_pad_min = 0; + config->function_pad_min = 0; + config->infer_function_pad_min = 1; } else { - config->function_pad_min = push_array(arena, U64, 1); - lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, config->function_pad_min, LNK_ParseU64Flag_CheckUnder32bit); + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->function_pad_min, LNK_ParseU64Flag_CheckUnder32bit); } config->do_function_pad_min = LNK_SwitchState_Yes; } break; diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 07a07f21..a2db79a3 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -325,7 +325,8 @@ typedef struct LNK_Config U64 max_worker_count; String8 shared_thread_pool_name; LNK_SwitchState do_function_pad_min; - U64 *function_pad_min; + B32 infer_function_pad_min; + U64 function_pad_min; U64 *manifest_resource_id; B32 no_default_libs; Version link_ver; diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index c09fb02e..e10db029 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -40,6 +40,7 @@ typedef enum LNK_Error_UnresolvedSymbol, LNK_Error_AssociativeLoop, LNK_Error_AlternateNameConflict, + LNK_Error_RelocationAgainstRemovedSection, LNK_Error_StopLast, LNK_Error_First, diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 6cdb1287..40540dde 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -299,6 +299,10 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) switch (interp) { case COFF_SymbolValueInterp_Regular: { if (symbol.storage_class == COFF_SymStorageClass_External) { + COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); + if (sect_header->flags & COFF_SectionFlag_LnkRemove) { + break; + } LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); U64 hash = lnk_symbol_hash(symbol.name); lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, hash, defn); diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index f2db71cb..aee79dc0 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -347,7 +347,7 @@ lnk_finalize_section_layout(LNK_Section *sect, U64 file_align, U64 function_pad_ for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) { LNK_SectionContrib *sc = sc_chunk->v[sc_idx]; - // assign offset and size + // assign offset cursor = AlignPow2(cursor, sc->align); sc->u.off = cursor; diff --git a/src/torture/torture.c b/src/torture/torture.c index 74023605..92d692dd 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -3352,6 +3352,48 @@ exit:; return result; } +internal T_Result +t_function_pad_min(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 ret[] = { 0xc3, 0xc3, 0xc3 }; + COFF_ObjSection *text_sect = t_push_text_section(obj_writer, str8_array_fixed(ret)); + coff_obj_writer_push_symbol_extern_func(obj_writer, str8_lit("A"), 0, text_sect); + coff_obj_writer_push_symbol_extern_func(obj_writer, str8_lit("B"), 1, text_sect); + coff_obj_writer_push_symbol_extern_func(obj_writer, str8_lit("C"), 2, text_sect); + String8 obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + if (!t_write_file(str8_lit("funcs.obj"), obj)) { goto exit; } + } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:A /functionpadmin:8 /out:a.exe funcs.obj"); + if (linker_exit_code != 0) { goto exit; } + + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + + U8 expected_text[] = { + 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc + }; + if (!str8_match(text_data, str8_array_fixed(expected_text), 0)) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + //////////////////////////////////////////////////////////////// internal void @@ -3405,6 +3447,7 @@ entry_point(CmdLine *cmdline) { "delay_import_user32", t_delay_import_user32 }, { "empty_section", t_empty_section }, { "removed_section", t_removed_section }, + { "function_pad_min", t_function_pad_min }, //{ "import_export", t_import_export }, };