diff --git a/src/linker/lnk.c b/src/linker/lnk.c index ad3ba862..ef04ecf1 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1475,7 +1475,7 @@ lnk_build_guard_tables(TP_Context *tp, } else { // use relocation data in code sections to get function symbols for (U64 isect = 0; isect < obj->sect_count; ++isect) { - LNK_Chunk *chunk = &obj->chunk_arr[isect]; + LNK_Chunk *chunk = obj->chunk_arr[isect]; if (!chunk) { continue; } @@ -1782,7 +1782,7 @@ THREAD_POOL_TASK_FUNC(lnk_emit_base_relocs_from_objs_task) for (U64 obj_idx = range.min; obj_idx < range.max; ++obj_idx) { LNK_Obj *obj = task->obj_arr[obj_idx]; for (U64 sect_idx = 0; sect_idx < obj->sect_count; sect_idx += 1) { - B32 is_live = !lnk_chunk_is_discarded(&obj->chunk_arr[sect_idx]); + B32 is_live = !lnk_chunk_is_discarded(obj->chunk_arr[sect_idx]); if (is_live) { LNK_RelocList reloc_list = obj->sect_reloc_list_arr[sect_idx]; for (LNK_Reloc *reloc = reloc_list.first; reloc != 0; reloc = reloc->next) { @@ -2610,16 +2610,6 @@ lnk_apply_reloc(U64 base_addr, } break; } -#if BUILD_DEBUG - if (str8_match(str8_lit("__ImageBase"), symbol->name, 0)) { - Assert(symbol_isect == 0); - Assert(symbol_voff == 0); - Assert(symbol_foff == 0); - Assert(symbol_vsize == 0); - Assert(symbol_fsize == 0); - } -#endif - U64 reloc_align = 1; U64 reloc_size = 0; S64 reloc_value = 0; @@ -3521,7 +3511,7 @@ lnk_run(int argc, char **argv) } ProfEnd(); - LNK_ObjNodeArray obj_node_arr = lnk_obj_list_push_parallel(tp, tp_arena, &obj_list, st, unique_obj_input_list.count, input_obj_arr); + LNK_ObjNodeArray obj_node_arr = lnk_obj_list_push_parallel(tp, tp_arena, &obj_list, st, config->function_pad_min, unique_obj_input_list.count, input_obj_arr); ProfBegin("Machine Compat Check"); for (U64 obj_idx = 0; obj_idx < obj_node_arr.count; ++obj_idx) { diff --git a/src/linker/lnk_chunk.c b/src/linker/lnk_chunk.c index 7400b603..37d44ec8 100644 --- a/src/linker/lnk_chunk.c +++ b/src/linker/lnk_chunk.c @@ -183,11 +183,15 @@ lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk) stack->src_node = stack->src_node->next; stack->dst_node = stack->dst_node->next; - dst->ref = src->ref; - dst->align = src->align; - dst->sort_idx = push_str8_copy(arena, src->sort_idx); - dst->type = src->type; - dst->flags = src->flags; + dst->ref = src->ref; + dst->type = src->type; + dst->align = src->align; + dst->is_discarded = src->is_discarded; + dst->sort_chunk = src->sort_chunk; + dst->sort_idx = push_str8_copy(arena, src->sort_idx); + dst->input_idx = src->input_idx; + dst->flags = src->flags; + dst->associate = src->associate; lnk_chunk_set_debugf(arena, dst, "%S", src->debug); switch (src->type) { @@ -343,25 +347,37 @@ lnk_chunk_list_get_node_count(LNK_Chunk *chunk) } internal void -lnk_chunk_align_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkAlignArrayList *list, U64 cap, U64 align_off, U64 align_size) +lnk_chunk_pad_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkPadArrayList *list, U64 cap, U64 align_off, U64 align_size) { if (align_size > 0) { if (list->last == 0 || list->last->data.count >= list->last->cap) { - LNK_ChunkAlignArrayNode *node = push_array(scratch, LNK_ChunkAlignArrayNode, 1); + LNK_ChunkPadArrayNode *node = push_array(scratch, LNK_ChunkPadArrayNode, 1); node->cap = cap; - node->data.v = push_array_no_zero(arena, LNK_ChunkAlign, cap); + node->data.v = push_array_no_zero(arena, LNK_ChunkPad, 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++]; + LNK_ChunkPadArray *last_array = &list->last->data; + LNK_ChunkPad *align = &last_array->v[last_array->count++]; align->off = align_off; align->size = align_size; } } +internal +LNK_CHUNK_VISITOR_SIG(lnk_offset_chunks) +{ + LNK_OffsetChunks *offset_chunks = ud; + U64 offset = offset_chunks->offset; + LNK_ChunkLayout *layout = offset_chunks->layout; + + layout->chunk_off_array[chunk->ref.chunk_id] += offset; + + return 0; +} + internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) { @@ -401,8 +417,8 @@ lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) stack->chunk_array.count = 1; stack->chunk_array.v = &root; - U64 align_cap = 4096; - LNK_ChunkAlignArrayList align_list = {0}; + U64 pad_cap = 4096; + LNK_ChunkPadArrayList pad_list = {0}; U64 cursor = 0; @@ -416,22 +432,29 @@ lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) 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: { + // push pad + if (chunk->u.leaf.size < chunk->min_size) { + U64 pad_size = chunk->min_size - chunk->u.leaf.size; + lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, pad_size); + cursor += pad_size; + } + + // push align + U64 align_size = AlignPadPow2(cursor, chunk->align); + lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_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; + // 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; @@ -445,11 +468,20 @@ lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) } break; case LNK_Chunk_LeafArray: { -#if BUILD_DEBUG - for (U64 i = 0; i < chunk->u.arr->count; ++i) { - Assert(chunk->u.arr->v[i]->type == LNK_Chunk_Leaf); - } -#endif + // push align + U64 align_size = AlignPadPow2(cursor, chunk->align); + lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_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; + // apply sort if (chunk->sort_chunk) { lnk_chunk_array_sort(*chunk->u.arr); @@ -462,6 +494,20 @@ lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) } goto _continue; case LNK_Chunk_List: { + // push align + U64 align_size = AlignPadPow2(cursor, chunk->align); + lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_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; + // list -> array LNK_ChunkArray chunk_array = {0}; chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count); @@ -488,29 +534,41 @@ lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) if (stack->next) { // pop node chunk from stack struct Stack *prev = stack->next; + Assert(prev->ichunk > 0); + LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1]; + + U64 chunk_data_off = layout.chunk_off_array[chunk->ref.chunk_id]; + Assert(chunk_data_off != max_U64); + Assert(chunk_data_off <= cursor); + + U64 chunk_data_size = cursor - chunk_data_off; + + // store id -> virt size (no pad and align) + Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64); + layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk_data_size; + + // push pad + if (chunk_data_size < chunk->min_size) { + U64 pad_size = chunk->min_size - chunk->u.leaf.size; + lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, chunk_data_off, pad_size); + + LNK_OffsetChunks ud = {0}; + ud.offset = pad_size; + ud.layout = &layout; + lnk_visit_chunks(0, chunk, lnk_offset_chunks, &ud); + } // 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); - - U64 chunk_start_off = layout.chunk_off_array[chunk->ref.chunk_id]; - Assert(chunk_start_off != max_U64); - Assert(chunk_start_off <= cursor); - - // store id -> virt size - Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64); - U64 virt_chunk_size = cursor - chunk_start_off; - layout.chunk_virt_size_array[chunk->ref.chunk_id] = virt_chunk_size; - - // advance cursor + U64 align_size = AlignPadPow2(cursor, chunk->align); + lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, align_size); cursor += align_size; - // store id -> file size + chunk_data_size = cursor - chunk_data_off; + + // store id -> file size (pad + align) Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64); - U64 file_chunk_size = cursor - chunk_start_off; - layout.chunk_file_size_array[chunk->ref.chunk_id] = file_chunk_size; + layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk_data_size; } // move to next frame @@ -520,11 +578,11 @@ lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count) } 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; + ProfBegin("Build Pad Array"); + layout.pad_array_count = 0; + layout.pad_array = push_array(arena, LNK_ChunkPadArray, pad_list.count); + for (LNK_ChunkPadArrayNode *node = pad_list.first; node != 0; node = node->next) { + layout.pad_array[layout.pad_array_count++] = node->data; } ProfEnd(); @@ -578,7 +636,7 @@ THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task) } internal -THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task) +THREAD_POOL_TASK_FUNC(lnk_fill_pads_task) { ProfBeginFunction(); @@ -588,12 +646,12 @@ THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task) 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); + for (U64 pad_array_idx = range.min; pad_array_idx < range.max; ++pad_array_idx) { + LNK_ChunkPadArray pad_array = layout.pad_array[pad_array_idx]; + for (U64 pad_idx = 0; pad_idx < pad_array.count; ++pad_idx) { + LNK_ChunkPad pad = pad_array.v[pad_idx]; + Assert(pad.off + pad.size <= buffer.size); + MemorySet(buffer.str + pad.off, fill_byte, pad.size); } } @@ -616,9 +674,9 @@ lnk_serialize_chunk_layout(TP_Context *tp, LNK_ChunkLayout layout, String8 buffe 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); + ProfBeginV("Fill Pads [Array Count %llu]", layout.pad_array_count); + task.ranges = tp_divide_work(scratch.arena, layout.pad_array_count, tp->worker_count); + tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_pads_task, &task); ProfEnd(); scratch_end(scratch); diff --git a/src/linker/lnk_chunk.h b/src/linker/lnk_chunk.h index c11b9469..e8313b98 100644 --- a/src/linker/lnk_chunk.h +++ b/src/linker/lnk_chunk.h @@ -28,6 +28,7 @@ typedef struct LNK_Chunk LNK_ChunkRef ref; LNK_ChunkType type; U64 align; + U64 min_size; B32 is_discarded; B32 sort_chunk; String8 sort_idx; @@ -95,29 +96,29 @@ typedef struct LNK_ChunkOpList LNK_ChunkOp *last; } LNK_ChunkOpList; -typedef struct LNK_ChunkAlign +typedef struct LNK_ChunkPad { U64 off; U64 size; -} LNK_ChunkAlign; +} LNK_ChunkPad; -typedef struct LNK_ChunkAlignArray +typedef struct LNK_ChunkPadArray { - U64 count; - LNK_ChunkAlign *v; -} LNK_ChunkAlignArray; -typedef struct LNK_ChunkAlignArrayNode + U64 count; + LNK_ChunkPad *v; +} LNK_ChunkPadArray; +typedef struct LNK_ChunkPadArrayNode { - struct LNK_ChunkAlignArrayNode *next; + struct LNK_ChunkPadArrayNode *next; U64 cap; - LNK_ChunkAlignArray data; -} LNK_ChunkAlignArrayNode; -typedef struct LNK_ChunkAlignArrayList + LNK_ChunkPadArray data; +} LNK_ChunkPadArrayNode; +typedef struct LNK_ChunkPadArrayList { U64 count; - LNK_ChunkAlignArrayNode *first; - LNK_ChunkAlignArrayNode *last; -} LNK_ChunkAlignArrayList; + LNK_ChunkPadArrayNode *first; + LNK_ChunkPadArrayNode *last; +} LNK_ChunkPadArrayList; typedef struct LNK_ChunkLayout { @@ -126,8 +127,8 @@ typedef struct LNK_ChunkLayout 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; + U64 pad_array_count; + LNK_ChunkPadArray *pad_array; } LNK_ChunkLayout; typedef struct LNK_ChunkManager @@ -136,6 +137,14 @@ typedef struct LNK_ChunkManager U64 total_chunk_count; } LNK_ChunkManager; +//////////////////////////////// + +typedef struct +{ + U64 offset; + LNK_ChunkLayout *layout; +} LNK_OffsetChunks; + typedef struct { LNK_ChunkLayout layout; diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index a0123bf6..98d3a31c 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2978,7 +2978,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) U64 sc_count = 0; for (U64 chunk_idx = 0; chunk_idx < obj->sect_count; ++chunk_idx) { - LNK_Chunk *chunk = &obj->chunk_arr[chunk_idx]; + LNK_Chunk *chunk = obj->chunk_arr[chunk_idx]; if (!chunk || lnk_chunk_is_discarded(chunk)) { continue; @@ -5325,7 +5325,7 @@ THREAD_POOL_TASK_FUNC(lnk_collect_obj_virtual_ranges_task) dst->virt_ranges = push_array_no_zero(arena, Rng1U64, obj->sect_count); for (U64 chunk_idx = 0; chunk_idx < obj->sect_count; ++chunk_idx) { - LNK_Chunk *chunk = &obj->chunk_arr[chunk_idx]; + LNK_Chunk *chunk = obj->chunk_arr[chunk_idx]; if (!chunk || lnk_chunk_is_discarded(chunk)) { continue; } diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 64da9000..e8d486a3 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -938,7 +938,7 @@ lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, LNK_InputObj **inputs = lnk_array_from_input_obj_list(scratch.arena, input_obj_list); LNK_SectionTable *st = lnk_section_table_alloc(0,0,0); LNK_ObjList obj_list = {0}; - lnk_obj_list_push_parallel(tp, arena, &obj_list, st, input_obj_list.count, inputs); + lnk_obj_list_push_parallel(tp, arena, &obj_list, st, 0, input_obj_list.count, inputs); LNK_LibBuild import_lib = lnk_build_lib(scratch.arena, machine, time_stamp, dll_name, obj_list, exptab); B32 emit_second_member = 0; // MSVC linker refuses to link with lib that has the second member. diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 363f1868..fc44573c 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -142,7 +142,7 @@ lnk_obj_search_chunks(Arena *arena, LNK_Obj *obj, String8 name, String8 postfix, str8_match(obj_sect_sort, postfix, 0); if (is_match) { - LNK_ChunkPtr chunk = &obj->chunk_arr[sect_idx]; + LNK_ChunkPtr chunk = obj->chunk_arr[sect_idx]; if (!collect_discarded && lnk_chunk_is_discarded(chunk)) { continue; @@ -332,8 +332,6 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) LNK_ObjNode *obj_node = task->obj_node_arr + task_id; LNK_Obj *obj = &obj_node->data; - //Assert(coff_data.size > 0); - // cache path, we need it for error reports and debug stuff String8 cached_path = push_str8_copy(arena, input->path); String8 cached_lib_path = push_str8_copy(arena, input->lib_path); @@ -353,9 +351,9 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) chunk_count += coff_info.section_count_no_null; chunk_count += 1; // :common_block - String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); - String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); - LNK_Chunk *chunk_arr = push_array_no_zero(arena, LNK_Chunk, chunk_count); + String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); + String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); + LNK_Chunk *chunk_arr = push_array_no_zero(arena, LNK_Chunk, chunk_count); // init section name and postfix array for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) { @@ -391,6 +389,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) LNK_Chunk *chunk = &chunk_arr[sect_idx]; chunk->ref = lnk_chunk_ref(0,0); // :chunk_ref_assign chunk->align = coff_align_size_from_section_flags(coff_sect->flags); + chunk->min_size = 0; chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LNK_REMOVE); chunk->sort_chunk = 1; chunk->type = LNK_Chunk_Leaf; @@ -416,11 +415,16 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) master_common_block->u.list = push_array(arena, LNK_ChunkList, 1); lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", cached_path); + LNK_ChunkPtr *chunk_ptr_arr = push_array_no_zero(arena, LNK_ChunkPtr, chunk_count); + for (U64 i = 0; i < chunk_count; ++i) { + chunk_ptr_arr[i] = &chunk_arr[i]; + } + // convert from coff B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ; - LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block); + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, task->function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_ptr_arr, master_common_block); LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); - LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_arr, symbol_arr); + LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr); // fill out obj obj->data = input->data; @@ -432,7 +436,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) obj->sect_count = coff_info.section_count_no_null; obj->sect_name_arr = sect_name_arr; obj->sect_sort_arr = sect_sort_arr; - obj->chunk_arr = chunk_arr; + obj->chunk_arr = chunk_ptr_arr; obj->symbol_list = symbol_list; obj->sect_reloc_list_arr = reloc_list_arr; obj->directive_info = lnk_init_directives(arena, cached_path, coff_info.section_count_no_null, sect_name_arr, chunk_arr); @@ -478,7 +482,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_new_sect_scanner) for (U64 chunk_idx = 0; chunk_idx < obj->chunk_count; chunk_idx += 1) { String8 sect_name = obj->sect_name_arr[chunk_idx]; - COFF_SectionFlags sect_flags = obj->chunk_arr[chunk_idx].flags & ~COFF_SectionFlags_LNK_FLAGS; + COFF_SectionFlags sect_flags = obj->chunk_arr[chunk_idx]->flags & ~COFF_SectionFlags_LNK_FLAGS; KeyValuePair *is_present = hash_table_search_string(ht, sect_name); if (is_present) { @@ -511,8 +515,8 @@ THREAD_POOL_TASK_FUNC(lnk_chunk_counter) LNK_Obj *obj = &task->obj_arr[obj_idx].data; for (U64 chunk_idx = 0; chunk_idx < obj->chunk_count; chunk_idx += 1) { String8 name = obj->sect_name_arr[chunk_idx]; - LNK_Chunk *chunk = &obj->chunk_arr[chunk_idx]; - LNK_Section *sect = lnk_section_table_search(task->st, name); + LNK_Chunk *chunk = obj->chunk_arr[chunk_idx]; + LNK_Section *sect = lnk_section_table_search(task->st, name); U64 count = 0; lnk_visit_chunks(0, chunk, lnk_chunk_get_count_cb, &count); @@ -549,7 +553,7 @@ THREAD_POOL_TASK_FUNC(lnk_chunk_ref_assigner) for (U64 chunk_idx = 0; chunk_idx < obj->chunk_count; chunk_idx += 1) { String8 name = obj->sect_name_arr[chunk_idx]; String8 sort = obj->sect_sort_arr[chunk_idx]; - LNK_Chunk *chunk = &obj->chunk_arr[chunk_idx]; + LNK_Chunk *chunk = obj->chunk_arr[chunk_idx]; // :find_chunk_section LNK_Section *sect = lnk_section_table_search(task->st, name); @@ -570,7 +574,7 @@ THREAD_POOL_TASK_FUNC(lnk_chunk_ref_assigner) } internal LNK_ObjNodeArray -lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 input_count, LNK_InputObj **inputs) +lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 function_pad_min, U64 input_count, LNK_InputObj **inputs) { ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); @@ -580,10 +584,11 @@ lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_lis ProfBegin("Obj Initer"); { - LNK_ObjIniter task = {0}; - task.inputs = inputs; - task.obj_id_base = obj_id_base; - task.obj_node_arr = obj_arr.v; + LNK_ObjIniter task = {0}; + task.inputs = inputs; + task.obj_id_base = obj_id_base; + task.obj_node_arr = obj_arr.v; + task.function_pad_min = function_pad_min; tp_for_parallel(tp, arena, input_count, lnk_obj_initer, &task); } ProfEnd(); @@ -717,20 +722,19 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, + U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, - LNK_Chunk *chunk_arr, + LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block) { - LNK_SymbolList weak_symbol_list = {0}; - - LNK_SymbolArray symbol_array = {0}; - symbol_array.count = coff_symbols.count; - symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); + LNK_SymbolArray symbol_array; + symbol_array.count = coff_symbols.count; + symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); - for (U64 symbol_idx = 0; symbol_idx < coff_symbols.count; symbol_idx += 1) { + for (U64 symbol_idx = 0; symbol_idx < coff_symbols.count; ++symbol_idx) { COFF_Symbol32 *coff_symbol = &coff_symbols.v[symbol_idx]; LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; @@ -751,22 +755,32 @@ lnk_symbol_array_from_coff(Arena *arena, break; } + COFF_SectionHeader *coff_sect_header = &coff_sect_arr[coff_symbol->section_number - 1]; + + if (coff_symbol->value > coff_sect_header->fsize) { + lnk_error(LNK_Error_IllData, "%S: out of bounds section offset in symbol \"%S (%u)\"", obj_path, name, coff_symbol->value); + break; + } + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; if (coff_symbol->storage_class == COFF_SymStorageClass_EXTERNAL) { visibility = LNK_DefinedSymbolVisibility_Extern; } - + LNK_DefinedSymbolFlags flags = 0; - if (coff_symbol->type.u.lsb == COFF_SymType_NULL && coff_symbol->type.u.msb == COFF_SymDType_FUNC) { + if (coff_symbol->type.u.lsb == COFF_SymType_NULL && + coff_symbol->type.u.msb == COFF_SymDType_FUNC && + (coff_sect_header->flags & COFF_SectionFlag_CNT_CODE)) { flags |= LNK_DefinedSymbolFlag_IsFunc; } - - COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; - U64 check_sum = 0; - { - B32 is_comdat = !!(coff_sect_arr[coff_symbol->section_number - 1].flags & COFF_SectionFlag_LNK_COMDAT); - B32 has_static_def = is_comdat && - coff_symbol->value == 0 && + + LNK_Chunk *chunk = chunk_ptr_arr[coff_symbol->section_number-1]; + U64 offset = coff_symbol->value; + COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; + U64 check_sum = 0; + + if (coff_sect_header->flags & COFF_SectionFlag_LNK_COMDAT) { + B32 has_static_def = coff_symbol->value == 0 && coff_symbol->type.u.lsb == COFF_SymType_NULL && coff_symbol->storage_class == COFF_SymStorageClass_STATIC && coff_symbol->aux_symbol_count == 1; @@ -786,15 +800,122 @@ lnk_symbol_array_from_coff(Arena *arena, break; } - LNK_Chunk *head_chunk = &chunk_arr[secdef_number - 1]; - LNK_Chunk *associate_chunk = &chunk_arr[coff_symbol->section_number - 1]; + LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1]; + LNK_Chunk *associate_chunk = chunk_ptr_arr[coff_symbol->section_number-1]; + Assert(head_chunk->type == LNK_Chunk_Leaf); + Assert(associate_chunk->type == LNK_Chunk_Leaf); lnk_chunk_associate(arena, head_chunk, associate_chunk); } } } - - LNK_Chunk *chunk = &chunk_arr[coff_symbol->section_number - 1]; - U64 offset = coff_symbol->value; + + if (function_pad_min) { + if ((flags & LNK_DefinedSymbolFlag_IsFunc)) { + if (offset > 0) { + // convert leaf to list chunk + // + // there is no way to know up front how many splits we have, + // so lazily convert chunks when see two or more functions + // in a section + if (chunk->type == LNK_Chunk_Leaf) { + // make a list chunk + LNK_Chunk *chunk_list = push_array(arena, LNK_Chunk, 1); + chunk_list->align = chunk->align; + chunk_list->is_discarded = chunk->is_discarded; + chunk_list->type = LNK_Chunk_List; + chunk_list->sort_idx = chunk->sort_idx; + chunk_list->sort_chunk = 0; + chunk_list->input_idx = chunk->input_idx; + chunk_list->flags = chunk->flags; + chunk_list->associate = chunk->associate; + chunk_list->u.list = push_array(arena, LNK_ChunkList, 1); + + // reset chunk properties + chunk->align = 1; + chunk->min_size = function_pad_min; + chunk->sort_chunk = 0; + chunk->sort_idx = str8_zero(); + chunk->input_idx = 0; + chunk->associate = 0; + + // push leaf to list + lnk_chunk_list_push(arena, chunk_list->u.list, chunk); + + // set list as target chunk + chunk = chunk_list; + + // set list chunk to be head of this section + chunk_ptr_arr[coff_symbol->section_number-1] = chunk_list; + } + + // find chunk that is near symbol + U64 cursor = 0; + LNK_ChunkNode *current = chunk->u.list->last; + for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { + Assert(c->data->type == LNK_Chunk_Leaf); + if (cursor + c->data->u.leaf.size > coff_symbol->value) { + current = c; + break; + } + cursor += c->data->u.leaf.size; + } + + if (cursor < coff_symbol->value) { + // bifurcate chunk at symbol offset + U64 split_pos = coff_symbol->value - cursor; + Rng1U64 left_data_range = rng_1u64(0, split_pos); + Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size); + String8 left_data = str8_substr(current->data->u.leaf, left_data_range); + String8 right_data = str8_substr(current->data->u.leaf, right_data_range); + + // create new chunk for new part + LNK_Chunk *split_chunk = push_array(arena, LNK_Chunk, 1); + split_chunk->align = 1; + split_chunk->is_discarded = current->data->is_discarded; + split_chunk->type = LNK_Chunk_Leaf; + split_chunk->flags = current->data->flags; + split_chunk->u.leaf = right_data; + + LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1); + split_node->data = split_chunk; + + // update split chunk data + current->data->u.leaf = left_data; + + // insert split chunk after current chunk + split_node->next = current->next; + current->next = split_node; + chunk->u.list->count += 1; + + // point symbol to new split chunk + chunk = split_chunk; + offset = 0; + } else { + // chunk was already split at the offset + chunk = current->data; + offset = coff_symbol->value - cursor; + } + } + + chunk->min_size = function_pad_min; + } + + // if symbol points to bifurcated section then we have an alias symbol (e.g. memmove is an alias to memcpy) + // and we need to find chunk that is near symbol + if (chunk->type == LNK_Chunk_List) { + U64 cursor = 0; + for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { + if (cursor + c->data->u.leaf.size > coff_symbol->value) { + chunk = c->data; + offset = offset - cursor; + break; + } + cursor += c->data->u.leaf.size; + } + } + } + + Assert(chunk->type == LNK_Chunk_Leaf); lnk_init_defined_symbol_chunk(symbol, name, visibility, flags, chunk, offset, selection, check_sum); } break; case COFF_SymbolValueInterp_UNDEFINED: { @@ -805,6 +926,7 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_Chunk *chunk = push_array_no_zero(arena, LNK_Chunk, 1); chunk->ref = lnk_chunk_ref(0,0); // :chunk_ref_assign chunk->align = 1; + chunk->min_size = 0; chunk->is_discarded = 0; chunk->sort_chunk = 1; chunk->type = LNK_Chunk_Leaf; @@ -845,8 +967,6 @@ lnk_symbol_array_from_coff(Arena *arena, #endif lnk_init_weak_symbol(symbol, name, weak_ext->characteristics, &symbol_array.v[weak_ext->tag_index]); - - lnk_symbol_list_push(arena, &weak_symbol_list, symbol); } break; case COFF_SymbolValueInterp_ABS: { // Never code or data, synthetic symbol. COFF spec says bits in value are used @@ -873,14 +993,14 @@ lnk_symbol_array_from_coff(Arena *arena, } internal LNK_RelocList * -lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_Chunk *chunk_arr, LNK_SymbolArray symbol_array) +lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array) { LNK_RelocList *reloc_list_arr = push_array_no_zero(arena, LNK_RelocList, sect_count); - for (U64 sect_idx = 0; sect_idx < sect_count; sect_idx += 1) { + for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) { COFF_SectionHeader *coff_header = &coff_sect_arr[sect_idx]; COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, coff_header); COFF_Reloc *coff_reloc_v = (COFF_Reloc *)(coff_data.str + coff_reloc_info.array_off); - LNK_Chunk *sect_chunk = &chunk_arr[sect_idx]; + LNK_Chunk *sect_chunk = chunk_ptr_arr[sect_idx]; reloc_list_arr[sect_idx] = lnk_reloc_list_from_coff_reloc_array(arena, machine, sect_chunk, symbol_array, coff_reloc_v, coff_reloc_info.count); } return reloc_list_arr; diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index a27b46e8..3c27d3a7 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -40,7 +40,7 @@ typedef struct LNK_Obj String8 *sect_name_arr; String8 *sect_sort_arr; LNK_RelocList *sect_reloc_list_arr; - LNK_Chunk *chunk_arr; + LNK_ChunkPtr *chunk_arr; LNK_SymbolList symbol_list; LNK_DirectiveInfo directive_info; LNK_ExportParseList export_parse; @@ -92,6 +92,7 @@ typedef struct U64 obj_id_base; LNK_SectDefnList *defn_arr; LNK_SectionTable *st; + U64 function_pad_min; } LNK_ObjIniter; typedef struct @@ -177,12 +178,12 @@ internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, Stri internal LNK_Obj ** lnk_obj_arr_from_list(Arena *arena, LNK_ObjList list); internal LNK_ObjNodeArray lnk_obj_list_reserve(Arena *arena, LNK_ObjList *list, U64 count); internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8 name, String8 postfix, B32 collect_discarded); -internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 input_count, LNK_InputObj **inputs); +internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 function_pad_min, U64 input_count, LNK_InputObj **inputs); internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr); -internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block); +internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block); internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count); -internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_Chunk *sect_chunk_arr, LNK_SymbolArray symbol_array); +internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array); internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr); internal U32 lnk_obj_get_features(LNK_Obj *obj); diff --git a/src/linker/lnk_reloc.c b/src/linker/lnk_reloc.c index e22c31d4..779234ab 100644 --- a/src/linker/lnk_reloc.c +++ b/src/linker/lnk_reloc.c @@ -64,16 +64,36 @@ internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count) { LNK_RelocList reloc_list = {0}; - LNK_Reloc *reloc_arr = lnk_reloc_list_reserve(arena, &reloc_list, reloc_count); - LNK_Reloc *reloc_ptr = reloc_arr; - LNK_Reloc *reloc_opl = reloc_arr + reloc_count; + + LNK_Reloc *reloc_arr = lnk_reloc_list_reserve(arena, &reloc_list, reloc_count); + LNK_Reloc *reloc_ptr = reloc_arr; + LNK_Reloc *reloc_opl = reloc_arr + reloc_count; COFF_Reloc *coff_reloc_ptr = reloc_v; - for (; reloc_ptr < reloc_opl; reloc_ptr += 1, coff_reloc_ptr += 1) { + + for (; reloc_ptr < reloc_opl; ++reloc_ptr, ++coff_reloc_ptr) { + LNK_RelocType type = lnk_ext_reloc_type_from_coff(machine, coff_reloc_ptr->type); + LNK_Chunk *reloc_chunk = chunk; + U64 apply_off = coff_reloc_ptr->apply_off; + LNK_Symbol *symbol = symbol_array.v + coff_reloc_ptr->isymbol; + + if (chunk->type == LNK_Chunk_List) { + U64 cursor = 0; + for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { + Assert(c->data->type == LNK_Chunk_Leaf); + if (coff_reloc_ptr->apply_off < cursor + c->data->u.leaf.size) { + reloc_chunk = c->data; + apply_off = coff_reloc_ptr->apply_off - cursor; + break; + } + cursor += c->data->u.leaf.size; + } + } + Assert(coff_reloc_ptr->isymbol < symbol_array.count); - reloc_ptr->chunk = chunk; - reloc_ptr->type = lnk_ext_reloc_type_from_coff(machine, coff_reloc_ptr->type); - reloc_ptr->apply_off = coff_reloc_ptr->apply_off; - reloc_ptr->symbol = symbol_array.v + coff_reloc_ptr->isymbol; + reloc_ptr->chunk = reloc_chunk; + reloc_ptr->type = type; + reloc_ptr->apply_off = apply_off; + reloc_ptr->symbol = symbol; } return reloc_list; } diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 8e05261c..422008cf 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -259,8 +259,8 @@ lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine) 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.pad_array_count = 0; + sect->layout.pad_array = 0; } sect->is_loose = 0; }