From a484906cf96e047551e0c1dace9876ed70241223 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 9 Jun 2025 14:08:37 -0700 Subject: [PATCH] create section contribution for common block --- src/linker/lnk.c | 48 +++++++++++++++++++++------------- src/linker/lnk_section_table.c | 23 +++++++++------- src/linker/lnk_section_table.h | 25 ++++++++---------- src/torture/torture.c | 7 ++--- 4 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 875b9a5e..ab34c89b 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3399,7 +3399,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_virtual_offsets_and_sizes_in_obj_section_headers if (~sect_header->flags & COFF_SectionFlag_LnkRemove) { LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; LNK_Section *sect = task->image_sects.v[sc->u.sect_idx]; - sect_header->vsize = sc->u.size; + sect_header->vsize = lnk_size_from_section_contribution(sc); sect_header->voff = sect->voff + sc->u.off; } } @@ -3423,7 +3423,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_file_offsets_and_sizes_in_obj_section_headers_ta LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; LNK_Section *sect = task->image_sects.v[sc->u.sect_idx]; if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { - sect_header->fsize = sc->u.size; + sect_header->fsize = lnk_size_from_section_contribution(sc); sect_header->foff = sect->foff + sc->u.off; } } @@ -3880,6 +3880,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT lnk_section_table_push(sectab, str8_lit(".rdata"), PE_RDATA_SECTION_FLAGS); lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS); lnk_section_table_push(sectab, str8_lit(".bss"), PE_BSS_SECTION_FLAGS); + LNK_Section *common_block_sect = lnk_section_table_search(sectab, str8_lit(".bss"), PE_BSS_SECTION_FLAGS); LNK_BuildImageTask task = {0}; task.symtab = symtab; @@ -4032,7 +4033,6 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // TODO: build common block in .bss and merge with .data U64 common_block_contribs_count; LNK_CommonBlockContrib *common_block_contribs; - LNK_Section *common_block_sect; { ProfBegin("Build Common Block"); @@ -4078,23 +4078,35 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT ProfEnd(); if (common_block_contribs_count) { - ProfBeginV("Assign Common Block Offsets [count %llu]", common_block_contribs_count); + ProfBeginV("Make Common Block [count %llu]", common_block_contribs_count); - // grab .bss section - common_block_sect = lnk_section_table_search(sectab, str8_lit(".bss"), PE_BSS_SECTION_FLAGS); - - // sort common blocks from largest to smallest for tighter packing + // sort common blocks from for tighter packing radsort(common_block_contribs, common_block_contribs_count, lnk_common_block_contrib_is_before); - // compute common block offsets + // compute .bss virtual size - this marks start of the common block + lnk_finalize_section_layout(sectab, common_block_sect, config->file_align); + U64 common_block_cursor = common_block_sect->vsize; + + // compute and assign offsets into the common block for (U64 contrib_idx = 0; contrib_idx < common_block_contribs_count; contrib_idx += 1) { LNK_CommonBlockContrib *contrib = &common_block_contribs[contrib_idx]; U32 size = contrib->u.size; U32 align = Min(32, u64_up_to_pow2(size)); // link.exe caps align at 32 bytes - common_block_sect->vsize = AlignPow2(common_block_sect->vsize, align); - contrib->u.offset = common_block_sect->vsize; - common_block_sect->vsize += size; + common_block_cursor = AlignPow2(common_block_cursor, align); + contrib->u.offset = common_block_cursor; + common_block_cursor += size; } + + // append common block's contribution + LNK_SectionContribChunk *common_block_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &common_block_sect->contribs, 1, str8(0,0)); + LNK_SectionContrib *common_block_sc = lnk_section_contrib_chunk_push(common_block_chunk, 1); + common_block_sc->u.obj_idx = max_U32; + common_block_sc->u.obj_sect_idx = max_U32; + common_block_sc->align = 1; + common_block_sc->node.next = 0; + common_block_sc->node.string = str8(0, common_block_cursor - common_block_sect->vsize); + common_block_sc->data_list = &common_block_sc->node; + ProfEnd(); } @@ -4140,10 +4152,11 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_Section *final_sect = lnk_finalized_section_from_id(sectab, sect->merge_id); 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_contribution(last_sc); sect->voff = final_sect->voff + first_sc->u.off; - sect->vsize = (last_sc->u.off - first_sc->u.off) + last_sc->u.size; + 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->u.size; + sect->fsize = (last_sc->u.off - first_sc->u.off) + last_sc_size; sect->sect_idx = final_sect->sect_idx; } @@ -4259,7 +4272,6 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT image_header_sc->align = config->file_align; image_header_sc->data_list = image_header_data.first; - image_header_sc->u.size = safe_cast_u32(image_header_data.total_size); lnk_finalize_section_layout(sectab, image_header_sect, config->file_align); } @@ -4302,7 +4314,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT Assert(sc->u.off >= prev_sc_opl); U64 fill_size = sc->u.off - prev_sc_opl; MemorySet(image_data.str + sect->foff + prev_sc_opl, fill_byte, fill_size); - prev_sc_opl = sc->u.off + sc->u.size; + prev_sc_opl = sc->u.off + lnk_size_from_section_contribution(sc); // copy contrib contents { @@ -4583,8 +4595,8 @@ lnk_build_rad_map(Arena *arena, String8 image_data, U64 thread_count, U64 objs_c U64 file_off = image_section_table[sc->u.sect_idx]->foff + sc->u.off; U64 virt_off = image_section_table[sc->u.sect_idx]->voff + sc->u.off; - U64 virt_size = sc->u.size; - U64 file_size = sc->u.size; + U64 virt_size = lnk_size_from_section_contribution(sc); + U64 file_size = lnk_size_from_section_contribution(sc); String8 sc_data = str8_substr(image_data, rng_1u64(file_off, file_off + virt_size)); U128 sc_hash = {0}; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index b07b4001..07ea2b00 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -100,6 +100,16 @@ lnk_section_array_from_list(Arena *arena, LNK_SectionList list) return result; } +internal U64 +lnk_size_from_section_contribution(LNK_SectionContrib *sc) +{ + U64 size = 0; + for (String8Node *n = sc->data_list; n != 0; n = n->next) { + size += n->string.size; + } + return size; +} + internal U64 lnk_voff_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc) { @@ -120,7 +130,7 @@ internal U64 lnk_fopl_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc) { U64 foff = lnk_foff_from_section_contrib(image_section_table, sc); - return foff + sc->u.size; + return foff + lnk_size_from_section_contribution(sc); } internal LNK_SectionContrib * @@ -150,7 +160,7 @@ lnk_get_section_contrib_size(LNK_Section *sect) { LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect); LNK_SectionContrib *last_sc = lnk_get_last_section_contrib(sect); - U64 size = (last_sc->u.off - first_sc->u.off) + last_sc->u.size; + U64 size = (last_sc->u.off - first_sc->u.off) + lnk_size_from_section_contribution(last_sc); return size; } @@ -468,16 +478,11 @@ lnk_finalize_section_layout(LNK_SectionTable *sectab, LNK_Section *sect, U64 fil U64 sc_off = cursor; // compute contrib size - U64 sc_size = 0; - for (String8Node *data_n = sc->data_list; data_n != 0; data_n = data_n->next) { - sc_size += data_n->string.size; - } - + U64 sc_size = lnk_size_from_section_contribution(sc); cursor += sc_size; // assign offset and size - sc->u.off = sc_off; - sc->u.size = sc_size; + sc->u.off = sc_off; } } ProfEnd(); diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index 6361d01d..14b2bbf8 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -5,26 +5,22 @@ typedef struct LNK_SectionContrib { + String8Node node; // most contributions require at least one data node, so preallocate it here + String8Node *data_list; // list of data nodes that contribute to final section union { + // used before section layout is finalized struct { - U32 obj_idx; - U32 obj_sect_idx; + U32 obj_idx; // index of the input obj that contributes to the image section + U32 obj_sect_idx; // index into contributing obj's section table }; + // used after section layout is finalized struct { - U32 off; - U32 size; - U16 sect_idx; + U32 off; // contribution offset within the image section + U16 sect_idx; // section index in the image + U8 unused[2]; }; } u; - - U16 align; - - union { - String8Node *data_list; - U64 bss_size; - }; - - String8Node node; + U16 align; // alignment of the contribution in the image } LNK_SectionContrib; typedef struct LNK_CommonBlockContrib @@ -119,6 +115,7 @@ internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionL //////////////////////////////// +internal U64 lnk_size_from_section_contrib(LNK_SectionContrib *sc); internal U64 lnk_voff_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc); internal U64 lnk_foff_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc); internal U64 lnk_fopl_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc); diff --git a/src/torture/torture.c b/src/torture/torture.c index ff175d87..8a63e196 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -1629,6 +1629,7 @@ t_common_block(void) COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_common(obj_writer, str8_lit("A"), 3); COFF_ObjSection *data_sect = t_push_data_section(obj_writer, str8_array_fixed(a_data)); data_sect->flags |= COFF_SectionFlag_Align1Bytes; + coff_obj_writer_push_section(obj_writer, str8_lit(".bss"), PE_BSS_SECTION_FLAGS, str8(0, 1)); // shift common block's initial position coff_obj_writer_section_push_reloc(obj_writer, data_sect, 0, symbol, COFF_Reloc_X64_Addr32); String8 a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); @@ -1672,14 +1673,14 @@ t_common_block(void) if (data_sect == 0) { goto exit; } // blocks must be sorted in descending order to reduce alignment padding - if (comm_sect->vsize != 0xB) { goto exit; } + if (comm_sect->vsize != 0x13) { goto exit; } // ensure linker correctly patched addresses for symbols pointing into common block String8 data = str8_substr(exe, rng_1u64(data_sect->foff, data_sect->foff + data_sect->fsize)); U32 *a_addr = (U32 *)data.str; U64 *b_addr = (U64 *)(data.str + sizeof(a_data)); - if (*a_addr != (pe.image_base + comm_sect->voff + 0x8)) { goto exit; } - if (*b_addr != (pe.image_base + comm_sect->voff + 0x0)) { goto exit; } + if (*a_addr != (pe.image_base + comm_sect->voff + 0x10)) { goto exit; } + if (*b_addr != (pe.image_base + comm_sect->voff + 0x8)) { goto exit; } result = T_Result_Pass; exit:;