create section contribution for common block

This commit is contained in:
Nikita Smith
2025-06-25 10:53:24 -07:00
committed by Ryan Fleury
parent 95bea877ab
commit a484906cf9
4 changed files with 59 additions and 44 deletions
+30 -18
View File
@@ -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) { if (~sect_header->flags & COFF_SectionFlag_LnkRemove) {
LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx];
LNK_Section *sect = task->image_sects.v[sc->u.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; 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_SectionContrib *sc = task->sect_map[obj_idx][sect_idx];
LNK_Section *sect = task->image_sects.v[sc->u.sect_idx]; LNK_Section *sect = task->image_sects.v[sc->u.sect_idx];
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { 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; 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(".rdata"), PE_RDATA_SECTION_FLAGS);
lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_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_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}; LNK_BuildImageTask task = {0};
task.symtab = symtab; 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 // TODO: build common block in .bss and merge with .data
U64 common_block_contribs_count; U64 common_block_contribs_count;
LNK_CommonBlockContrib *common_block_contribs; LNK_CommonBlockContrib *common_block_contribs;
LNK_Section *common_block_sect;
{ {
ProfBegin("Build Common Block"); ProfBegin("Build Common Block");
@@ -4078,23 +4078,35 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
ProfEnd(); ProfEnd();
if (common_block_contribs_count) { 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 // sort common blocks from for tighter packing
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
radsort(common_block_contribs, common_block_contribs_count, lnk_common_block_contrib_is_before); 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) { for (U64 contrib_idx = 0; contrib_idx < common_block_contribs_count; contrib_idx += 1) {
LNK_CommonBlockContrib *contrib = &common_block_contribs[contrib_idx]; LNK_CommonBlockContrib *contrib = &common_block_contribs[contrib_idx];
U32 size = contrib->u.size; U32 size = contrib->u.size;
U32 align = Min(32, u64_up_to_pow2(size)); // link.exe caps align at 32 bytes 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); common_block_cursor = AlignPow2(common_block_cursor, align);
contrib->u.offset = common_block_sect->vsize; contrib->u.offset = common_block_cursor;
common_block_sect->vsize += size; 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(); 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_Section *final_sect = lnk_finalized_section_from_id(sectab, sect->merge_id);
LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect); LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect);
LNK_SectionContrib *last_sc = lnk_get_last_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->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->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; 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->align = config->file_align;
image_header_sc->data_list = image_header_data.first; 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); 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); Assert(sc->u.off >= prev_sc_opl);
U64 fill_size = 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); 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 // 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 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_off = image_section_table[sc->u.sect_idx]->voff + sc->u.off;
U64 virt_size = sc->u.size; U64 virt_size = lnk_size_from_section_contribution(sc);
U64 file_size = sc->u.size; U64 file_size = lnk_size_from_section_contribution(sc);
String8 sc_data = str8_substr(image_data, rng_1u64(file_off, file_off + virt_size)); String8 sc_data = str8_substr(image_data, rng_1u64(file_off, file_off + virt_size));
U128 sc_hash = {0}; U128 sc_hash = {0};
+14 -9
View File
@@ -100,6 +100,16 @@ lnk_section_array_from_list(Arena *arena, LNK_SectionList list)
return result; 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 internal U64
lnk_voff_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc) 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) lnk_fopl_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc)
{ {
U64 foff = lnk_foff_from_section_contrib(image_section_table, 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 * 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 *first_sc = lnk_get_first_section_contrib(sect);
LNK_SectionContrib *last_sc = lnk_get_last_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; return size;
} }
@@ -468,16 +478,11 @@ lnk_finalize_section_layout(LNK_SectionTable *sectab, LNK_Section *sect, U64 fil
U64 sc_off = cursor; U64 sc_off = cursor;
// compute contrib size // compute contrib size
U64 sc_size = 0; U64 sc_size = lnk_size_from_section_contribution(sc);
for (String8Node *data_n = sc->data_list; data_n != 0; data_n = data_n->next) {
sc_size += data_n->string.size;
}
cursor += sc_size; cursor += sc_size;
// assign offset and size // assign offset and size
sc->u.off = sc_off; sc->u.off = sc_off;
sc->u.size = sc_size;
} }
} }
ProfEnd(); ProfEnd();
+11 -14
View File
@@ -5,26 +5,22 @@
typedef struct LNK_SectionContrib 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 { union {
// used before section layout is finalized
struct { struct {
U32 obj_idx; U32 obj_idx; // index of the input obj that contributes to the image section
U32 obj_sect_idx; U32 obj_sect_idx; // index into contributing obj's section table
}; };
// used after section layout is finalized
struct { struct {
U32 off; U32 off; // contribution offset within the image section
U32 size; U16 sect_idx; // section index in the image
U16 sect_idx; U8 unused[2];
}; };
} u; } u;
U16 align; // alignment of the contribution in the image
U16 align;
union {
String8Node *data_list;
U64 bss_size;
};
String8Node node;
} LNK_SectionContrib; } LNK_SectionContrib;
typedef struct LNK_CommonBlockContrib 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_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_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); internal U64 lnk_fopl_from_section_contrib(COFF_SectionHeader **image_section_table, LNK_SectionContrib *sc);
+4 -3
View File
@@ -1629,6 +1629,7 @@ t_common_block(void)
COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_common(obj_writer, str8_lit("A"), 3); 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)); COFF_ObjSection *data_sect = t_push_data_section(obj_writer, str8_array_fixed(a_data));
data_sect->flags |= COFF_SectionFlag_Align1Bytes; 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); 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); String8 a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
coff_obj_writer_release(&obj_writer); coff_obj_writer_release(&obj_writer);
@@ -1672,14 +1673,14 @@ t_common_block(void)
if (data_sect == 0) { goto exit; } if (data_sect == 0) { goto exit; }
// blocks must be sorted in descending order to reduce alignment padding // 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 // 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)); String8 data = str8_substr(exe, rng_1u64(data_sect->foff, data_sect->foff + data_sect->fsize));
U32 *a_addr = (U32 *)data.str; U32 *a_addr = (U32 *)data.str;
U64 *b_addr = (U64 *)(data.str + sizeof(a_data)); U64 *b_addr = (U64 *)(data.str + sizeof(a_data));
if (*a_addr != (pe.image_base + comm_sect->voff + 0x8)) { goto exit; } if (*a_addr != (pe.image_base + comm_sect->voff + 0x10)) { goto exit; }
if (*b_addr != (pe.image_base + comm_sect->voff + 0x0)) { goto exit; } if (*b_addr != (pe.image_base + comm_sect->voff + 0x8)) { goto exit; }
result = T_Result_Pass; result = T_Result_Pass;
exit:; exit:;