diff --git a/src/linker/linker.natvis b/src/linker/linker.natvis index cd8dd98a..4b6e5c55 100644 --- a/src/linker/linker.natvis +++ b/src/linker/linker.natvis @@ -16,8 +16,9 @@ - + + {{count={count} first={first} last={last} }} diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 76cea08a..b1b75df1 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -943,11 +943,9 @@ lnk_make_res_obj(TP_Context *tp, lnk_section_table_assign_indices(st); lnk_section_table_build_data(tp, st, machine); 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); - lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, 0); - - String8 res_obj = lnk_section_table_serialize(arena, st); - + lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, res_obj, 0); lnk_section_table_release(&st); 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_build_data(tp, st, machine); 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_patch_relocs_linker(tp, symtab, st, sect_id_map, 0); - String8 coff_data = lnk_section_table_serialize(arena, st); + lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, coff_data, 0); lnk_section_table_release(&st); @@ -1210,10 +1208,8 @@ lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path) internal B32 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 - // check against lib name - if (input_source == LNK_InputSource_Default || - input_source == LNK_InputSource_Obj) { + // when /defaultlib:path comes from command line or obj directive check against lib name + if (input_source == LNK_InputSource_Default || input_source == LNK_InputSource_Obj) { String8 lib_name = str8_skip_last_slash(path); if (hash_table_search_path(default_lib_ht, lib_name)) { 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); dir->time_stamp = time_stamp; dir->type = type; - //dir->voff = 0; // relocated through 'symbol' - //dir->foff = 0; // relocated through 'symbol' - //dir->size = 0; // relocated through 'symbol' + //dir->voff = 0; // relocated through 'data_symbol' + //dir->foff = 0; // relocated through 'data_symbol' + //dir->size = 0; // relocated through 'data_symbol' // push chunk 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 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 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 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; { KeyValuePair *is_page_present = hash_table_search_u64(page_ht, page_voff); @@ -2613,7 +2603,7 @@ lnk_apply_reloc(U64 base_addr, LNK_Reloc *reloc) { LNK_Symbol *symbol = lnk_resolve_symbol(symtab, reloc->symbol); - + // TODO: check if user forced to link with unresolved symbols and accordingly report the error if (!LNK_Symbol_IsDefined(symbol->type)) { lnk_error(LNK_Error_UndefinedSymbol, "%S", symbol->name); @@ -2629,21 +2619,21 @@ lnk_apply_reloc(U64 base_addr, LNK_DefinedSymbol *defined_symbol = &symbol->u.defined; switch (defined_symbol->value_type) { - case LNK_DefinedSymbolValue_Null: break; - case LNK_DefinedSymbolValue_Chunk: { - symbol_isect = lnk_isect_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_off = lnk_sect_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); - } break; - case LNK_DefinedSymbolValue_VA: { - symbol_voff = defined_symbol->u.va - base_addr; - } break; + case LNK_DefinedSymbolValue_Null: break; + case LNK_DefinedSymbolValue_Chunk: { + symbol_isect = lnk_isect_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_off = lnk_sect_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); + } break; + case LNK_DefinedSymbolValue_VA: { + symbol_voff = defined_symbol->u.va - base_addr; + } break; } -#if LNK_DEBUG +#if BUILD_DEBUG if (str8_match(str8_lit("__ImageBase"), symbol->name, 0)) { Assert(symbol_isect == 0); Assert(symbol_voff == 0); @@ -2658,92 +2648,92 @@ lnk_apply_reloc(U64 base_addr, S64 reloc_value = 0; switch (reloc->type) { - case LNK_Reloc_NULL: /* ignore */ break; - case LNK_Reloc_ADDR_16: { - reloc_value = safe_cast_u16(base_addr + symbol_voff); - reloc_size = 2; - } break; - case LNK_Reloc_ADDR_32: { - reloc_value = safe_cast_u32(base_addr + symbol_voff); - reloc_size = 4; - } break; - case LNK_Reloc_ADDR_64: { - reloc_value = base_addr + symbol_voff; - reloc_size = 8; - } break; - case LNK_Reloc_CHUNK_SIZE_FILE_16: { - reloc_value = safe_cast_u16(symbol_fsize); - reloc_size = 2; - } break; - case LNK_Reloc_CHUNK_SIZE_FILE_32: { - reloc_value = symbol_fsize; - reloc_size = 4; - } break; - case LNK_Reloc_CHUNK_SIZE_VIRT_32: { - reloc_value = symbol_vsize; - reloc_size = 4; - } break; - case LNK_Reloc_FILE_ALIGN_32: { - reloc_value = 0; - reloc_size = 4; - reloc_align = file_align; - } break; - case LNK_Reloc_FILE_OFF_32: { - reloc_value = safe_cast_u32(symbol_foff); - reloc_size = 4; - } break; - case LNK_Reloc_FILE_OFF_64: { - reloc_value = symbol_foff; - reloc_size = 8; - } break; - case LNK_Reloc_REL32: { - 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_size = 4; - } break; - case LNK_Reloc_REL32_1: { - 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_size = 4; - } break; - case LNK_Reloc_REL32_2: { - 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_size = 4; - } break; - case LNK_Reloc_REL32_3: { - 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_size = 4; - } break; - case LNK_Reloc_REL32_4: { - 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_size = 4; - } break; - case LNK_Reloc_REL32_5: { - 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_size = 4; - } break; - case LNK_Reloc_SECT_REL: { - reloc_value = safe_cast_u32(symbol_off); - reloc_size = 4; - } break; - case LNK_Reloc_SECT_IDX: { - reloc_value = safe_cast_u32(symbol_isect); - reloc_size = 4; - } break; - case LNK_Reloc_VIRT_ALIGN_32: { - reloc_value = 0; - reloc_size = 4; - reloc_align = virt_align; - } break; - case LNK_Reloc_VIRT_OFF_32: { - reloc_value = safe_cast_u32(symbol_voff); - reloc_size = 4; - } break; - default: NotImplemented; + case LNK_Reloc_NULL: /* ignore */ break; + case LNK_Reloc_ADDR_16: { + reloc_value = safe_cast_u16(base_addr + symbol_voff); + reloc_size = 2; + } break; + case LNK_Reloc_ADDR_32: { + reloc_value = safe_cast_u32(base_addr + symbol_voff); + reloc_size = 4; + } break; + case LNK_Reloc_ADDR_64: { + reloc_value = base_addr + symbol_voff; + reloc_size = 8; + } break; + case LNK_Reloc_CHUNK_SIZE_FILE_16: { + reloc_value = safe_cast_u16(symbol_fsize); + reloc_size = 2; + } break; + case LNK_Reloc_CHUNK_SIZE_FILE_32: { + reloc_value = symbol_fsize; + reloc_size = 4; + } break; + case LNK_Reloc_CHUNK_SIZE_VIRT_32: { + reloc_value = symbol_vsize; + reloc_size = 4; + } break; + case LNK_Reloc_FILE_ALIGN_32: { + reloc_value = 0; + reloc_size = 4; + reloc_align = file_align; + } break; + case LNK_Reloc_FILE_OFF_32: { + reloc_value = safe_cast_u32(symbol_foff); + reloc_size = 4; + } break; + case LNK_Reloc_FILE_OFF_64: { + reloc_value = symbol_foff; + reloc_size = 8; + } break; + case LNK_Reloc_REL32: { + 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_size = 4; + } break; + case LNK_Reloc_REL32_1: { + 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_size = 4; + } break; + case LNK_Reloc_REL32_2: { + 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_size = 4; + } break; + case LNK_Reloc_REL32_3: { + 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_size = 4; + } break; + case LNK_Reloc_REL32_4: { + 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_size = 4; + } break; + case LNK_Reloc_REL32_5: { + 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_size = 4; + } break; + case LNK_Reloc_SECT_REL: { + reloc_value = safe_cast_u32(symbol_off); + reloc_size = 4; + } break; + case LNK_Reloc_SECT_IDX: { + reloc_value = safe_cast_u32(symbol_isect); + reloc_size = 4; + } break; + case LNK_Reloc_VIRT_ALIGN_32: { + reloc_value = 0; + reloc_size = 4; + reloc_align = virt_align; + } break; + case LNK_Reloc_VIRT_OFF_32: { + reloc_value = safe_cast_u32(symbol_voff); + reloc_size = 4; + } break; + default: NotImplemented; } // read addend @@ -2763,6 +2753,7 @@ THREAD_POOL_TASK_FUNC(lnk_section_reloc_patcher) { LNK_SectionRelocPatcher *task = raw_task; + String8 image_data = task->image_data; LNK_SymbolTable *symtab = task->symtab; LNK_SectionTable *st = task->st; 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) { 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) { - LNK_Chunk *chunk = reloc->chunk; - if (lnk_chunk_is_discarded(chunk)) { - 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; + 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; } + 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 -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(); 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_SectionRelocPatcher task = {0}; + task.image_data = image_data; task.symtab = symtab; task.st = st; task.sect_id_map = sect_id_map; @@ -2822,8 +2800,10 @@ lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTabl internal THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) { - LNK_ObjRelocPatcher *task = raw_task; - LNK_Obj *obj = task->obj_arr[task_id]; + LNK_ObjRelocPatcher *task = raw_task; + 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) { 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)) { continue; } - Assert(reloc->chunk->type == LNK_Chunk_Leaf); - - 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; - } - } - + String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, reloc->chunk->ref); 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; } @@ -2850,12 +2819,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) } 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(); Temp scratch = scratch_begin(0,0); LNK_ObjRelocPatcher task; + task.image_data = image_data; task.symtab = symtab; task.st = st; task.sect_id_map = sect_id_map; @@ -3648,10 +3618,13 @@ lnk_run(int argc, char **argv) LNK_InputLibList unique_input_lib_list = {0}; for (LNK_InputLib *input = input_lib_list.first; input != 0; input = input->next) { String8 path = input->string; - + if (lnk_is_lib_disallowed(disallow_lib_ht, path)) { continue; } + + + if (lnk_is_lib_loaded(default_lib_ht, loaded_lib_ht, input_source, path)) { continue; } @@ -3942,6 +3915,11 @@ lnk_run(int argc, char **argv) lnk_section_table_assign_indices(st); lnk_section_table_assign_virtual_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 LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); @@ -3949,40 +3927,38 @@ lnk_run(int argc, char **argv) ProfBegin("Patch Relocs"); 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_linker(tp, 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, image_data, base_addr); ProfEnd(); ProfBegin("Sort Exception Info"); 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); - switch (config->machine) { - case COFF_MachineType_X86: - case COFF_MachineType_X64: { - U64 count = pdata.size / sizeof(PE_IntelPdata); - radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664); - } break; - case COFF_MachineType_ARM64: - case COFF_MachineType_ARM: { - AssertAlways(!"TOOD: ARM"); - } break; - case COFF_MachineType_MIPSFPU: - case COFF_MachineType_MIPS16: - case COFF_MachineType_MIPSFPU16: { - AssertAlways(!"TODO: MIPS"); - } break; + if (pdata_symbol) { + Assert(pdata_symbol->type == LNK_Symbol_DefinedExtern); + String8 pdata = lnk_data_from_chunk_ref_no_pad(sect_id_map, image_data, pdata_symbol->u.defined.u.chunk->ref); + switch (config->machine) { + case COFF_MachineType_X86: + case COFF_MachineType_X64: { + U64 count = pdata.size / sizeof(PE_IntelPdata); + radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664); + } break; + case COFF_MachineType_ARM64: + case COFF_MachineType_ARM: { + AssertAlways(!"TOOD: ARM"); + } break; + case COFF_MachineType_MIPSFPU: + case COFF_MachineType_MIPS16: + case COFF_MachineType_MIPSFPU16: { + AssertAlways(!"TODO: MIPS"); + } break; + } } ProfEnd(); 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); if (tls_used_symbol) { @@ -4129,6 +4105,7 @@ lnk_run(int argc, char **argv) String8List pdb_data = lnk_build_pdb(tp, tp_arena, + image_data, config->guid, config->machine, config->time_stamp, diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 1affc4df..855517a2 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -199,6 +199,7 @@ typedef struct typedef struct { + String8 image_data; LNK_SymbolTable *symtab; LNK_SectionTable *st; LNK_Section **sect_id_map; @@ -209,6 +210,7 @@ typedef struct typedef struct { + String8 image_data; LNK_SymbolTable *symtab; LNK_SectionTable *st; LNK_Section **sect_id_map; @@ -284,8 +286,8 @@ internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_S //////////////////////////////// // 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_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_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, 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); diff --git a/src/linker/lnk_chunk.c b/src/linker/lnk_chunk.c index f8fe8eb4..98f4dddb 100644 --- a/src/linker/lnk_chunk.c +++ b/src/linker/lnk_chunk.c @@ -343,185 +343,170 @@ lnk_chunk_list_get_node_count(LNK_Chunk *chunk) } 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 * -lnk_push_chunk_op_end_virt(Arena *arena) +internal LNK_ChunkLayout +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); - end_virt_op->next = 0; - end_virt_op->type = LNK_ChunkOp_EndVirt; - return end_virt_op; -} + ProfBeginV("lnk_layout_from_chunk [total_chunk_count = %llu]", total_chunk_count); + Temp scratch = scratch_begin(&arena, 1); + + LNK_ChunkLayout layout = {0}; + layout.total_count = total_chunk_count; + layout.chunk_ptr_array = push_array_no_zero(arena, LNK_ChunkPtr, total_chunk_count); + layout.chunk_off_array = push_array_no_zero(arena, U64, total_chunk_count); + layout.chunk_file_size_array = push_array_no_zero(arena, U64, total_chunk_count); + layout.chunk_virt_size_array = push_array_no_zero(arena, U64, total_chunk_count); -internal LNK_ChunkOp * -lnk_push_chunk_op_end_file(Arena *arena) -{ - LNK_ChunkOp *end_op = push_array_no_zero(arena, LNK_ChunkOp, 1); - end_op->next = 0; - end_op->type = LNK_ChunkOp_End; - return end_op; -} + ProfBegin("Init Arrays"); + for (U64 i = 0; i < total_chunk_count; ++i) { + layout.chunk_ptr_array[i] = &g_null_chunk; + } +#if BUILD_DEBUG + MemorySet(layout.chunk_off_array, 0xff, total_chunk_count * sizeof(layout.chunk_off_array)); + MemorySet(layout.chunk_file_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_file_size_array)); + MemorySet(layout.chunk_virt_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_virt_size_array)); +#endif + ProfEnd(); -internal LNK_ChunkOp * -lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val) -{ - LNK_ChunkOp *align_op = push_array_no_zero(arena, LNK_ChunkOp, 1); - align_op->next = 0; - align_op->type = LNK_ChunkOp_Align; - align_op->u.align.x = align; - align_op->u.align.val = val; - return align_op; -} + // handle null chunk + layout.chunk_off_array[0] = 0; + layout.chunk_file_size_array[0] = 0; + layout.chunk_virt_size_array[0] = 0; -internal LNK_ChunkOp * -lnk_push_chunk_op_write(Arena *arena, String8 string) -{ - LNK_ChunkOp *write_op = push_array_no_zero(arena, LNK_ChunkOp, 1); - write_op->next = 0; - write_op->type = LNK_ChunkOp_WriteString; - write_op->u.string = string; - return write_op; -} - -internal LNK_ChunkOpList -lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte) -{ + // setup stack struct Stack { struct Stack *next; LNK_ChunkArray chunk_array; U64 ichunk; + U64 cursor; }; - - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - - // setup stack struct Stack *stack = push_array(scratch.arena, struct Stack, 1); stack->chunk_array.count = 1; stack->chunk_array.v = &root; - - // setup output list - LNK_ChunkOpList list = {0}; - list.total_chunk_count = total_chunk_count; - list.first = list.last = 0; - - // write null - 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 + + U64 align_cap = 4096; + LNK_ChunkAlignArrayList align_list = {0}; + + U64 cursor = 0; + + ProfBegin("Traverse chunks from root"); while (stack) { while (stack->ichunk < stack->chunk_array.count) { LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++]; - // skip unused chunks + // skip discarded chunk if (lnk_chunk_is_discarded(chunk)) { 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) { case LNK_Chunk_Leaf: { - // align start in its own begin/end block so align bytes don't contribute to chunk size - LNK_ChunkOp *pad_begin_op = lnk_push_chunk_op_begin(arena, list.total_chunk_count++); - LNK_ChunkOp *pad_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte); - 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 - LNK_ChunkOp *leaf_begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id); - LNK_ChunkOp *leaf_write_op = lnk_push_chunk_op_write(arena, chunk->u.leaf); - 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); - LNK_ChunkOp *leaf_end_file_op = lnk_push_chunk_op_end_file(arena); - #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); + // store id -> file size + Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64); + layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size; + + // store id -> virt size + Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64); + layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size; + + // advance + cursor += chunk->u.leaf.size; } break; case LNK_Chunk_LeafArray: { - 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); - + // apply sort if (chunk->sort_chunk) { lnk_chunk_array_sort(*chunk->u.arr); } - struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1); - frame->next = 0; + // recurse into sub chunks + struct Stack *frame = push_array(scratch.arena, struct Stack, 1); frame->chunk_array = *chunk->u.arr; - frame->ichunk = 0; + frame->cursor = cursor; SLLStackPush(stack, frame); } goto _continue; - case LNK_Chunk_List: { - // balance ops at :end_chunk_series - 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 + case LNK_Chunk_List: { + // list -> array LNK_ChunkArray chunk_array = {0}; 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) { chunk_array.v[chunk_array.count++] = cptr->data; } + // apply sort if (chunk->sort_chunk) { lnk_chunk_array_sort(chunk_array); } - // recurse into list chunk - struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1); - frame->next = 0; + // recurse into sub chunks + struct Stack *frame = push_array(scratch.arena, struct Stack, 1); frame->chunk_array = chunk_array; - frame->ichunk = 0; + frame->cursor = cursor; SLLStackPush(stack, frame); } goto _continue; - case LNK_Chunk_Null: { /* ignore */ } break; + case LNK_Chunk_Null: break; } } // terminate series if (stack->next) { + // pop node chunk from stack struct Stack *prev = stack->next; Assert(prev->ichunk > 0); - // :end_chunk_series - LNK_ChunkOp *end_virt_op = lnk_push_chunk_op_end_virt(arena); - LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, prev->chunk_array.v[prev->ichunk - 1]->align, align_byte); - LNK_ChunkOp *end_op = lnk_push_chunk_op_end_file(arena); - lnk_chunk_op_list_push_node(&list, end_virt_op); - lnk_chunk_op_list_push_node(&list, align_op); - lnk_chunk_op_list_push_node(&list, end_op); + // align chunk end + LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1]; + U64 align_size = AlignPadPow2(cursor, chunk->align); + lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size); + + // check stack cursor for correctness + 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 @@ -529,121 +514,111 @@ lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 _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); ProfEnd(); - return list; + return layout; } 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(); - Temp scratch = scratch_begin(&arena, 1); - - // setup stack - struct Stack { - struct Stack *next; - U64 chunk_id; - U64 cursor; - } *stack = 0; - - // setup state - U64 cursor = 0; - String8List data_list = {0}; - - // setup output - U64 *chunk_off_array = push_array_no_zero(arena, U64, op_list.total_chunk_count); - 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_PARANOID - 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 - for (LNK_ChunkOp *op = op_list.first; op != NULL; op = op->next) { - switch (op->type) { - case LNK_ChunkOp_Null: break; - 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; - string.size = size; - string.str = push_array_no_zero(arena, U8, string.size); - MemorySet(string.str, op->u.align.val, string.size); - - op->type = LNK_ChunkOp_WriteString; - 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); + LNK_ChunkLayout layout = lnk_layout_from_chunk(arena, cman->root, cman->total_chunk_count); + ProfEnd(); + return layout; +} + +internal +THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task) +{ + ProfBeginFunction(); + + LNK_ChunkLayoutSerializer *task = raw_task; + Rng1U64 range = task->ranges[task_id]; + LNK_ChunkLayout layout = task->layout; + String8 buffer = task->buffer; + + for (U64 chunk_idx = range.min; chunk_idx < range.max; ++chunk_idx) { + LNK_Chunk *chunk = layout.chunk_ptr_array[chunk_idx]; + + if (lnk_chunk_is_discarded(chunk)) { + continue; + } + + if (chunk->type == LNK_Chunk_Leaf) { + U64 off = layout.chunk_off_array[chunk->ref.chunk_id]; + Assert(off + chunk->u.leaf.size <= buffer.size); + U8 *buffer_ptr = buffer.str + off; + + if (chunk->u.leaf.str == 0) { + // zero out chunk bytes + MemorySet(buffer_ptr, 0, chunk->u.leaf.size); + } else { + // copy chunk bytes + MemoryCopy(buffer_ptr, chunk->u.leaf.str, chunk->u.leaf.size); } -#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(); - return layout; } -internal LNK_ChunkLayout -lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte) +internal +THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task) { ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - - // should we write data for chunks? - B32 is_data_inited = !!(~flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA); - - // build layout - LNK_ChunkOpList op_list = lnk_op_list_from_chunk(scratch.arena, cman->root, cman->total_chunk_count, align_byte); - LNK_ChunkLayout layout = lnk_chunk_layout_from_op_list(arena, op_list, is_data_inited); + + LNK_ChunkLayoutSerializer *task = raw_task; + Rng1U64 range = task->ranges[task_id]; + LNK_ChunkLayout layout = task->layout; + String8 buffer = task->buffer; + U8 fill_byte = task->fill_byte; + + for (U64 align_array_idx = range.min; align_array_idx < range.max; ++align_array_idx) { + LNK_ChunkAlignArray align_array = layout.align_array[align_array_idx]; + 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); ProfEnd(); - return layout; } internal B32 @@ -699,15 +674,10 @@ LNK_CHUNK_VISITOR_SIG(lnk_save_chunk_ptr) internal LNK_ChunkPtr * 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_visit_chunks(0, cman->root, lnk_save_chunk_ptr, chunk_id_map); - - LNK_Chunk *null_chunk = push_array(arena, LNK_Chunk, 1); - null_chunk->is_discarded = 1; - - chunk_id_map[0] = null_chunk; - - return chunk_id_map; + LNK_ChunkPtr *map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count); + lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, map); + map[0] = &g_null_chunk; + return map; } internal LNK_ChunkNode * diff --git a/src/linker/lnk_chunk.h b/src/linker/lnk_chunk.h index ecef5f3d..c11b9469 100644 --- a/src/linker/lnk_chunk.h +++ b/src/linker/lnk_chunk.h @@ -5,8 +5,7 @@ //////////////////////////////// -#define LNK_DEBUG_CHUNKS 0 -#define LNK_DUMP_CHUNK_LAYOUT 0 +#define LNK_DEBUG_CHUNKS 0 //////////////////////////////// @@ -79,17 +78,14 @@ typedef struct LNK_ChunkOp struct LNK_ChunkOp *next; LNK_ChunkOpType type; union { - String8 string; - U64 chunk_id; + String8 string; + LNK_Chunk *chunk; struct { U64 val; U64 x; } align; LNK_Chunk *leaf; } u; -#if LNK_DUMP_CHUNK_LAYOUT - LNK_Chunk *chunk; -#endif } LNK_ChunkOp; typedef struct LNK_ChunkOpList @@ -99,12 +95,39 @@ typedef struct LNK_ChunkOpList LNK_ChunkOp *last; } 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 { - String8 data; - U64 *chunk_off_array; - U64 *chunk_file_size_array; - U64 *chunk_virt_size_array; + U64 total_count; + LNK_Chunk **chunk_ptr_array; // discarded chunks point to g_null_chunk + U64 *chunk_off_array; // discarded chunks have offset set to max_U64 + 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; typedef struct LNK_ChunkManager @@ -113,6 +136,14 @@ typedef struct LNK_ChunkManager U64 total_chunk_count; } 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 }; @@ -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_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_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, COFF_SectionFlags flags, U8 align_byte); +internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count); +internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman); #define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud) typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig); diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 531dc776..a0123bf6 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2969,6 +2969,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) PDB_DbiModule *mod = task->mod_arr[obj_idx]; LNK_Obj *obj = &task->obj_arr[obj_idx]; PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx]; + String8 image_data = task->image_data; // TODO: use chunked lists for SC @@ -2990,7 +2991,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) // query chunk info 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); 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 lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, + String8 image_data, Guid guid, COFF_MachineType machine, 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_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); 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; @@ -3294,6 +3296,7 @@ lnk_build_pdb(TP_Context *tp, task.sect_id_map = sect_id_map; task.mod_arr = mod_arr; 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); dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list); diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index e8c73f8d..cca87cff 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -316,6 +316,7 @@ typedef struct LNK_Section **sect_id_map; PDB_DbiModule **mod_arr; PDB_DbiSectionContribList *sc_list; + String8 image_data; } LNK_PushDbiSecContribTaskData; typedef struct @@ -581,6 +582,7 @@ internal void lnk_build_pdb_public_symbols(TP_Context *tp, internal String8List lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, + String8 image_data, Guid guid, COFF_MachineType machine, COFF_TimeStamp time_stamp, diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index d7629944..363f1868 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -399,7 +399,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) chunk->flags = coff_sect->flags; chunk->associate = 0; 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 @@ -414,7 +414,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) master_common_block->flags = LNK_BSS_SECTION_FLAGS; master_common_block->associate = 0; 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 B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index b9af0284..8e05261c 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -250,16 +250,18 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine) internal void lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine) { - if (sect->is_loose && sect->has_layout) { - // get value for align data fill - U8 align_byte = 0; - B32 is_code = !!(sect->flags & COFF_SectionFlag_CNT_CODE); - if (is_code) { - align_byte = lnk_code_align_byte_from_machine(machine); + if (sect->is_loose) { + if (sect->has_layout) { + sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman); + } else { + sect->layout.total_count = sect->cman->total_chunk_count; + 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; } } @@ -594,19 +596,48 @@ lnk_section_table_assign_indices(LNK_SectionTable *st) } 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(); 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) { - LNK_Section *sect = §_node->data; - str8_list_push(scratch.arena, &image_list, sect->layout.data); + + U64 image_size = 0; + for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) { + LNK_Section *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 = §_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); ProfEnd(); - return result; + return image; } internal LNK_ChunkPtr ** @@ -736,24 +767,41 @@ 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) +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_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_file_size_from_chunk_ref(sect_id_map, chunk_ref); - String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size)); + 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]; + String8 chunk_data; + if (sect->has_layout) { + 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; } 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_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 = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size)); + + String8 chunk_data; + 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; } diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index 37fd1405..4aa6f2c3 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -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_file_offsets(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_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_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 String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, 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(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, String8 image_data, 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_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);