create section layout without copying chunk data and perform chunk data

copy in parallel given layout
This commit is contained in:
Nikita Smith
2024-11-15 16:14:00 -08:00
parent 2562d04fbf
commit b631d431fa
10 changed files with 490 additions and 457 deletions
+2 -1
View File
@@ -16,8 +16,9 @@
</Type> </Type>
<Type Name="LNK_SymbolList"> <Type Name="LNK_SymbolList">
<AlternativeType Name="CV_SymbolList"/>
<AlternativeType Name="LNK_SectionList"/> <AlternativeType Name="LNK_SectionList"/>
<AlternativeType Name="LNK_ChunkList"/>
<AlternativeType Name="CV_SymbolList"/>
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString> <DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
<Expand> <Expand>
<LinkedListItems> <LinkedListItems>
+157 -180
View File
@@ -943,11 +943,9 @@ lnk_make_res_obj(TP_Context *tp,
lnk_section_table_assign_indices(st); lnk_section_table_assign_indices(st);
lnk_section_table_build_data(tp, st, machine); lnk_section_table_build_data(tp, st, machine);
lnk_section_table_assign_file_offsets(st); lnk_section_table_assign_file_offsets(st);
String8 res_obj = lnk_section_table_serialize(tp, arena, st, machine);
sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st);
lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, 0); lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, res_obj, 0);
String8 res_obj = lnk_section_table_serialize(arena, st);
lnk_section_table_release(&st); lnk_section_table_release(&st);
arena_release(temp_tp_arena->v[0]); arena_release(temp_tp_arena->v[0]);
@@ -1161,9 +1159,9 @@ lnk_make_linker_coff_obj(TP_Context *tp,
lnk_section_table_assign_indices(st); lnk_section_table_assign_indices(st);
lnk_section_table_build_data(tp, st, machine); lnk_section_table_build_data(tp, st, machine);
lnk_section_table_assign_file_offsets(st); lnk_section_table_assign_file_offsets(st);
String8 coff_data = lnk_section_table_serialize(tp, arena, st, machine);
LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st);
lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, 0); lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, coff_data, 0);
String8 coff_data = lnk_section_table_serialize(arena, st);
lnk_section_table_release(&st); lnk_section_table_release(&st);
@@ -1210,10 +1208,8 @@ lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path)
internal B32 internal B32
lnk_is_lib_loaded(HashTable *default_lib_ht, HashTable *loaded_lib_ht, LNK_InputSourceType input_source, String8 path) lnk_is_lib_loaded(HashTable *default_lib_ht, HashTable *loaded_lib_ht, LNK_InputSourceType input_source, String8 path)
{ {
// when /defaultlib:path is comes from command line or obj directive // when /defaultlib:path comes from command line or obj directive check against lib name
// check against lib name if (input_source == LNK_InputSource_Default || input_source == LNK_InputSource_Obj) {
if (input_source == LNK_InputSource_Default ||
input_source == LNK_InputSource_Obj) {
String8 lib_name = str8_skip_last_slash(path); String8 lib_name = str8_skip_last_slash(path);
if (hash_table_search_path(default_lib_ht, lib_name)) { if (hash_table_search_path(default_lib_ht, lib_name)) {
return 1; return 1;
@@ -1378,9 +1374,9 @@ lnk_push_pe_debug_data_directory(LNK_Section *sect,
PE_DebugDirectory *dir = push_array(sect->arena, PE_DebugDirectory, 1); PE_DebugDirectory *dir = push_array(sect->arena, PE_DebugDirectory, 1);
dir->time_stamp = time_stamp; dir->time_stamp = time_stamp;
dir->type = type; dir->type = type;
//dir->voff = 0; // relocated through 'symbol' //dir->voff = 0; // relocated through 'data_symbol'
//dir->foff = 0; // relocated through 'symbol' //dir->foff = 0; // relocated through 'data_symbol'
//dir->size = 0; // relocated through 'symbol' //dir->size = 0; // relocated through 'data_symbol'
// push chunk // push chunk
LNK_Chunk *dir_entry_chunk = lnk_section_push_chunk_data(sect, dir_array_chunk, str8_struct(dir), str8_zero()); LNK_Chunk *dir_entry_chunk = lnk_section_push_chunk_data(sect, dir_array_chunk, str8_struct(dir), str8_zero());
@@ -1434,7 +1430,8 @@ lnk_build_debug_rdi(LNK_SectionTable *st,
// push chunks // push chunks
String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path); String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path);
LNK_Chunk *debug_rdi_chunk = lnk_section_push_chunk_data(rdi_sect, rdi_sect->root, debug_rdi, str8_zero()); lnk_chunk_set_debugf(rdi_sect->arena, debug_rdi, LNK_CV_HEADER_RDI_SYMBOL_NAME); LNK_Chunk *debug_rdi_chunk = lnk_section_push_chunk_data(rdi_sect, rdi_sect->root, debug_rdi, str8_zero());
lnk_chunk_set_debugf(rdi_sect->arena, debug_rdi_chunk, LNK_CV_HEADER_RDI_SYMBOL_NAME);
// push symbols // push symbols
LNK_Symbol *debug_rdi_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_RDI_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, 0, 0, 0); LNK_Symbol *debug_rdi_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_RDI_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, 0, 0, 0);
@@ -1759,13 +1756,6 @@ lnk_emit_base_reloc_info(Arena *arena,
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
U64 page_voff = AlignDownPow2(reloc_voff, page_size); U64 page_voff = AlignDownPow2(reloc_voff, page_size);
if (str8_match(reloc->symbol->name, str8_lit("_mi_heap_empty"), 0)) {
int x = 0;
}
if (page_voff == 0x21C7000) {
int x = 0;
}
LNK_BaseRelocPageNode *page; LNK_BaseRelocPageNode *page;
{ {
KeyValuePair *is_page_present = hash_table_search_u64(page_ht, page_voff); KeyValuePair *is_page_present = hash_table_search_u64(page_ht, page_voff);
@@ -2629,21 +2619,21 @@ lnk_apply_reloc(U64 base_addr,
LNK_DefinedSymbol *defined_symbol = &symbol->u.defined; LNK_DefinedSymbol *defined_symbol = &symbol->u.defined;
switch (defined_symbol->value_type) { switch (defined_symbol->value_type) {
case LNK_DefinedSymbolValue_Null: break; case LNK_DefinedSymbolValue_Null: break;
case LNK_DefinedSymbolValue_Chunk: { case LNK_DefinedSymbolValue_Chunk: {
symbol_isect = lnk_isect_from_symbol(sect_id_map, symbol); symbol_isect = lnk_isect_from_symbol(sect_id_map, symbol);
symbol_vsize = lnk_virt_size_from_symbol(sect_id_map, symbol); symbol_vsize = lnk_virt_size_from_symbol(sect_id_map, symbol);
symbol_fsize = lnk_file_size_from_symbol(sect_id_map, symbol); symbol_fsize = lnk_file_size_from_symbol(sect_id_map, symbol);
symbol_off = lnk_sect_off_from_symbol(sect_id_map, symbol); symbol_off = lnk_sect_off_from_symbol(sect_id_map, symbol);
symbol_voff = lnk_virt_off_from_symbol(sect_id_map, symbol); symbol_voff = lnk_virt_off_from_symbol(sect_id_map, symbol);
symbol_foff = lnk_file_off_from_symbol(sect_id_map, symbol); symbol_foff = lnk_file_off_from_symbol(sect_id_map, symbol);
} break; } break;
case LNK_DefinedSymbolValue_VA: { case LNK_DefinedSymbolValue_VA: {
symbol_voff = defined_symbol->u.va - base_addr; symbol_voff = defined_symbol->u.va - base_addr;
} break; } break;
} }
#if LNK_DEBUG #if BUILD_DEBUG
if (str8_match(str8_lit("__ImageBase"), symbol->name, 0)) { if (str8_match(str8_lit("__ImageBase"), symbol->name, 0)) {
Assert(symbol_isect == 0); Assert(symbol_isect == 0);
Assert(symbol_voff == 0); Assert(symbol_voff == 0);
@@ -2658,92 +2648,92 @@ lnk_apply_reloc(U64 base_addr,
S64 reloc_value = 0; S64 reloc_value = 0;
switch (reloc->type) { switch (reloc->type) {
case LNK_Reloc_NULL: /* ignore */ break; case LNK_Reloc_NULL: /* ignore */ break;
case LNK_Reloc_ADDR_16: { case LNK_Reloc_ADDR_16: {
reloc_value = safe_cast_u16(base_addr + symbol_voff); reloc_value = safe_cast_u16(base_addr + symbol_voff);
reloc_size = 2; reloc_size = 2;
} break; } break;
case LNK_Reloc_ADDR_32: { case LNK_Reloc_ADDR_32: {
reloc_value = safe_cast_u32(base_addr + symbol_voff); reloc_value = safe_cast_u32(base_addr + symbol_voff);
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_ADDR_64: { case LNK_Reloc_ADDR_64: {
reloc_value = base_addr + symbol_voff; reloc_value = base_addr + symbol_voff;
reloc_size = 8; reloc_size = 8;
} break; } break;
case LNK_Reloc_CHUNK_SIZE_FILE_16: { case LNK_Reloc_CHUNK_SIZE_FILE_16: {
reloc_value = safe_cast_u16(symbol_fsize); reloc_value = safe_cast_u16(symbol_fsize);
reloc_size = 2; reloc_size = 2;
} break; } break;
case LNK_Reloc_CHUNK_SIZE_FILE_32: { case LNK_Reloc_CHUNK_SIZE_FILE_32: {
reloc_value = symbol_fsize; reloc_value = symbol_fsize;
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_CHUNK_SIZE_VIRT_32: { case LNK_Reloc_CHUNK_SIZE_VIRT_32: {
reloc_value = symbol_vsize; reloc_value = symbol_vsize;
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_FILE_ALIGN_32: { case LNK_Reloc_FILE_ALIGN_32: {
reloc_value = 0; reloc_value = 0;
reloc_size = 4; reloc_size = 4;
reloc_align = file_align; reloc_align = file_align;
} break; } break;
case LNK_Reloc_FILE_OFF_32: { case LNK_Reloc_FILE_OFF_32: {
reloc_value = safe_cast_u32(symbol_foff); reloc_value = safe_cast_u32(symbol_foff);
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_FILE_OFF_64: { case LNK_Reloc_FILE_OFF_64: {
reloc_value = symbol_foff; reloc_value = symbol_foff;
reloc_size = 8; reloc_size = 8;
} break; } break;
case LNK_Reloc_REL32: { case LNK_Reloc_REL32: {
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 0)); reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 0));
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_REL32_1: { case LNK_Reloc_REL32_1: {
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 1)); reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 1));
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_REL32_2: { case LNK_Reloc_REL32_2: {
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 2)); reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 2));
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_REL32_3: { case LNK_Reloc_REL32_3: {
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 3)); reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 3));
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_REL32_4: { case LNK_Reloc_REL32_4: {
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 4)); reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 4));
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_REL32_5: { case LNK_Reloc_REL32_5: {
U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc);
reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 5)); reloc_value = safe_cast_s32((S64)(symbol_voff - reloc_voff) - (4 + 5));
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_SECT_REL: { case LNK_Reloc_SECT_REL: {
reloc_value = safe_cast_u32(symbol_off); reloc_value = safe_cast_u32(symbol_off);
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_SECT_IDX: { case LNK_Reloc_SECT_IDX: {
reloc_value = safe_cast_u32(symbol_isect); reloc_value = safe_cast_u32(symbol_isect);
reloc_size = 4; reloc_size = 4;
} break; } break;
case LNK_Reloc_VIRT_ALIGN_32: { case LNK_Reloc_VIRT_ALIGN_32: {
reloc_value = 0; reloc_value = 0;
reloc_size = 4; reloc_size = 4;
reloc_align = virt_align; reloc_align = virt_align;
} break; } break;
case LNK_Reloc_VIRT_OFF_32: { case LNK_Reloc_VIRT_OFF_32: {
reloc_value = safe_cast_u32(symbol_voff); reloc_value = safe_cast_u32(symbol_voff);
reloc_size = 4; reloc_size = 4;
} break; } break;
default: NotImplemented; default: NotImplemented;
} }
// read addend // read addend
@@ -2763,6 +2753,7 @@ THREAD_POOL_TASK_FUNC(lnk_section_reloc_patcher)
{ {
LNK_SectionRelocPatcher *task = raw_task; LNK_SectionRelocPatcher *task = raw_task;
String8 image_data = task->image_data;
LNK_SymbolTable *symtab = task->symtab; LNK_SymbolTable *symtab = task->symtab;
LNK_SectionTable *st = task->st; LNK_SectionTable *st = task->st;
LNK_Section **sect_id_map = task->sect_id_map; LNK_Section **sect_id_map = task->sect_id_map;
@@ -2772,34 +2763,20 @@ THREAD_POOL_TASK_FUNC(lnk_section_reloc_patcher)
for (U64 sect_idx = range.min; sect_idx < range.max; sect_idx += 1) { for (U64 sect_idx = range.min; sect_idx < range.max; sect_idx += 1) {
LNK_Section *sect = task->sect_arr[sect_idx]; LNK_Section *sect = task->sect_arr[sect_idx];
if (sect->has_layout) { for (LNK_Reloc *reloc = sect->reloc_list.first; reloc != 0; reloc = reloc->next) {
for (LNK_Reloc *reloc = sect->reloc_list.first; reloc != 0; reloc = reloc->next) { LNK_Chunk *chunk = reloc->chunk;
LNK_Chunk *chunk = reloc->chunk; if (lnk_chunk_is_discarded(chunk)) {
if (lnk_chunk_is_discarded(chunk)) { continue;
continue;
}
String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, chunk->ref);
lnk_apply_reloc(base_addr, st->sect_align, st->file_align, sect_id_map, symtab, chunk_data, reloc);
int bad_vs = 0; (void)bad_vs;
}
} else {
for (LNK_Reloc *reloc = sect->reloc_list.first; reloc != 0; reloc = reloc->next) {
LNK_Chunk *chunk = reloc->chunk;
if (lnk_chunk_is_discarded(chunk)) {
continue;
}
if (chunk->type != LNK_Chunk_Leaf) {
continue;
}
lnk_apply_reloc(base_addr, st->sect_align, st->file_align, sect_id_map, symtab, chunk->u.leaf, reloc);
int bad_vs = 0; (void)bad_vs;
} }
String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, chunk->ref);
lnk_apply_reloc(base_addr, st->sect_align, st->file_align, sect_id_map, symtab, chunk_data, reloc);
int bad_vs = 0; (void)bad_vs;
} }
} }
} }
internal void internal void
lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, U64 base_addr) lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
@@ -2807,6 +2784,7 @@ lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTabl
LNK_SectionPtrArray sect_arr = lnk_section_ptr_array_from_list(scratch.arena, st->list); LNK_SectionPtrArray sect_arr = lnk_section_ptr_array_from_list(scratch.arena, st->list);
LNK_SectionRelocPatcher task = {0}; LNK_SectionRelocPatcher task = {0};
task.image_data = image_data;
task.symtab = symtab; task.symtab = symtab;
task.st = st; task.st = st;
task.sect_id_map = sect_id_map; task.sect_id_map = sect_id_map;
@@ -2822,8 +2800,10 @@ lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTabl
internal internal
THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
{ {
LNK_ObjRelocPatcher *task = raw_task; LNK_ObjRelocPatcher *task = raw_task;
LNK_Obj *obj = task->obj_arr[task_id]; String8 image_data = task->image_data;
LNK_Obj *obj = task->obj_arr[task_id];
LNK_Section **sect_id_map = task->sect_id_map;
for (U64 sect_idx = 0; sect_idx < obj->sect_count; sect_idx += 1) { for (U64 sect_idx = 0; sect_idx < obj->sect_count; sect_idx += 1) {
LNK_RelocList reloc_list = obj->sect_reloc_list_arr[sect_idx]; LNK_RelocList reloc_list = obj->sect_reloc_list_arr[sect_idx];
@@ -2831,18 +2811,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
if (lnk_chunk_is_discarded(reloc->chunk)) { if (lnk_chunk_is_discarded(reloc->chunk)) {
continue; continue;
} }
Assert(reloc->chunk->type == LNK_Chunk_Leaf); String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, reloc->chunk->ref);
String8 chunk_data;
{
LNK_Section *sect = lnk_sect_from_chunk_ref(task->sect_id_map, reloc->chunk->ref);
if (sect->has_layout) {
chunk_data = lnk_data_from_chunk_ref(task->sect_id_map, reloc->chunk->ref);
} else {
chunk_data = reloc->chunk->u.leaf;
}
}
lnk_apply_reloc(task->base_addr, task->st->sect_align, task->st->file_align, task->sect_id_map, task->symtab, chunk_data, reloc); lnk_apply_reloc(task->base_addr, task->st->sect_align, task->st->file_align, task->sect_id_map, task->symtab, chunk_data, reloc);
int bad_vs = 0; (void)bad_vs; int bad_vs = 0; (void)bad_vs;
} }
@@ -2850,12 +2819,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
} }
internal void internal void
lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, U64 base_addr) lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
LNK_ObjRelocPatcher task; LNK_ObjRelocPatcher task;
task.image_data = image_data;
task.symtab = symtab; task.symtab = symtab;
task.st = st; task.st = st;
task.sect_id_map = sect_id_map; task.sect_id_map = sect_id_map;
@@ -3652,6 +3622,9 @@ lnk_run(int argc, char **argv)
if (lnk_is_lib_disallowed(disallow_lib_ht, path)) { if (lnk_is_lib_disallowed(disallow_lib_ht, path)) {
continue; continue;
} }
if (lnk_is_lib_loaded(default_lib_ht, loaded_lib_ht, input_source, path)) { if (lnk_is_lib_loaded(default_lib_ht, loaded_lib_ht, input_source, path)) {
continue; continue;
} }
@@ -3943,47 +3916,50 @@ lnk_run(int argc, char **argv)
lnk_section_table_assign_virtual_offsets(st); lnk_section_table_assign_virtual_offsets(st);
lnk_section_table_assign_file_offsets(st); lnk_section_table_assign_file_offsets(st);
ProfBegin("Image Serialize");
image_data = lnk_section_table_serialize(tp, scratch.arena, st, config->machine);
Assert(image_data.size > 0);
ProfEnd();
// image layout is finalized, section id map is stable after this point // image layout is finalized, section id map is stable after this point
LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st);
ProfBegin("Patch Relocs"); ProfBegin("Patch Relocs");
U64 base_addr = lnk_get_base_addr(config); U64 base_addr = lnk_get_base_addr(config);
lnk_patch_relocs_obj(tp, obj_list, symtab, st, sect_id_map, base_addr); lnk_patch_relocs_obj(tp, obj_list, symtab, st, sect_id_map, image_data, base_addr);
lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, base_addr); lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, image_data, base_addr);
ProfEnd(); ProfEnd();
ProfBegin("Sort Exception Info"); ProfBegin("Sort Exception Info");
LNK_Symbol *pdata_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_PDATA_SYMBOL_NAME); LNK_Symbol *pdata_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_PDATA_SYMBOL_NAME);
String8 pdata = lnk_data_from_chunk_ref_no_pad(sect_id_map, pdata_symbol->u.defined.u.chunk->ref); if (pdata_symbol) {
switch (config->machine) { Assert(pdata_symbol->type == LNK_Symbol_DefinedExtern);
case COFF_MachineType_X86: String8 pdata = lnk_data_from_chunk_ref_no_pad(sect_id_map, image_data, pdata_symbol->u.defined.u.chunk->ref);
case COFF_MachineType_X64: { switch (config->machine) {
U64 count = pdata.size / sizeof(PE_IntelPdata); case COFF_MachineType_X86:
radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664); case COFF_MachineType_X64: {
} break; U64 count = pdata.size / sizeof(PE_IntelPdata);
case COFF_MachineType_ARM64: radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664);
case COFF_MachineType_ARM: { } break;
AssertAlways(!"TOOD: ARM"); case COFF_MachineType_ARM64:
} break; case COFF_MachineType_ARM: {
case COFF_MachineType_MIPSFPU: AssertAlways(!"TOOD: ARM");
case COFF_MachineType_MIPS16: } break;
case COFF_MachineType_MIPSFPU16: { case COFF_MachineType_MIPSFPU:
AssertAlways(!"TODO: MIPS"); case COFF_MachineType_MIPS16:
} break; case COFF_MachineType_MIPSFPU16: {
AssertAlways(!"TODO: MIPS");
} break;
}
} }
ProfEnd(); ProfEnd();
ProfEnd(); // :EndBuild ProfEnd(); // :EndBuild
ProfBegin("Image Serialize");
image_data = lnk_section_table_serialize(scratch.arena, st);
Assert(image_data.size > 0);
ProfEnd();
LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Main, LNK_TLS_SYMBOL_NAME); LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Main, LNK_TLS_SYMBOL_NAME);
if (tls_used_symbol) { if (tls_used_symbol) {
ProfBegin("Patch TLS Align"); ProfBegin("Patch TLS Align");
@@ -4129,6 +4105,7 @@ lnk_run(int argc, char **argv)
String8List pdb_data = lnk_build_pdb(tp, String8List pdb_data = lnk_build_pdb(tp,
tp_arena, tp_arena,
image_data,
config->guid, config->guid,
config->machine, config->machine,
config->time_stamp, config->time_stamp,
+4 -2
View File
@@ -199,6 +199,7 @@ typedef struct
typedef struct typedef struct
{ {
String8 image_data;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_SectionTable *st; LNK_SectionTable *st;
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
@@ -209,6 +210,7 @@ typedef struct
typedef struct typedef struct
{ {
String8 image_data;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_SectionTable *st; LNK_SectionTable *st;
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
@@ -284,8 +286,8 @@ internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_S
//////////////////////////////// ////////////////////////////////
// Relocs // Relocs
internal void lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, U64 base_addr); internal void lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
internal void lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, U64 base_addr); internal void lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc); internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc);
+180 -210
View File
@@ -343,185 +343,170 @@ lnk_chunk_list_get_node_count(LNK_Chunk *chunk)
} }
internal void internal void
lnk_chunk_op_list_push_node(LNK_ChunkOpList *list, LNK_ChunkOp *op) lnk_chunk_align_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkAlignArrayList *list, U64 cap, U64 align_off, U64 align_size)
{ {
SLLQueuePush(list->first, list->last, op); if (align_size > 0) {
if (list->last == 0 || list->last->data.count >= list->last->cap) {
LNK_ChunkAlignArrayNode *node = push_array(scratch, LNK_ChunkAlignArrayNode, 1);
node->cap = cap;
node->data.v = push_array_no_zero(arena, LNK_ChunkAlign, cap);
SLLQueuePush(list->first, list->last, node);
++list->count;
}
LNK_ChunkAlignArray *last_array = &list->last->data;
LNK_ChunkAlign *align = &last_array->v[last_array->count++];
align->off = align_off;
align->size = align_size;
}
} }
internal LNK_ChunkOp *
lnk_push_chunk_op_begin(Arena *arena, U64 chunk_id)
{
LNK_ChunkOp *begin_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
begin_op->next = 0;
begin_op->type = LNK_ChunkOp_Begin;
begin_op->u.chunk_id = chunk_id;
return begin_op;
}
internal LNK_ChunkOp * internal LNK_ChunkLayout
lnk_push_chunk_op_end_virt(Arena *arena) lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count)
{ {
LNK_ChunkOp *end_virt_op = push_array_no_zero(arena, LNK_ChunkOp, 1); ProfBeginV("lnk_layout_from_chunk [total_chunk_count = %llu]", total_chunk_count);
end_virt_op->next = 0; Temp scratch = scratch_begin(&arena, 1);
end_virt_op->type = LNK_ChunkOp_EndVirt;
return end_virt_op;
}
internal LNK_ChunkOp * LNK_ChunkLayout layout = {0};
lnk_push_chunk_op_end_file(Arena *arena) layout.total_count = total_chunk_count;
{ layout.chunk_ptr_array = push_array_no_zero(arena, LNK_ChunkPtr, total_chunk_count);
LNK_ChunkOp *end_op = push_array_no_zero(arena, LNK_ChunkOp, 1); layout.chunk_off_array = push_array_no_zero(arena, U64, total_chunk_count);
end_op->next = 0; layout.chunk_file_size_array = push_array_no_zero(arena, U64, total_chunk_count);
end_op->type = LNK_ChunkOp_End; layout.chunk_virt_size_array = push_array_no_zero(arena, U64, total_chunk_count);
return end_op;
}
internal LNK_ChunkOp * ProfBegin("Init Arrays");
lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val) for (U64 i = 0; i < total_chunk_count; ++i) {
{ layout.chunk_ptr_array[i] = &g_null_chunk;
LNK_ChunkOp *align_op = push_array_no_zero(arena, LNK_ChunkOp, 1); }
align_op->next = 0; #if BUILD_DEBUG
align_op->type = LNK_ChunkOp_Align; MemorySet(layout.chunk_off_array, 0xff, total_chunk_count * sizeof(layout.chunk_off_array));
align_op->u.align.x = align; MemorySet(layout.chunk_file_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_file_size_array));
align_op->u.align.val = val; MemorySet(layout.chunk_virt_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_virt_size_array));
return align_op; #endif
} ProfEnd();
internal LNK_ChunkOp * // handle null chunk
lnk_push_chunk_op_write(Arena *arena, String8 string) layout.chunk_off_array[0] = 0;
{ layout.chunk_file_size_array[0] = 0;
LNK_ChunkOp *write_op = push_array_no_zero(arena, LNK_ChunkOp, 1); layout.chunk_virt_size_array[0] = 0;
write_op->next = 0;
write_op->type = LNK_ChunkOp_WriteString;
write_op->u.string = string;
return write_op;
}
internal LNK_ChunkOpList // setup stack
lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte)
{
struct Stack { struct Stack {
struct Stack *next; struct Stack *next;
LNK_ChunkArray chunk_array; LNK_ChunkArray chunk_array;
U64 ichunk; U64 ichunk;
U64 cursor;
}; };
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
// setup stack
struct Stack *stack = push_array(scratch.arena, struct Stack, 1); struct Stack *stack = push_array(scratch.arena, struct Stack, 1);
stack->chunk_array.count = 1; stack->chunk_array.count = 1;
stack->chunk_array.v = &root; stack->chunk_array.v = &root;
// setup output list U64 align_cap = 4096;
LNK_ChunkOpList list = {0}; LNK_ChunkAlignArrayList align_list = {0};
list.total_chunk_count = total_chunk_count;
list.first = list.last = 0;
// write null U64 cursor = 0;
LNK_ChunkOp *null_begin_op = lnk_push_chunk_op_begin(arena, 0);
LNK_ChunkOp *null_end_virt_op = lnk_push_chunk_op_end_virt(arena);
LNK_ChunkOp *null_end_file_op = lnk_push_chunk_op_end_file(arena);;
lnk_chunk_op_list_push_node(&list, null_begin_op);
lnk_chunk_op_list_push_node(&list, null_end_virt_op);
lnk_chunk_op_list_push_node(&list, null_end_file_op);
// traverse chunks from root ProfBegin("Traverse chunks from root");
while (stack) { while (stack) {
while (stack->ichunk < stack->chunk_array.count) { while (stack->ichunk < stack->chunk_array.count) {
LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++]; LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++];
// skip unused chunks // skip discarded chunk
if (lnk_chunk_is_discarded(chunk)) { if (lnk_chunk_is_discarded(chunk)) {
continue; continue;
} }
// push align
U64 align_size = AlignPadPow2(cursor, chunk->align);
lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
cursor += align_size;
// store id -> chunk
Assert(chunk->ref.chunk_id < total_chunk_count);
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
// store id -> offset
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
switch (chunk->type) { switch (chunk->type) {
case LNK_Chunk_Leaf: { case LNK_Chunk_Leaf: {
// align start in its own begin/end block so align bytes don't contribute to chunk size // store id -> file size
LNK_ChunkOp *pad_begin_op = lnk_push_chunk_op_begin(arena, list.total_chunk_count++); Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
LNK_ChunkOp *pad_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte); layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
LNK_ChunkOp *pad_end_file_op = lnk_push_chunk_op_end_file(arena);
lnk_chunk_op_list_push_node(&list, pad_begin_op);
lnk_chunk_op_list_push_node(&list, pad_align_op);
lnk_chunk_op_list_push_node(&list, pad_end_file_op);
// write leaf // store id -> virt size
LNK_ChunkOp *leaf_begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id); Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
LNK_ChunkOp *leaf_write_op = lnk_push_chunk_op_write(arena, chunk->u.leaf); layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
LNK_ChunkOp *leaf_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
LNK_ChunkOp *leaf_end_virt_op = lnk_push_chunk_op_end_virt(arena); // advance
LNK_ChunkOp *leaf_end_file_op = lnk_push_chunk_op_end_file(arena); cursor += chunk->u.leaf.size;
#if LNK_DUMP_CHUNK_LAYOUT
leaf_write_op->chunk = chunk;
#endif
lnk_chunk_op_list_push_node(&list, leaf_begin_op);
lnk_chunk_op_list_push_node(&list, leaf_write_op);
lnk_chunk_op_list_push_node(&list, leaf_align_op);
lnk_chunk_op_list_push_node(&list, leaf_end_virt_op);
lnk_chunk_op_list_push_node(&list, leaf_end_file_op);
} break; } break;
case LNK_Chunk_LeafArray: { case LNK_Chunk_LeafArray: {
LNK_ChunkOp *begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id); // apply sort
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
lnk_chunk_op_list_push_node(&list, begin_op);
lnk_chunk_op_list_push_node(&list, align_op);
if (chunk->sort_chunk) { if (chunk->sort_chunk) {
lnk_chunk_array_sort(*chunk->u.arr); lnk_chunk_array_sort(*chunk->u.arr);
} }
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1); // recurse into sub chunks
frame->next = 0; struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
frame->chunk_array = *chunk->u.arr; frame->chunk_array = *chunk->u.arr;
frame->ichunk = 0; frame->cursor = cursor;
SLLStackPush(stack, frame); SLLStackPush(stack, frame);
} goto _continue; } goto _continue;
case LNK_Chunk_List: { case LNK_Chunk_List: {
// balance ops at :end_chunk_series // list -> array
LNK_ChunkOp *begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id);
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
lnk_chunk_op_list_push_node(&list, begin_op);
lnk_chunk_op_list_push_node(&list, align_op);
// chunk list -> chunk array
LNK_ChunkArray chunk_array = {0}; LNK_ChunkArray chunk_array = {0};
chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count); chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count);
for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) { for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) {
chunk_array.v[chunk_array.count++] = cptr->data; chunk_array.v[chunk_array.count++] = cptr->data;
} }
// apply sort
if (chunk->sort_chunk) { if (chunk->sort_chunk) {
lnk_chunk_array_sort(chunk_array); lnk_chunk_array_sort(chunk_array);
} }
// recurse into list chunk // recurse into sub chunks
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1); struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
frame->next = 0;
frame->chunk_array = chunk_array; frame->chunk_array = chunk_array;
frame->ichunk = 0; frame->cursor = cursor;
SLLStackPush(stack, frame); SLLStackPush(stack, frame);
} goto _continue; } goto _continue;
case LNK_Chunk_Null: { /* ignore */ } break; case LNK_Chunk_Null: break;
} }
} }
// terminate series // terminate series
if (stack->next) { if (stack->next) {
// pop node chunk from stack
struct Stack *prev = stack->next; struct Stack *prev = stack->next;
Assert(prev->ichunk > 0); Assert(prev->ichunk > 0);
// :end_chunk_series // align chunk end
LNK_ChunkOp *end_virt_op = lnk_push_chunk_op_end_virt(arena); LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1];
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, prev->chunk_array.v[prev->ichunk - 1]->align, align_byte); U64 align_size = AlignPadPow2(cursor, chunk->align);
LNK_ChunkOp *end_op = lnk_push_chunk_op_end_file(arena); lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
lnk_chunk_op_list_push_node(&list, end_virt_op);
lnk_chunk_op_list_push_node(&list, align_op); // check stack cursor for correctness
lnk_chunk_op_list_push_node(&list, end_op); Assert(cursor >= prev->cursor);
// store id -> virt size
U64 virt_chunk_size = cursor - prev->cursor;
layout.chunk_virt_size_array[chunk->ref.chunk_id] = virt_chunk_size;
// store id -> file size
U64 file_chunk_size = (cursor + align_size) - prev->cursor;
layout.chunk_file_size_array[chunk->ref.chunk_id] = file_chunk_size;
// advance cursor
cursor += align_size;
} }
// move to next frame // move to next frame
@@ -529,121 +514,111 @@ lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8
_continue:; _continue:;
} }
ProfEnd();
ProfBegin("Build Aligns Array");
layout.align_array_count = 0;
layout.align_array = push_array(arena, LNK_ChunkAlignArray, align_list.count);
for (LNK_ChunkAlignArrayNode *node = align_list.first; node != 0; node = node->next) {
layout.align_array[layout.align_array_count++] = node->data;
}
ProfEnd();
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return list; return layout;
} }
internal LNK_ChunkLayout internal LNK_ChunkLayout
lnk_chunk_layout_from_op_list(Arena *arena, LNK_ChunkOpList op_list, B32 is_data_inited) lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1); LNK_ChunkLayout layout = lnk_layout_from_chunk(arena, cman->root, cman->total_chunk_count);
ProfEnd();
return layout;
}
// setup stack internal
struct Stack { THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task)
struct Stack *next; {
U64 chunk_id; ProfBeginFunction();
U64 cursor;
} *stack = 0;
// setup state LNK_ChunkLayoutSerializer *task = raw_task;
U64 cursor = 0; Rng1U64 range = task->ranges[task_id];
String8List data_list = {0}; LNK_ChunkLayout layout = task->layout;
String8 buffer = task->buffer;
// setup output for (U64 chunk_idx = range.min; chunk_idx < range.max; ++chunk_idx) {
U64 *chunk_off_array = push_array_no_zero(arena, U64, op_list.total_chunk_count); LNK_Chunk *chunk = layout.chunk_ptr_array[chunk_idx];
U64 *chunk_file_size_array = push_array_no_zero(arena, U64, op_list.total_chunk_count);
U64 *chunk_virt_size_array = push_array_no_zero(arena, U64, op_list.total_chunk_count);
// debug stomp so discarded chunks map to invalid offset if (lnk_chunk_is_discarded(chunk)) {
#if LNK_PARANOID continue;
MemorySet(chunk_off_array, 0xFF, sizeof(*chunk_off_array) * op_list.total_chunk_count); }
MemorySet(chunk_file_size_array, 0xFF, sizeof(*chunk_file_size_array) * op_list.total_chunk_count);
MemorySet(chunk_virt_size_array, 0xFF, sizeof(*chunk_virt_size_array) * op_list.total_chunk_count);
#endif
// execute opcodes if (chunk->type == LNK_Chunk_Leaf) {
for (LNK_ChunkOp *op = op_list.first; op != NULL; op = op->next) { U64 off = layout.chunk_off_array[chunk->ref.chunk_id];
switch (op->type) { Assert(off + chunk->u.leaf.size <= buffer.size);
case LNK_ChunkOp_Null: break; U8 *buffer_ptr = buffer.str + off;
case LNK_ChunkOp_Begin: {
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
frame->chunk_id = op->u.chunk_id;
frame->cursor = cursor;
SLLStackPush(stack, frame);
chunk_off_array[stack->chunk_id] = stack->cursor;
} break;
case LNK_ChunkOp_End: {
chunk_file_size_array[stack->chunk_id] = cursor - stack->cursor;
SLLStackPop(stack);
} break;
case LNK_ChunkOp_EndVirt: {
chunk_virt_size_array[stack->chunk_id] = cursor - stack->cursor;
} break;
case LNK_ChunkOp_Align: {
Assert(IsPow2(op->u.align.x));
U64 size = AlignPow2(cursor, op->u.align.x) - cursor;
String8 string; if (chunk->u.leaf.str == 0) {
string.size = size; // zero out chunk bytes
string.str = push_array_no_zero(arena, U8, string.size); MemorySet(buffer_ptr, 0, chunk->u.leaf.size);
MemorySet(string.str, op->u.align.val, string.size); } else {
// copy chunk bytes
op->type = LNK_ChunkOp_WriteString; MemoryCopy(buffer_ptr, chunk->u.leaf.str, chunk->u.leaf.size);
op->u.string = string;
} // fall-through
case LNK_ChunkOp_WriteString: {
if (is_data_inited) {
// we allow chunks to have null for str for regions in the image that are zeroed out.
if (op->u.string.str == 0) {
op->u.string.str = push_array(arena, U8, op->u.string.size);
}
str8_list_push(scratch.arena, &data_list, op->u.string);
} }
#if LNK_DUMP_CHUNK_LAYOUT
if (op->chunk) {
fprintf(g_layout_file, "[%.*s] %llX %.*s\n", str8_varg(op->chunk->sort_idx), op->chunk->input_idx, str8_varg(op->chunk->debug));
}
#endif
// advance
cursor += op->u.string.size;
} break;
} }
} }
// are begin/end series opcodes balanced?
Assert(stack == 0);
// fill out result
LNK_ChunkLayout layout = {0};
layout.data = str8_list_join(arena, &data_list, 0);
layout.chunk_off_array = chunk_off_array;
layout.chunk_file_size_array = chunk_file_size_array;
layout.chunk_virt_size_array = chunk_virt_size_array;
scratch_end(scratch);
ProfEnd(); ProfEnd();
return layout;
} }
internal LNK_ChunkLayout internal
lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte) THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
// should we write data for chunks? LNK_ChunkLayoutSerializer *task = raw_task;
B32 is_data_inited = !!(~flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA); Rng1U64 range = task->ranges[task_id];
LNK_ChunkLayout layout = task->layout;
String8 buffer = task->buffer;
U8 fill_byte = task->fill_byte;
// build layout for (U64 align_array_idx = range.min; align_array_idx < range.max; ++align_array_idx) {
LNK_ChunkOpList op_list = lnk_op_list_from_chunk(scratch.arena, cman->root, cman->total_chunk_count, align_byte); LNK_ChunkAlignArray align_array = layout.align_array[align_array_idx];
LNK_ChunkLayout layout = lnk_chunk_layout_from_op_list(arena, op_list, is_data_inited); for (U64 align_idx = 0; align_idx < align_array.count; ++align_idx) {
LNK_ChunkAlign align = align_array.v[align_idx];
Assert(align.off + align.size <= buffer.size);
MemorySet(buffer.str + align.off, fill_byte, align.size);
}
}
ProfEnd();
}
internal void
lnk_serialize_chunk_layout(TP_Context *tp, LNK_ChunkLayout layout, String8 buffer, U8 fill_byte)
{
ProfBeginFunction();
Temp scratch = scratch_begin(0,0);
LNK_ChunkLayoutSerializer task;
task.layout = layout;
task.buffer = buffer;
task.fill_byte = fill_byte;
ProfBeginV("Fill Chunks [Chunk Count %llu]", layout.total_count);
task.ranges = tp_divide_work(scratch.arena, layout.total_count, tp->worker_count);
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_chunks_task, &task);
ProfEnd();
ProfBeginV("Fill Aligns [Array Count %llu]", layout.align_array_count);
task.ranges = tp_divide_work(scratch.arena, layout.align_array_count, tp->worker_count);
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_aligns_task, &task);
ProfEnd();
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return layout;
} }
internal B32 internal B32
@@ -699,15 +674,10 @@ LNK_CHUNK_VISITOR_SIG(lnk_save_chunk_ptr)
internal LNK_ChunkPtr * internal LNK_ChunkPtr *
lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman) lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman)
{ {
LNK_ChunkPtr *chunk_id_map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count + 1); LNK_ChunkPtr *map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count);
lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, chunk_id_map); lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, map);
map[0] = &g_null_chunk;
LNK_Chunk *null_chunk = push_array(arena, LNK_Chunk, 1); return map;
null_chunk->is_discarded = 1;
chunk_id_map[0] = null_chunk;
return chunk_id_map;
} }
internal LNK_ChunkNode * internal LNK_ChunkNode *
+44 -14
View File
@@ -5,8 +5,7 @@
//////////////////////////////// ////////////////////////////////
#define LNK_DEBUG_CHUNKS 0 #define LNK_DEBUG_CHUNKS 0
#define LNK_DUMP_CHUNK_LAYOUT 0
//////////////////////////////// ////////////////////////////////
@@ -79,17 +78,14 @@ typedef struct LNK_ChunkOp
struct LNK_ChunkOp *next; struct LNK_ChunkOp *next;
LNK_ChunkOpType type; LNK_ChunkOpType type;
union { union {
String8 string; String8 string;
U64 chunk_id; LNK_Chunk *chunk;
struct { struct {
U64 val; U64 val;
U64 x; U64 x;
} align; } align;
LNK_Chunk *leaf; LNK_Chunk *leaf;
} u; } u;
#if LNK_DUMP_CHUNK_LAYOUT
LNK_Chunk *chunk;
#endif
} LNK_ChunkOp; } LNK_ChunkOp;
typedef struct LNK_ChunkOpList typedef struct LNK_ChunkOpList
@@ -99,12 +95,39 @@ typedef struct LNK_ChunkOpList
LNK_ChunkOp *last; LNK_ChunkOp *last;
} LNK_ChunkOpList; } LNK_ChunkOpList;
typedef struct LNK_ChunkAlign
{
U64 off;
U64 size;
} LNK_ChunkAlign;
typedef struct LNK_ChunkAlignArray
{
U64 count;
LNK_ChunkAlign *v;
} LNK_ChunkAlignArray;
typedef struct LNK_ChunkAlignArrayNode
{
struct LNK_ChunkAlignArrayNode *next;
U64 cap;
LNK_ChunkAlignArray data;
} LNK_ChunkAlignArrayNode;
typedef struct LNK_ChunkAlignArrayList
{
U64 count;
LNK_ChunkAlignArrayNode *first;
LNK_ChunkAlignArrayNode *last;
} LNK_ChunkAlignArrayList;
typedef struct LNK_ChunkLayout typedef struct LNK_ChunkLayout
{ {
String8 data; U64 total_count;
U64 *chunk_off_array; LNK_Chunk **chunk_ptr_array; // discarded chunks point to g_null_chunk
U64 *chunk_file_size_array; U64 *chunk_off_array; // discarded chunks have offset set to max_U64
U64 *chunk_virt_size_array; U64 *chunk_file_size_array; // discarded chunks have offset set to max_U64
U64 *chunk_virt_size_array; // discarded chunks have offset set to max_U64
U64 align_array_count;
LNK_ChunkAlignArray *align_array;
} LNK_ChunkLayout; } LNK_ChunkLayout;
typedef struct LNK_ChunkManager typedef struct LNK_ChunkManager
@@ -113,6 +136,14 @@ typedef struct LNK_ChunkManager
U64 total_chunk_count; U64 total_chunk_count;
} LNK_ChunkManager; } LNK_ChunkManager;
typedef struct
{
LNK_ChunkLayout layout;
String8 buffer;
U8 fill_byte;
Rng1U64 *ranges;
} LNK_ChunkLayoutSerializer;
//////////////////////////////// ////////////////////////////////
read_only global LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 }; read_only global LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
@@ -148,9 +179,8 @@ internal LNK_ChunkOp * lnk_push_chunk_op_end_file(Arena *arena);
internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val); internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val);
internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string); internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string);
internal LNK_ChunkOpList lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte); internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count);
internal LNK_ChunkLayout lnk_chunk_layout_from_op_list(Arena *arena, LNK_ChunkOpList op_list, B32 is_data_inited); internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman);
internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte);
#define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud) #define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud)
typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig); typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig);
+5 -2
View File
@@ -2969,6 +2969,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
PDB_DbiModule *mod = task->mod_arr[obj_idx]; PDB_DbiModule *mod = task->mod_arr[obj_idx];
LNK_Obj *obj = &task->obj_arr[obj_idx]; LNK_Obj *obj = &task->obj_arr[obj_idx];
PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx]; PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx];
String8 image_data = task->image_data;
// TODO: use chunked lists for SC // TODO: use chunked lists for SC
@@ -2990,7 +2991,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
// query chunk info // query chunk info
ISectOff chunk_sc = lnk_sc_from_chunk_ref (sect_id_map, chunk->ref); ISectOff chunk_sc = lnk_sc_from_chunk_ref (sect_id_map, chunk->ref);
String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, chunk->ref); String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, image_data, chunk->ref);
LNK_Section *chunk_sect = lnk_sect_from_chunk_ref (sect_id_map, chunk->ref); LNK_Section *chunk_sect = lnk_sect_from_chunk_ref (sect_id_map, chunk->ref);
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref); U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref);
@@ -3116,6 +3117,7 @@ lnk_build_pdb_public_symbols(TP_Context *tp,
internal String8List internal String8List
lnk_build_pdb(TP_Context *tp, lnk_build_pdb(TP_Context *tp,
TP_Arena *tp_arena, TP_Arena *tp_arena,
String8 image_data,
Guid guid, Guid guid,
COFF_MachineType machine, COFF_MachineType machine,
COFF_TimeStamp time_stamp, COFF_TimeStamp time_stamp,
@@ -3276,7 +3278,7 @@ lnk_build_pdb(TP_Context *tp,
{ {
LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME);
LNK_Chunk *coff_sect_chunk = lnk_chunk_from_symbol(coff_sect_array_symbol); LNK_Chunk *coff_sect_chunk = lnk_chunk_from_symbol(coff_sect_array_symbol);
String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, coff_sect_chunk->ref); String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, coff_sect_chunk->ref);
U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader); U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader);
COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str; COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str;
for (COFF_SectionHeader *hdr_ptr = &coff_sect_ptr[0], *opl = hdr_ptr + coff_sect_count; for (COFF_SectionHeader *hdr_ptr = &coff_sect_ptr[0], *opl = hdr_ptr + coff_sect_count;
@@ -3294,6 +3296,7 @@ lnk_build_pdb(TP_Context *tp,
task.sect_id_map = sect_id_map; task.sect_id_map = sect_id_map;
task.mod_arr = mod_arr; task.mod_arr = mod_arr;
task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, obj_count); task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, obj_count);
task.image_data = image_data;
tp_for_parallel(tp, tp_arena, obj_count, lnk_push_dbi_sec_contrib_task, &task); tp_for_parallel(tp, tp_arena, obj_count, lnk_push_dbi_sec_contrib_task, &task);
dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list); dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list);
+2
View File
@@ -316,6 +316,7 @@ typedef struct
LNK_Section **sect_id_map; LNK_Section **sect_id_map;
PDB_DbiModule **mod_arr; PDB_DbiModule **mod_arr;
PDB_DbiSectionContribList *sc_list; PDB_DbiSectionContribList *sc_list;
String8 image_data;
} LNK_PushDbiSecContribTaskData; } LNK_PushDbiSecContribTaskData;
typedef struct typedef struct
@@ -581,6 +582,7 @@ internal void lnk_build_pdb_public_symbols(TP_Context *tp,
internal String8List lnk_build_pdb(TP_Context *tp, internal String8List lnk_build_pdb(TP_Context *tp,
TP_Arena *tp_arena, TP_Arena *tp_arena,
String8 image_data,
Guid guid, Guid guid,
COFF_MachineType machine, COFF_MachineType machine,
COFF_TimeStamp time_stamp, COFF_TimeStamp time_stamp,
+2 -2
View File
@@ -399,7 +399,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
chunk->flags = coff_sect->flags; chunk->flags = coff_sect->flags;
chunk->associate = 0; chunk->associate = 0;
chunk->u.leaf = data; chunk->u.leaf = data;
lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, isect: 0x%llX", path, sect_name_arr[sect_idx], sect_idx); lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx);
} }
// :common_block // :common_block
@@ -414,7 +414,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
master_common_block->flags = LNK_BSS_SECTION_FLAGS; master_common_block->flags = LNK_BSS_SECTION_FLAGS;
master_common_block->associate = 0; master_common_block->associate = 0;
master_common_block->u.list = push_array(arena, LNK_ChunkList, 1); master_common_block->u.list = push_array(arena, LNK_ChunkList, 1);
lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", path); lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", cached_path);
// convert from coff // convert from coff
B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ;
+74 -26
View File
@@ -250,16 +250,18 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine)
internal void internal void
lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine) lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine)
{ {
if (sect->is_loose && sect->has_layout) { if (sect->is_loose) {
// get value for align data fill if (sect->has_layout) {
U8 align_byte = 0; sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman);
B32 is_code = !!(sect->flags & COFF_SectionFlag_CNT_CODE); } else {
if (is_code) { sect->layout.total_count = sect->cman->total_chunk_count;
align_byte = lnk_code_align_byte_from_machine(machine); sect->layout.chunk_ptr_array = lnk_make_chunk_id_map(sect->arena, sect->cman);
sect->layout.chunk_off_array = 0;
sect->layout.chunk_file_size_array = 0;
sect->layout.chunk_virt_size_array = 0;
sect->layout.align_array_count = 0;
sect->layout.align_array = 0;
} }
sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman, sect->flags, align_byte);
sect->is_loose = 0; sect->is_loose = 0;
} }
} }
@@ -594,19 +596,48 @@ lnk_section_table_assign_indices(LNK_SectionTable *st)
} }
internal String8 internal String8
lnk_section_table_serialize(Arena *arena, LNK_SectionTable *st) lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
String8List image_list = {0};
for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { U64 image_size = 0;
LNK_Section *sect = &sect_node->data; for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
str8_list_push(scratch.arena, &image_list, sect->layout.data); LNK_Section *sect = &sect_n->data;
if (sect->has_layout) {
U64 root_size = sect->layout.chunk_file_size_array[sect->root->ref.chunk_id];
image_size += root_size;
}
} }
String8 result = str8_list_join(arena, &image_list, NULL);
U8 *image_buffer = push_array_no_zero(arena, U8, image_size);
String8 image = str8(image_buffer, image_size);
U64 image_cursor = 0;
for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
LNK_Section *sect = &sect_n->data;
if (sect->has_layout) {
if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
continue;
}
U64 sect_size = sect->layout.chunk_file_size_array[sect->root->ref.chunk_id];
String8 sect_data = str8_substr(image, rng_1u64(image_cursor, image_cursor + sect_size));
U8 fill_byte = 0;
if (sect->flags & COFF_SectionFlag_CNT_CODE) {
fill_byte = lnk_code_align_byte_from_machine(machine);
}
lnk_serialize_chunk_layout(tp, sect->layout, sect_data, fill_byte);
image_cursor += sect_size;
}
}
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return result; return image;
} }
internal LNK_ChunkPtr ** internal LNK_ChunkPtr **
@@ -736,24 +767,41 @@ lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref)
} }
internal String8 internal String8
lnk_data_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref) lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref)
{ {
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref); LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id]; LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, chunk_ref); String8 chunk_data;
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk_ref); if (sect->has_layout) {
String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size)); U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk_ref);
U64 chunk_foff = lnk_file_off_from_chunk_ref(sect_id_map, chunk_ref);
chunk_data = str8_substr(image_data, r1u64(chunk_foff, chunk_foff + chunk_size));
} else {
LNK_Chunk *chunk = sect->layout.chunk_ptr_array[final_chunk_ref.chunk_id];
Assert(chunk->type == LNK_Chunk_Leaf);
chunk_data = chunk->u.leaf;
}
return chunk_data; return chunk_data;
} }
internal String8 internal String8
lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref) lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref)
{ {
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref); LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id]; LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, chunk_ref);
U64 chunk_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk_ref); String8 chunk_data;
String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size)); if (sect->has_layout) {
U64 chunk_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk_ref);
U64 chunk_foff = lnk_file_off_from_chunk_ref(sect_id_map, chunk_ref);
chunk_data = str8_substr(image_data, r1u64(chunk_foff, chunk_foff + chunk_size));
} else {
LNK_Chunk *chunk = sect->layout.chunk_ptr_array[final_chunk_ref.chunk_id];
Assert(chunk->type == LNK_Chunk_Leaf);
chunk_data = chunk->u.leaf;
}
return chunk_data; return chunk_data;
} }
+3 -3
View File
@@ -121,7 +121,7 @@ internal void lnk_section_table_build_data(TP_Context *tp, LNK_Se
internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *st); internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *st);
internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *st); internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *st);
internal void lnk_section_table_assign_indices(LNK_SectionTable *st); internal void lnk_section_table_assign_indices(LNK_SectionTable *st);
internal String8 lnk_section_table_serialize(Arena *arena, LNK_SectionTable *st); internal String8 lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine);
internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *st); internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *st);
internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *st); internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *st);
@@ -134,8 +134,8 @@ internal U64 lnk_virt_off_from_chunk_ref(LNK_Section **sect_id_map,
internal U64 lnk_file_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal U64 lnk_file_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal U64 lnk_virt_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal U64 lnk_virt_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal U64 lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal U64 lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
internal ISectOff lnk_sc_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal ISectOff lnk_sc_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
internal U64 lnk_virt_off_from_reloc(LNK_Section **sect_id_map, LNK_Reloc *reloc); internal U64 lnk_virt_off_from_reloc(LNK_Section **sect_id_map, LNK_Reloc *reloc);
internal U64 lnk_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol); internal U64 lnk_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);