From 03e4958190eab3f312b9d8dfd2c9d07af1b28602 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 16 May 2025 13:33:09 -0700 Subject: [PATCH] assign layout offsets and sizes to merged sections --- src/linker/lnk.c | 51 ++++++++++++++++++++++------------ src/linker/lnk_config.c | 5 ++-- src/linker/lnk_section_table.c | 48 +++++++++++++++++++++++++++++--- src/linker/lnk_section_table.h | 23 +++++++++------ 4 files changed, 95 insertions(+), 32 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 6cefa2b7..d94fe688 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2281,6 +2281,11 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S { ProfBegin("Finalize Sections Layout"); + // merge sections + if (config->flags & LNK_ConfigFlag_Merge) { + lnk_section_table_merge(sectab, config->merge_list); + } + // sort contribs for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { for (LNK_SectionContribChunk *sc_chunk = sect_n->data.contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) { @@ -2289,32 +2294,31 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S } } - // merge sections - if (config->flags & LNK_ConfigFlag_Merge) { - lnk_section_table_merge(sectab, config->merge_list); - } - // 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(sectab, §_n->data, config->file_align); } // remove empty sections - String8List empty_sect_list = {0}; - for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { - LNK_Section *sect = §_n->data; - if (sect->vsize == 0) { - str8_list_push(scratch.arena, &empty_sect_list, sect->name); + { + String8List empty_sect_list = {0}; + for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { + LNK_Section *sect = §_n->data; + if (sect->vsize == 0) { + str8_list_push(scratch.arena, &empty_sect_list, sect->name); + } + } + for (String8Node *name_n = empty_sect_list.first; name_n != 0; name_n = name_n->next) { + lnk_section_table_remove(sectab, name_n->string); } - } - for (String8Node *name_n = empty_sect_list.first; name_n != 0; name_n = name_n->next) { - lnk_section_table_remove(sectab, name_n->string); } // assign section indices to sections - U64 sect_idx = 0; - for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { - sect_n->data.sect_idx = sect_idx++; + { + U64 sect_idx = 0; + for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { + sect_n->data.sect_idx = sect_idx++; + } } // assign section indices to contribs @@ -2327,6 +2331,19 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S } } + // 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_SectionContrib *first_sc = lnk_get_first_section_contrib(sect); + LNK_SectionContrib *last_sc = lnk_get_last_section_contrib(sect); + LNK_Section *final_sect = lnk_finalized_section_from_id(sectab, sect->merge_id); + sect->voff = final_sect->voff + first_sc->u.off; + sect->vsize = (last_sc->u.off - first_sc->u.off) + last_sc->u.size; + sect->foff = final_sect->foff + first_sc->u.off; + sect->fsize = (last_sc->u.off - first_sc->u.off) + last_sc->u.size; + sect->sect_idx = final_sect->sect_idx; + } + ProfEnd(); } @@ -3054,7 +3071,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S ProfEnd(); } - // patch Debug + // patch debug { LNK_Section *debug_dir_sect = lnk_section_table_search(sectab, str8_lit(".RAD_LINKER_DEBUG_DIR"), PE_RDATA_SECTION_FLAGS); if (debug_dir_sect) { diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 89c96599..3118a91f 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1436,12 +1436,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Merge: { if (value_strings.node_count == 1) { - LNK_MergeDirective merge = {0};; + LNK_MergeDirective merge = {0}; if (lnk_parse_merge_directive(push_str8_copy(arena, value_strings.first->string), &merge)) { lnk_merge_directive_list_push(arena, &config->merge_list, merge); } else { - lnk_error_cmd_switch(LNK_Warning_InvalidMergeDirectiveFormat, obj_path, lib_path, cmd_switch, "invalid merge directive format expected \"/MERGE:FROM=TO\" but got \"%S\"", - value_strings.first->string); + lnk_error_cmd_switch(LNK_Warning_InvalidMergeDirectiveFormat, obj_path, lib_path, cmd_switch, "unable to parse merge directive, expected format \"/MERGE:FROM=TO\" but got \"%S\"", value_strings.first->string); } } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters %d", value_strings.node_count); diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index de6ed91b..1d1edf09 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -91,6 +91,17 @@ lnk_get_first_section_contrib(LNK_Section *sect) return 0; } +internal LNK_SectionContrib * +lnk_get_last_section_contrib(LNK_Section *sect) +{ + if (sect->contribs.chunk_count > 0) { + if (sect->contribs.last->count > 0) { + return sect->contribs.last->v[0]; + } + } + return 0; +} + internal LNK_SectionTable * lnk_section_table_alloc(void) { @@ -148,7 +159,7 @@ lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags return sect; } -internal void +internal LNK_SectionNode * lnk_section_table_remove(LNK_SectionTable *sectab, String8 name) { ProfBeginFunction(); @@ -190,6 +201,7 @@ lnk_section_table_remove(LNK_SectionTable *sectab, String8 name) } ProfEnd(); + return node; } internal LNK_Section * @@ -210,8 +222,12 @@ lnk_section_table_search(LNK_SectionTable *sectab, String8 full_or_partial_name, } internal LNK_SectionArray -lnk_section_table_search_many(Arena *arena, LNK_SectionTable *sectab, String8 name) +lnk_section_table_search_many(Arena *arena, LNK_SectionTable *sectab, String8 full_or_partial_name) { + String8 name = {0}; + String8 postfix = {0}; + coff_parse_section_name(full_or_partial_name, &name, &postfix); + U64 match_count = 0; for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { if (str8_match(sect_n->data.name, name, 0)) { @@ -223,7 +239,7 @@ lnk_section_table_search_many(Arena *arena, LNK_SectionTable *sectab, String8 na if (match_count > 0) { result.count = 0; - result.v = push_array(arena, LNK_Section *, match_count); + result.v = push_array(arena, LNK_Section *, match_count); for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { if (str8_match(sect_n->data.name, name, 0)) { @@ -307,9 +323,14 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l // merge section with destination lnk_section_contrib_chunk_list_concat_in_place(&dst->contribs, &src->contribs); src->is_merged = 1; + src->merge_id = dst->id; // remove from output section list - lnk_section_table_remove(sectab, src->name); + LNK_SectionNode *merge_node = lnk_section_table_remove(sectab, src->name); + + // move node to the merge list + SLLQueuePush(sectab->merge_list.first, sectab->merge_list.last, merge_node); + sectab->merge_list.count += 1; } } scratch_end(scratch); @@ -387,3 +408,22 @@ lnk_assign_section_file_space(LNK_Section *sect, U64 *foff_cursor) } } +internal LNK_Section * +lnk_finalized_section_from_id(LNK_SectionTable *sectab, U64 id) +{ + for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { + if (sect_n->data.id == id) { + return §_n->data; + } + } + + for (LNK_SectionNode *sect_n = sectab->merge_list.first; sect_n != 0; sect_n = sect_n->next) { + if (sect_n->data.id == id) { + return lnk_finalized_section_from_id(sectab, sect_n->data.merge_id); + } + } + + return 0; +} + + diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index d44bcb81..2cdbf041 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -60,12 +60,12 @@ typedef struct LNK_SectionDefinition typedef struct LNK_Section { - U64 id; - String8 name; - COFF_SectionFlags flags; - B32 has_layout; - B32 is_merged; - + U64 id; + String8 name; + COFF_SectionFlags flags; + B32 has_layout; + B32 is_merged; + U64 merge_id; LNK_SectionContribChunkList contribs; U64 voff; @@ -101,7 +101,7 @@ typedef struct LNK_SectionTable U64 id_max; U64 next_sect_idx; LNK_SectionList list; - LNK_SectionList free_list; + LNK_SectionList merge_list; HashTable *sect_ht; // name -> LNK_Section * } LNK_SectionTable; @@ -116,11 +116,18 @@ internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionL //////////////////////////////// +internal LNK_SectionContrib * lnk_get_last_section_contrib(LNK_Section *sect); +internal LNK_SectionTable * lnk_section_table_alloc(void); + +//////////////////////////////// + internal LNK_SectionTable * lnk_section_table_alloc(void); internal void lnk_section_table_release(LNK_SectionTable **st_ptr); internal LNK_Section * lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags); -internal void lnk_section_table_remove(LNK_SectionTable *sectab, String8 name); +internal LNK_SectionNode * lnk_section_table_remove(LNK_SectionTable *sectab, String8 name); internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags); +internal LNK_SectionArray lnk_section_table_search_many(Arena *arena, LNK_SectionTable *sectab, String8 full_or_partial_name); internal void lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_list); internal LNK_SectionArray lnk_section_table_get_output_sections(Arena *arena, LNK_SectionTable *sectab); +internal LNK_Section * lnk_finalized_section_from_id(LNK_SectionTable *sectab, U64 id);