factor out section sort index into contribution chunk and simplify

contribution sorting
This commit is contained in:
Nikita Smith
2025-06-06 19:50:13 -07:00
committed by Ryan Fleury
parent f64265aafe
commit 15836572f4
5 changed files with 237 additions and 233 deletions
+174 -213
View File
@@ -2284,51 +2284,57 @@ THREAD_POOL_TASK_FUNC(lnk_remove_associative_sections_task)
internal
THREAD_POOL_TASK_FUNC(lnk_gather_section_definitions_task)
{
LNK_BuildImageTask *task = raw_task;
Temp scratch = scratch_begin(&arena, 1);
LNK_BuildImageTask *task = raw_task;
U64 obj_idx = task_id;
HashTable *sect_defn_ht = task->u.gather_sects.defns[worker_id];
LNK_Obj *obj = task->objs[task_id];
LNK_Obj *obj = task->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);
for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *sect_header = &section_table[sect_idx];
// remove section
if (sect_header->flags & COFF_SectionFlag_LnkRemove) {
continue;
if (~sect_header->flags & COFF_SectionFlag_LnkRemove) {
Temp temp = temp_begin(scratch.arena);
// was section defined?
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_SectionDefinition *sect_defn = 0;
hash_table_search_string_raw(sect_defn_ht, sect_name_with_flags, &sect_defn);
// push new section definition
if (sect_defn == 0) {
sect_defn = push_array(arena, LNK_SectionDefinition, 1);
sect_defn->name = sect_name;
sect_defn->obj = obj;
sect_defn->obj_sect_idx = sect_idx;
sect_defn->flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
sect_name_with_flags = push_str8_copy(arena, sect_name_with_flags);
hash_table_push_string_raw(arena, sect_defn_ht, sect_name_with_flags, sect_defn);
}
// acc contrib count
sect_defn->contribs_count += 1;
temp_end(temp);
}
// parse section name
String8 full_sect_name = coff_name_from_section_header(string_table, sect_header);
String8 sect_name, sect_sort_idx;
coff_parse_section_name(full_sect_name, &sect_name, &sect_sort_idx);
// was section defined?
COFF_SectionFlags sect_flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
String8 sect_name_with_flags = lnk_make_name_with_flags(arena, sect_name, sect_flags);
LNK_SectionDefinition *sect_defn = 0;
hash_table_search_string_raw(sect_defn_ht, sect_name_with_flags, &sect_defn);
// create section definition
if (sect_defn == 0) {
sect_defn = push_array(arena, LNK_SectionDefinition, 1);
sect_defn->name = sect_name;
sect_defn->flags = sect_flags;
sect_defn->obj = obj;
sect_defn->obj_sect_idx = sect_idx;
hash_table_push_string_raw(arena, sect_defn_ht, sect_name_with_flags, sect_defn);
}
// acc contrib count
sect_defn->contribs_count += 1;
}
scratch_end(scratch);
}
internal
THREAD_POOL_TASK_FUNC(lnk_gather_section_contribs_task)
{
LNK_BuildImageTask *task = raw_task;
U64 obj_idx = task_id;
Temp scratch = scratch_begin(&arena, 1);
LNK_BuildImageTask *task = raw_task;
U64 obj_idx = task_id;
LNK_Obj *obj = task->objs[obj_idx];
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
@@ -2336,51 +2342,34 @@ 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;
COFF_SectionHeader *sect_header = &section_table[sect_idx];
if (~sect_header->flags & COFF_SectionFlag_LnkRemove) {
Temp temp = temp_begin(scratch.arena);
if (sect_header->flags & COFF_SectionFlag_LnkRemove) {
continue;
}
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);
// parse section name
String8 full_sect_name = coff_name_from_section_header(string_table, sect_header);
String8 sect_name, sect_sort_idx;
coff_parse_section_name(full_sect_name, &sect_name, &sect_sort_idx);
// search for section to contribute
COFF_SectionFlags flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
LNK_Section *sect = lnk_section_table_search(task->sectab, sect_name, flags);
LNK_SectionContrib *sc;
if (sect) {
// extract align
U16 sc_align = coff_align_size_from_section_flags(sect_header->flags);
if (sc_align == 0) {
sc_align = task->default_align;
if (sc_chunk) {
U16 sc_align = coff_align_size_from_section_flags(sect_header->flags);
sc = lnk_section_contrib_chunk_push_atomic(sc_chunk, 1);
sc->node.next = 0;
sc->node.string = str8_substr(obj->data, rng_1u64(sect_header->foff, sect_header->foff + sect_header->fsize));
sc->data_list = &sc->node;
sc->align = sc_align == 0 ? task->default_align : sc_align;
sc->u.obj_idx = obj_idx;
sc->u.obj_sect_idx = sect_idx;
}
// extract section bytes
String8 sect_data = str8_substr(obj->data, rng_1u64(sect_header->foff, sect_header->foff + sect_header->fsize));
// fill out contrib
sc = lnk_section_contrib_chunk_push_atomic(sect->contribs.first, 1);
sc->node.next = 0;
sc->node.string = sect_data;
sc->data_list = &sc->node;
sc->align = sc_align;
sc->u.obj_idx = obj_idx;
sc->u.obj_sect_idx = sect_idx;
sc->u.sort_idx_size = (U16)sect_sort_idx.size;
sc->u.sort_idx = sect_sort_idx.str;
} else {
// section was removed, fill slot with pointer to null contrib
sc = &g_null_sc;
temp_end(temp);
}
task->sect_map[obj_idx][sect_idx] = sc;
}
ProfEnd();
scratch_end(scratch);
}
internal
@@ -2410,43 +2399,10 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_task)
internal int
lnk_section_contrib_ptr_is_before(void *raw_a, void *raw_b)
{
// Grouped Sections (PE Format)
// "All contributions with the same object-section name are allocated contiguously in the image,
// and the blocks of contributions are sorted in lexical order by object-section name."
LNK_SectionContrib *a = *(LNK_SectionContrib **)raw_a;
LNK_SectionContrib *b = *(LNK_SectionContrib **)raw_b;
int cmp;
if (a->u.sort_idx_size <= 1 && b->u.sort_idx_size <= 1) {
if (a->u.sort_idx_size == b->u.sort_idx_size) {
cmp = u32_compar(&a->u.obj_idx, &b->u.obj_idx);
if (cmp == 0) {
cmp = u32_compar(&a->u.obj_sect_idx, &b->u.obj_sect_idx);
}
} else {
// place sections without sort postfix first
cmp = u16_compar(&a->u.sort_idx_size, &b->u.sort_idx_size);
}
} else {
// sort on section postfix
String8 a_sort_idx = str8(a->u.sort_idx, a->u.sort_idx_size);
String8 b_sort_idx = str8(b->u.sort_idx, b->u.sort_idx_size);
cmp = str8_compar_case_sensitive(&a_sort_idx, &b_sort_idx);
// sort on obj position on command line
if (cmp == 0) {
cmp = u32_compar(&a->u.obj_idx, &b->u.obj_idx);
// sort on section index
if (cmp == 0) {
cmp = u32_compar(&a->u.obj_sect_idx, &b->u.obj_sect_idx);
}
}
}
int is_before = cmp < 0;
return is_before;
LNK_SectionContrib **a = raw_a, **b = raw_b;
U64 input_idx_a = Compose64Bit((*a)->u.obj_idx, (*a)->u.obj_sect_idx);
U64 input_idx_b = Compose64Bit((*b)->u.obj_idx, (*b)->u.obj_sect_idx);
return u64_compar_is_before(&input_idx_a, &input_idx_b);
}
internal
@@ -2454,8 +2410,9 @@ THREAD_POOL_TASK_FUNC(lnk_sort_contribs_task)
{
LNK_BuildImageTask *task = raw_task;
LNK_SectionContribChunk *chunk = task->u.sort_contribs.chunks[task_id];
Assert(chunk->count == chunk->cap);
ProfBeginV("[%llu]", chunk->count);
radsort(chunk->v, chunk->count, lnk_section_contrib_ptr_is_before);
ProfEnd();
}
internal int
@@ -2992,15 +2949,10 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
internal int
lnk_section_definition_is_before(void *raw_a, void *raw_b)
{
LNK_SectionDefinition **a = raw_a;
LNK_SectionDefinition **b = raw_b;
int is_before;
if ((*a)->obj->input_idx == (*b)->obj->input_idx) {
is_before = (*a)->obj_sect_idx < (*b)->obj_sect_idx;
} else {
is_before = (*a)->obj->input_idx < (*b)->obj->input_idx;
}
return is_before;
LNK_SectionDefinition **a = raw_a, **b = raw_b;
U64 input_idx_a = Compose64Bit((*a)->obj->input_idx, (*a)->obj_sect_idx);
U64 input_idx_b = Compose64Bit((*b)->obj->input_idx, (*b)->obj_sect_idx);
return u64_compar_is_before(&input_idx_a, &input_idx_b);
}
internal void
@@ -3960,7 +3912,8 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
radsort(sect_defns, sect_defns_count, lnk_section_definition_is_before);
for (U64 defn_idx = 0; defn_idx < sect_defns_count; defn_idx += 1) {
String8 name_with_flags = lnk_make_name_with_flags(arena->v[0], sect_defns[defn_idx]->name, sect_defns[defn_idx]->flags);
LNK_SectionDefinition *defn = sect_defns[defn_idx];
String8 name_with_flags = lnk_make_name_with_flags(arena->v[0], defn->name, defn->flags);
LNK_SectionDefinition *main_defn = 0;
hash_table_search_string_raw(task.u.gather_sects.defns[0], name_with_flags, &main_defn);
if (main_defn == 0) {
@@ -3981,46 +3934,54 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
ProfEnd();
ProfBegin("Push Sections And Reserve Section Contrib Memory");
task.contribs_ht = hash_table_init(sectab->arena, sect_defns_count);
for (U64 defn_idx = 0; defn_idx < sect_defns_count; defn_idx += 1) {
LNK_SectionDefinition *sect_defn = sect_defns[defn_idx];
// parse section name
String8 sect_name, sort_idx;
coff_parse_section_name(sect_defn->name, &sect_name, &sort_idx);
// do not create definitions for sections that are removed from the image
{
B32 skip = 0;
for (String8Node *name_n = config->remove_sections.first; name_n != 0; name_n = name_n->next) {
if (str8_match(sect_defn->name, name_n->string, 0)) {
skip = 1;
break;
}
for (String8Node *name_n = config->remove_sections.first; name_n != 0 && !skip; name_n = name_n->next) {
skip = str8_match(sect_name, name_n->string, 0);
}
if (skip) { continue; }
}
// warn about conflicting section flags
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
LNK_Section *sect = &sect_n->data;
if (str8_match(sect->name, sect_defn->name, 0)) {
if (sect->flags != sect_defn->flags) {
LNK_Obj *obj = sect_defn->obj;
U32 sect_number = sect_defn->obj_sect_idx + 1;
COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, sect_number);
String8 sect_name = coff_name_from_section_header(str8_substr(obj->data, obj->header.string_table_range), sect_header);
String8 expected_flags_str = coff_string_from_section_flags(arena->v[0], sect->flags);
String8 current_flags_str = coff_string_from_section_flags(arena->v[0], sect_defn->flags);
lnk_error_obj(LNK_Warning_SectionFlagsConflict, sect_defn->obj, "detected section flags conflict in %S(No. %X); expected {%S} but got {%S}", sect_name, sect_number, expected_flags_str, current_flags_str);
}
if (str8_match(sect_n->data.name, sect_name, 0) && sect_n->data.flags != sect_defn->flags) {
LNK_Obj *obj = sect_defn->obj;
U32 sect_number = sect_defn->obj_sect_idx + 1;
COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, sect_number);
String8 sect_name = coff_name_from_section_header(str8_substr(obj->data, obj->header.string_table_range), sect_header);
String8 expected_flags_str = coff_string_from_section_flags(arena->v[0], sect_n->data.flags);
String8 current_flags_str = coff_string_from_section_flags(arena->v[0], sect_defn->flags);
lnk_error_obj(LNK_Warning_SectionFlagsConflict, sect_defn->obj, "detected section flags conflict in %S(No. %X); expected {%S} but got {%S}", sect_name, sect_number, expected_flags_str, current_flags_str);
}
}
ProfBeginV("Reserve Section Contrib Chunks [%S]", sect_defn->name);
LNK_Section *sect = lnk_section_table_search(sectab, sect_defn->name, sect_defn->flags);
if (sect == 0) {
sect = lnk_section_table_push(sectab, sect_defn->name, sect_defn->flags);
}
AssertAlways(sect->contribs.chunk_count == 0);
lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &sect->contribs, sect_defn->contribs_count);
ProfEnd();
{
ProfBeginV("Reserve Section Contrib Chunks [%S]", sect_defn->name);
LNK_Section *sect = lnk_section_table_search(sectab, sect_name, sect_defn->flags);
if (!sect) {
sect = lnk_section_table_push(sectab, sect_name, sect_defn->flags);
}
String8 defn_name_with_flags = lnk_make_name_with_flags(sectab->arena, sect_defn->name, sect_defn->flags);
LNK_SectionContribChunk *contrib_chunk = 0;
hash_table_search_string_raw(task.contribs_ht, defn_name_with_flags, &contrib_chunk);
if (!contrib_chunk) {
contrib_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &sect->contribs, sect_defn->contribs_count, sort_idx);
hash_table_push_string_raw(sectab->arena, task.contribs_ht, defn_name_with_flags, contrib_chunk);
}
ProfEnd();
}
}
ProfEnd();
@@ -4039,81 +4000,33 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
tp_for_parallel(tp, 0, objs_count, lnk_gather_section_contribs_task, &task);
ProfEnd();
// ensure determinism by sorting section contribs in chunks by input index
{
ProfBegin("Sort Section Contribs");
U64 total_chunk_count = 0;
LNK_SectionContribChunk **chunks = 0;
{
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
total_chunk_count += sect_n->data.contribs.chunk_count;
}
U64 cursor = 0;
chunks = push_array(scratch.arena, LNK_SectionContribChunk *, total_chunk_count);
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
for (LNK_SectionContribChunk *chunk_n = sect_n->data.contribs.first; chunk_n != 0; chunk_n = chunk_n->next) {
chunks[cursor++] = chunk_n;
}
}
Assert(cursor == total_chunk_count);
}
task.u.sort_contribs.chunks = chunks;
tp_for_parallel(tp, 0, total_chunk_count, lnk_sort_contribs_task, &task);
ProfEnd();
}
ProfBegin("Set COMDAT Leaders");
tp_for_parallel(tp, 0, objs_count, lnk_set_comdat_leaders_task, &task);
ProfEnd();
// finalize sections layouts
{
ProfBegin("Finalize Sections Layout");
// merge sections
if (config->flags & LNK_ConfigFlag_Merge) {
lnk_section_table_merge(sectab, config->merge_list);
}
ProfBegin("Sort Section Contribs");
{
U64 total_chunk_count = 0;
LNK_SectionContribChunk **chunks = 0;
{
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
total_chunk_count += sect_n->data.contribs.chunk_count;
}
U64 cursor = 0;
chunks = push_array(scratch.arena, LNK_SectionContribChunk *, total_chunk_count);
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
for (LNK_SectionContribChunk *chunk_n = sect_n->data.contribs.first; chunk_n != 0; chunk_n = chunk_n->next) {
chunks[cursor++] = chunk_n;
}
}
Assert(cursor == total_chunk_count);
}
task.u.sort_contribs.chunks = chunks;
tp_for_parallel(tp, 0, total_chunk_count, lnk_sort_contribs_task, &task);
}
ProfEnd();
// 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, &sect_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 = &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);
}
}
// assign section indices to sections
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
lnk_assign_section_index(&sect_n->data, sectab->next_sect_idx++);
}
// 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 = &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();
}
// build common block
//
// TODO: build common block in .bss and merge with .data
@@ -4188,6 +4101,55 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
ProfEnd();
}
// finalize sections layouts
{
ProfBegin("Finalize Sections Layout");
// 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, &sect_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 = &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);
}
}
// assign section indices to sections
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
lnk_assign_section_index(&sect_n->data, sectab->next_sect_idx++);
}
// 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 = &sect_n->data;
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);
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();
}
//
// patch symbol tables
//
@@ -4261,11 +4223,10 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
String8List base_relocs_data = lnk_build_base_relocs(tp, arena, config, objs_count, objs);
if (base_relocs_data.total_size) {
LNK_Section *reloc = lnk_section_table_push(sectab, str8_lit(".reloc"), PE_RELOC_SECTION_FLAGS);
LNK_SectionContribChunk *first_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &reloc->contribs, 1);
LNK_SectionContribChunk *first_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &reloc->contribs, 1, str8_zero());
LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(first_sc_chunk, 1);
sc->data_list = base_relocs_data.first;
sc->align = 1;
sc->u.sort_idx_size = 0;
sc->u.obj_idx = max_U32;
lnk_finalize_section_layout(sectab, reloc, config->file_align);
@@ -4293,7 +4254,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
String8List image_header_data = lnk_build_win32_header(scratch.arena, symtab, config, task.image_sects, AlignPow2(expected_image_header_size, config->file_align));
LNK_Section *image_header_sect = lnk_section_table_push(sectab, str8_lit(".rad_linker_image_header_section"), 0);
LNK_SectionContribChunk *image_header_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &image_header_sect->contribs, 1);
LNK_SectionContribChunk *image_header_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &image_header_sect->contribs, 1, str8_zero());
LNK_SectionContrib *image_header_sc = lnk_section_contrib_chunk_push(image_header_sc_chunk, 1);
image_header_sc->align = config->file_align;
+1
View File
@@ -58,6 +58,7 @@ typedef struct
U64 objs_count;
LNK_Obj **objs;
LNK_SectionContrib ***sect_map;
HashTable *contribs_ht;
LNK_SectionArray image_sects;
union {
struct {
+1 -1
View File
@@ -10,7 +10,7 @@ typedef struct LNK_Obj
String8 data;
String8 path;
String8 lib_path;
U64 input_idx;
U32 input_idx;
COFF_FileHeaderInfo header;
U32 *comdats;
} LNK_Obj;
+47 -5
View File
@@ -50,13 +50,14 @@ lnk_section_contrib_chunk_push_atomic(LNK_SectionContribChunk *chunk, U64 count)
}
internal LNK_SectionContribChunk *
lnk_section_contrib_chunk_list_push_chunk(Arena *arena, LNK_SectionContribChunkList *list, U64 cap)
lnk_section_contrib_chunk_list_push_chunk(Arena *arena, LNK_SectionContribChunkList *list, U64 cap, String8 sort_idx)
{
LNK_SectionContribChunk *chunk = push_array(arena, LNK_SectionContribChunk, 1);
chunk->count = 0;
chunk->cap = cap;
chunk->v = push_array(arena, LNK_SectionContrib *, cap);
chunk->v2 = push_array(arena, LNK_SectionContrib, cap);
chunk->count = 0;
chunk->cap = cap;
chunk->v = push_array(arena, LNK_SectionContrib *, cap);
chunk->v2 = push_array(arena, LNK_SectionContrib, cap);
chunk->sort_idx = sort_idx;
for (U64 i = 0; i < cap; i += 1) { chunk->v[i] = &chunk->v2[i]; }
SLLQueuePush(list->first, list->last, chunk);
list->chunk_count += 1;
@@ -75,6 +76,17 @@ lnk_section_contrib_chunk_list_concat_in_place(LNK_SectionContribChunkList *list
}
}
internal LNK_SectionContribChunk **
lnk_array_from_section_contrib_chunk_list(Arena *arena, LNK_SectionContribChunkList list)
{
LNK_SectionContribChunk **result = push_array(arena, LNK_SectionContribChunk *, list.chunk_count);
U64 i = 0;
for (LNK_SectionContribChunk *chunk = list.first; chunk != 0; chunk = chunk->next, i += 1) {
result[i] = chunk;
}
return result;
}
internal LNK_SectionArray
lnk_section_array_from_list(Arena *arena, LNK_SectionList list)
{
@@ -415,9 +427,36 @@ lnk_section_table_get_output_sections(Arena *arena, LNK_SectionTable *sectab)
return result;
}
internal int
lnk_section_contrib_chunk_is_before(void *raw_a, void *raw_b)
{
LNK_SectionContribChunk **a = raw_a, **b = raw_b;
return str8_is_before_case_sensitive(&(*a)->sort_idx, &(*b)->sort_idx);
}
internal void
lnk_finalize_section_layout(LNK_SectionTable *sectab, LNK_Section *sect, U64 file_align)
{
Temp scratch = scratch_begin(0,0);
ProfBegin("Sort Section Contribs");
{
// Grouped Sections (PE Format)
// "All contributions with the same object-section name are allocated contiguously in the image,
// and the blocks of contributions are sorted in lexical order by object-section name."
LNK_SectionContribChunk **chunks = lnk_array_from_section_contrib_chunk_list(scratch.arena, sect->contribs);
radsort(chunks, sect->contribs.chunk_count, lnk_section_contrib_chunk_is_before);
// repopulate chunk list in sorted order
sect->contribs.first = 0;
sect->contribs.last = 0;
for (U64 chunk_idx = 0; chunk_idx < sect->contribs.chunk_count; chunk_idx += 1) {
SLLQueuePush(sect->contribs.first, sect->contribs.last, chunks[chunk_idx]);
}
}
ProfEnd();
ProfBegin("Layout Contribs");
U64 cursor = 0;
for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
@@ -441,11 +480,14 @@ lnk_finalize_section_layout(LNK_SectionTable *sectab, LNK_Section *sect, U64 fil
sc->u.size = sc_size;
}
}
ProfEnd();
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
sect->fsize = AlignPow2(cursor, file_align);
}
sect->vsize = cursor;
scratch_end(scratch);
}
+14 -14
View File
@@ -5,27 +5,26 @@
typedef struct LNK_SectionContrib
{
union {
struct {
U32 obj_idx;
U32 obj_sect_idx;
};
struct {
U32 off;
U32 size;
U16 sect_idx;
};
} u;
U16 align;
union {
String8Node *data_list;
U64 bss_size;
};
String8Node node;
union {
struct {
U16 sort_idx_size;
U32 obj_idx;
U32 obj_sect_idx;
U8 *sort_idx;
};
struct {
U16 sect_idx;
U32 off;
U32 size;
};
} u;
String8Node node;
} LNK_SectionContrib;
typedef struct LNK_CommonBlockContrib
@@ -42,6 +41,7 @@ typedef struct LNK_SectionContribChunk
struct LNK_SectionContribChunk *next;
U64 count;
U64 cap;
String8 sort_idx;
LNK_SectionContrib **v;
LNK_SectionContrib *v2;
} LNK_SectionContribChunk;