diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e6a3d845..f094c978 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -39,6 +39,7 @@ #include "pe/pe.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" +#include "codeview/codeview_enum.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" @@ -51,6 +52,7 @@ #include "coff/coff_enum.c" #include "pe/pe.c" #include "codeview/codeview.c" +#include "codeview/codeview_enum.c" #include "codeview/codeview_parse.c" #include "msf/msf.c" #include "msf/msf_parse.c" @@ -1824,11 +1826,20 @@ lnk_base_reloc_page_is_before(void *raw_a, void *raw_b) return a->voff < b->voff; } +int +lnk_base_reloc_page_compar(const void *raw_a, const void *raw_b) +{ + const LNK_BaseRelocPage *a = raw_a; + const LNK_BaseRelocPage *b = raw_b; + return u64_compar(&a->voff, &b->voff); +} + internal void lnk_base_reloc_page_array_sort(LNK_BaseRelocPageArray arr) { ProfBeginFunction(); - radsort(arr.v, arr.count, lnk_base_reloc_page_is_before); + //radsort(arr.v, arr.count, lnk_base_reloc_page_is_before); + qsort(arr.v, arr.count, sizeof(arr.v[0]), lnk_base_reloc_page_compar); ProfEnd(); } @@ -1927,7 +1938,7 @@ lnk_build_base_relocs(TP_Context *tp, ProfBegin("Page List -> Array"); LNK_BaseRelocPageArray page_arr = lnk_base_reloc_page_array_from_list(base_reloc_sect->arena, *main_page_list); ProfEnd(); - + ProfBegin("Sort Pages on VOFF"); lnk_base_reloc_page_array_sort(page_arr); ProfEnd(); @@ -3634,7 +3645,7 @@ lnk_run(int argc, char **argv) } for (U64 input_source = 0; input_source < ArrayCount(input_libs); ++input_source) { - ProfBeginV("Source %S", lnk_string_from_input_source(input_source)); + ProfBeginV("Input Source %S", lnk_string_from_input_source(input_source)); Temp temp = temp_begin(scratch.arena); LNK_InputLibList input_lib_list = input_libs[input_source]; @@ -3716,6 +3727,7 @@ lnk_run(int argc, char **argv) } temp_end(temp); + ProfEnd(); } // reset input libs diff --git a/src/linker/lnk_chunk.c b/src/linker/lnk_chunk.c index b1f99fb3..c35e4b73 100644 --- a/src/linker/lnk_chunk.c +++ b/src/linker/lnk_chunk.c @@ -302,13 +302,20 @@ lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_C return src_node; } +internal +LNK_CHUNK_VISITOR_SIG(lnk_set_associate_on_chunks) +{ + chunk->associate = (LNK_Chunk *)ud; + return 0; +} + internal void -lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *chunk) +lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *chunk) { // for simplicity we don't support multiple associations, // but it's possible to craft symbol table with multiple associations - Assert(!chunk->associate); - chunk->associate = head; + AssertAlways(!chunk->associate); + lnk_visit_chunks(0, chunk, lnk_set_associate_on_chunks, head); } internal B32 diff --git a/src/linker/lnk_chunk.h b/src/linker/lnk_chunk.h index e8313b98..0b64d968 100644 --- a/src/linker/lnk_chunk.h +++ b/src/linker/lnk_chunk.h @@ -175,7 +175,7 @@ internal LNK_Chunk * lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager * internal LNK_Chunk * lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index); internal LNK_ChunkNode * lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk); internal LNK_ChunkNode * lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max); -internal void lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *associate); +internal void lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *associate); internal B32 lnk_chunk_is_discarded(LNK_Chunk *chunk); internal U64 lnk_chunk_get_size(LNK_Chunk *chunk); internal U64 lnk_chunk_list_get_node_count(LNK_Chunk *chunk); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 03265995..c018b5ab 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -357,7 +357,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) 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); + LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, chunk_count); // :common_block U64 common_block_idx = chunk_count - 1; @@ -402,16 +402,13 @@ 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; chunk->sort_idx = sect_sort_arr[sect_idx]; chunk->input_idx = LNK_MakeChunkInputIdx(obj_idx, sect_idx); chunk->flags = coff_sect->flags; - chunk->associate = 0; chunk->u.leaf = data; 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); } @@ -437,7 +434,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // 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, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, cached_lib_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, 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_ptr_arr, symbol_arr); LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, cached_path, cached_lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr); @@ -740,9 +737,10 @@ lnk_obj_list_push_parallel(TP_Context *tp, internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, - String8 coff_data, + String8 raw_coff, LNK_Obj *obj, String8 obj_path, + String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, @@ -753,282 +751,270 @@ lnk_symbol_array_from_coff(Arena *arena, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block) { - LNK_SymbolArray symbol_array; - symbol_array.count = coff_symbol_count; - symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); - - for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; ++symbol_idx) { - String8 name; - U32 section_number; - U32 value; - COFF_SymStorageClass storage_class; - COFF_SymbolType type; - U64 aux_symbol_count; - void *aux_symbols; + if (function_pad_min) { + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + // read symbol + if (is_big_obj) { + symbol = coff_parse_symbol32(raw_coff, string_table_off, &((COFF_Symbol32 *)coff_symbols)[symbol_idx]); + } else { + symbol = coff_parse_symbol16(raw_coff, string_table_off, &((COFF_Symbol16 *)coff_symbols)[symbol_idx]); + } + + // is this a function symbol? + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_REGULAR && COFF_SymbolType_IsFunc(symbol.type)) { + if (symbol.section_number == 0 || symbol.section_number > sect_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number); + } + if (symbol.value > coff_sect_arr[symbol.section_number-1].fsize) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, symbol.value); + } + + LNK_Chunk *chunk = chunk_ptr_arr[symbol.section_number-1]; + if (symbol.value > 0) { + // convert leaf to list + // + // 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->type = LNK_Chunk_List; + chunk_list->align = chunk->align; + chunk_list->is_discarded = chunk->is_discarded; + chunk_list->sort_idx = chunk->sort_idx; + chunk_list->input_idx = chunk->input_idx; + chunk_list->flags = chunk->flags; + chunk_list->u.list = push_array(arena, LNK_ChunkList, 1); + lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, symbol.name); + + // update properties on first chunk + chunk->min_size = function_pad_min; + chunk->sort_chunk = 0; + chunk->sort_idx = str8_zero(); + chunk->input_idx = 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[symbol.section_number-1] = chunk_list; + } + + // find chunk that is near symbol + U64 offset_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 (offset_cursor + c->data->u.leaf.size >= symbol.value) { + current = c; + break; + } + offset_cursor += c->data->u.leaf.size; + } + Assert(current->data->type == LNK_Chunk_Leaf); + + if (offset_cursor < symbol.value) { + // bifurcate chunk at symbol offset + U64 split_pos = symbol.value - offset_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 + LNK_Chunk *split_chunk = push_array(arena, LNK_Chunk, 1); + split_chunk->type = LNK_Chunk_Leaf; + split_chunk->align = current->data->align; + split_chunk->min_size = function_pad_min; + split_chunk->is_discarded = current->data->is_discarded; + split_chunk->flags = current->data->flags; + split_chunk->u.leaf = right_data; + lnk_chunk_set_debugf(arena, split_chunk, "%S: chunk split on function %S SECT%x SPLIT_POS %#llx", obj_path, symbol.name, symbol.section_number, split_pos); + + 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 + if (split_node->next == 0) { + chunk->u.list->last = split_node; + } + split_node->next = current->next; + current->next = split_node; + chunk->u.list->count += 1; + } + } + } + } + } + + LNK_SymbolArray symbol_array = {0}; + symbol_array.count = coff_symbol_count; + symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); + + COFF_ParsedSymbol parsed_symbol; + for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + parsed_symbol.aux_symbol_count)) { + void *aux_symbols; if (is_big_obj) { - COFF_Symbol32 *coff_symbol32 = (COFF_Symbol32 *)coff_symbols + symbol_idx; - name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol32->name); - section_number = coff_symbol32->section_number; - value = coff_symbol32->value; - storage_class = coff_symbol32->storage_class; - type = coff_symbol32->type; - aux_symbol_count = coff_symbol32->aux_symbol_count; - aux_symbols = coff_symbol32 + 1; + COFF_Symbol32 *ptr = &((COFF_Symbol32 *)coff_symbols)[symbol_idx]; + parsed_symbol = coff_parse_symbol32(raw_coff, string_table_off, ptr); + aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; } else { - COFF_Symbol16 *coff_symbol16 = (COFF_Symbol16 *)coff_symbols + symbol_idx; - name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol16->name); - section_number = coff_symbol16->section_number; - value = coff_symbol16->value; - storage_class = coff_symbol16->storage_class; - type = coff_symbol16->type; - aux_symbol_count = coff_symbol16->aux_symbol_count; - aux_symbols = coff_symbol16 + 1; - - // promote special section numbers to 32 bit - if (section_number == COFF_SYMBOL_DEBUG_SECTION_16) { - section_number = COFF_SYMBOL_DEBUG_SECTION; - } else if (section_number == COFF_SYMBOL_ABS_SECTION_16) { - section_number = COFF_SYMBOL_ABS_SECTION; - } + COFF_Symbol16 *ptr = (COFF_Symbol16 *)coff_symbols + symbol_idx; + parsed_symbol = coff_parse_symbol16(raw_coff, string_table_off, ptr); + aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; } - if (symbol_idx + aux_symbol_count + 1 > coff_symbol_count) { - lnk_error(LNK_Error_IllData, "%S: symbol %S has out of bounds aux symbol count %u", obj_path, name, aux_symbol_count); + if (symbol_idx + parsed_symbol.aux_symbol_count + 1 > coff_symbol_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds aux symbol count %llu", parsed_symbol.name, symbol_idx, parsed_symbol.aux_symbol_count); } - COFF_SymbolValueInterpType interp = coff_interp_symbol(section_number, value, storage_class); + COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); switch (interp) { - case COFF_SymbolValueInterp_REGULAR: { - if (section_number == 0 || section_number > sect_count) { - lnk_error(LNK_Error_IllData, "%S: out ouf bounds section index in symbol \"%S (%u)\"", obj_path, name, section_number); - break; - } + case COFF_SymbolValueInterp_REGULAR: { + if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number); + } + if (parsed_symbol.value > coff_sect_arr[parsed_symbol.section_number-1].fsize) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, parsed_symbol.value, parsed_symbol.section_number); + } - COFF_SectionHeader *coff_sect_header = &coff_sect_arr[section_number-1]; - if (value > coff_sect_header->fsize) { - lnk_error(LNK_Error_IllData, "%S: out of bounds section offset in symbol \"%S (%u)\"", obj_path, name, value); - break; - } + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; + if (parsed_symbol.storage_class == COFF_SymStorageClass_EXTERNAL) { + visibility = LNK_DefinedSymbolVisibility_Extern; + } + LNK_DefinedSymbolFlags flags = 0; + if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { + flags |= LNK_DefinedSymbolFlag_IsFunc; + } - LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (storage_class == COFF_SymStorageClass_EXTERNAL) { - visibility = LNK_DefinedSymbolVisibility_Extern; - } - LNK_DefinedSymbolFlags flags = 0; - if (COFF_SymbolType_IsFunc(type)) { - flags |= LNK_DefinedSymbolFlag_IsFunc; - } + LNK_Chunk *chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; + U64 offset = parsed_symbol.value; + COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; + U64 check_sum = 0; - LNK_Chunk *chunk = chunk_ptr_arr[section_number-1]; - U64 offset = value; - COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY; - U64 check_sum = 0; - if (coff_sect_header->flags & COFF_SectionFlag_LNK_COMDAT) { - B32 has_static_def = value == 0 && - type.u.lsb == COFF_SymType_NULL && - storage_class == COFF_SymStorageClass_STATIC && - aux_symbol_count == 1; - if (has_static_def) { + B32 is_comdat = (coff_sect_arr[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LNK_COMDAT) && + parsed_symbol.value == 0 && + parsed_symbol.aux_symbol_count > 0 && + parsed_symbol.type.u.lsb == COFF_SymType_NULL && + parsed_symbol.storage_class == COFF_SymStorageClass_STATIC; + if (is_comdat) { COFF_SymbolSecDef *secdef = aux_symbols; selection = secdef->selection; check_sum = secdef->check_sum; - + + // create association link between chunks if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) { U32 secdef_number = secdef->number_lo; + + // promote secdef number to 32 bits if (is_big_obj) { secdef_number |= (U32)secdef->number_hi << 16; } - if (secdef_number == 0 || secdef_number > sect_count) { - lnk_error(LNK_Error_IllData, "%S: symbol %u has out of bounds section definition number %u", name, symbol_idx, secdef_number); - } - - LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1]; - LNK_Chunk *associate_chunk = chunk_ptr_arr[section_number-1]; - lnk_chunk_associate(arena, head_chunk, associate_chunk); - } - } - } - - if (function_pad_min) { - if ((flags & LNK_DefinedSymbolFlag_IsFunc)) { - if (offset > 0) { - // convert leaf to list - // - // 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->type = LNK_Chunk_List; - chunk_list->align = chunk->align; - chunk_list->is_discarded = chunk->is_discarded; - chunk_list->sort_idx = chunk->sort_idx; - 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); - lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, name); - - // 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[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 > value) { - current = c; - break; - } - cursor += c->data->u.leaf.size; - } - - if (cursor < value) { - // bifurcate chunk at symbol offset - U64 split_pos = 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_chunk_set_debugf(arena, chunk, "%S: chunk split on function %S", obj_path, name); - - 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; + // associate chunks + if (secdef_number > 0 && secdef_number <= sect_count) { + LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1]; + LNK_Chunk *associate_chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; + lnk_chunk_associate(head_chunk, associate_chunk); } else { - // chunk was already split at the offset - chunk = current->data; - offset = value - cursor; + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number); } } - - 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; + LNK_Chunk *closest_chunk = chunk->u.list->last->data; + U64 offset_cursor = 0; for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) { - if (cursor + c->data->u.leaf.size > value) { - chunk = c->data; - offset = offset - cursor; + if (offset_cursor + c->data->u.leaf.size > offset) { + closest_chunk = c->data; break; } - cursor += c->data->u.leaf.size; + offset_cursor += c->data->u.leaf.size; } + Assert(offset >= offset_cursor); + offset -= offset_cursor; + chunk = closest_chunk; } - } + Assert(chunk->type == LNK_Chunk_Leaf); - Assert(chunk->type == LNK_Chunk_Leaf); - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_chunk(symbol, name, visibility, flags, chunk, offset, selection, check_sum); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_WEAK: { - if (aux_symbol_count == 0) { - lnk_error(LNK_Error_IllData, "%S: Weak symbol \"%S (%u)\" must at least one aux symbol", obj_path, name, symbol_idx); - } - - COFF_SymbolWeakExt *weak_ext = aux_symbols; - if (weak_ext->tag_index >= coff_symbol_count) { - lnk_error(LNK_Error_IllData, "%S: Weak symbol \"%S (%u)\" points to out of bounds symbol", obj_path, name, symbol_idx); - break; - } + lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, offset, selection, check_sum); + symbol_array.v[symbol_idx].obj = obj; + } break; + case COFF_SymbolValueInterp_WEAK: { + if (parsed_symbol.aux_symbol_count == 0) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx); + } + + COFF_SymbolWeakExt *weak_ext = aux_symbols; + if (weak_ext->tag_index >= coff_symbol_count) { + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx); + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index]; - lnk_init_weak_symbol(symbol, name, weak_ext->characteristics, fallback_symbol); + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index]; + lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol); - symbol->obj = obj; - fallback_symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_UNDEFINED: { - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_undefined_symbol(symbol, name, LNK_SymbolScopeFlag_Main); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_COMMON: { - // :common_block - // - // TODO: sort chunks on size to reduce bss usage - LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1); - chunk->align = Min(32, u64_up_to_pow2(value)); // link.exe caps align at 32 bytes - chunk->type = LNK_Chunk_Leaf; - chunk->flags = master_common_block->flags; - chunk->u.leaf = str8(0, value); - lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, name); - lnk_chunk_list_push(arena, master_common_block->u.list, chunk); + symbol->obj = obj; + fallback_symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_UNDEFINED: { + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_COMMON: { + // :common_block + // + // TODO: sort chunks on size to reduce bss usage + LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1); + chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes + chunk->type = LNK_Chunk_Leaf; + chunk->flags = master_common_block->flags; + chunk->u.leaf = str8(0, parsed_symbol.value); + lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, parsed_symbol.name); + lnk_chunk_list_push(arena, master_common_block->u.list, chunk); - LNK_DefinedSymbolFlags flags = 0; - if (COFF_SymbolType_IsFunc(type)) { - flags |= LNK_DefinedSymbolFlag_IsFunc; - } + LNK_DefinedSymbolFlags flags = 0; + if (COFF_SymbolType_IsFunc(parsed_symbol.type)) { + flags |= LNK_DefinedSymbolFlag_IsFunc; + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_chunk(symbol, name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelectType_LARGEST, 0); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_ABS: { - // Never code or data, synthetic symbol. COFF spec says bits in value are used - // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. - // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelectType_LARGEST, 0); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_ABS: { + // Never code or data, synthetic symbol. COFF spec says bits in value are used + // as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented. + // LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf. - LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; - if (storage_class == COFF_SymStorageClass_EXTERNAL) { - visibility = LNK_DefinedSymbolVisibility_Extern; - } + LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static; + if (parsed_symbol.storage_class == COFF_SymStorageClass_EXTERNAL) { + visibility = LNK_DefinedSymbolVisibility_Extern; + } - LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_init_defined_symbol_va(symbol, name, visibility, 0, value); - symbol->obj = obj; - } break; - case COFF_SymbolValueInterp_DEBUG: break; + LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; + lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value); + symbol->obj = obj; + } break; + case COFF_SymbolValueInterp_DEBUG: { + } break; } - - // skip aux symbols - symbol_idx += aux_symbol_count; } return symbol_array; @@ -1084,7 +1070,7 @@ lnk_parse_msvc_linker_directive(Arena *arena, String8 obj_path, String8 lib_path local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 }; if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) { to_parse = str8_zero(); - lnk_error_with_loc(LNK_InternalError_NotImplemented, obj_path, lib_path, "TODO: support for BOM encoding"); + lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "TODO: support for BOM encoding"); } else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) { to_parse = str8_skip(buffer, sizeof(ascii_sig)); } else { diff --git a/src/linker/lnk_reloc.c b/src/linker/lnk_reloc.c index 779234ab..0c52820d 100644 --- a/src/linker/lnk_reloc.c +++ b/src/linker/lnk_reloc.c @@ -77,18 +77,20 @@ lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK LNK_Symbol *symbol = symbol_array.v + coff_reloc_ptr->isymbol; if (chunk->type == LNK_Chunk_List) { + reloc_chunk = chunk->u.list->last->data; 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; } + apply_off = coff_reloc_ptr->apply_off - cursor; } + Assert(reloc_chunk->type == LNK_Chunk_Leaf); Assert(coff_reloc_ptr->isymbol < symbol_array.count); reloc_ptr->chunk = reloc_chunk; reloc_ptr->type = type; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 422008cf..e2412459 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -145,7 +145,7 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, internal void lnk_section_associate_chunks(LNK_Section *sect, LNK_Chunk *head, LNK_Chunk *associate) { - lnk_chunk_associate(sect->arena, head, associate); + lnk_chunk_associate(head, associate); } internal LNK_Chunk * diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 19a87ca2..2fbf706b 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -2164,7 +2164,7 @@ gsi_write_build_result(TP_Context *tp, msf_stream_write(msf, gsi_sn, &build.bitmap[0], bitmap_size); ProfEnd(); - ProfBegin("Write buckets [%M]", compressed_bucket_arr-size); + ProfBegin("Write buckets [%M]", compressed_bucket_arr_size); msf_stream_write(msf, gsi_sn, &build.compressed_bucket_arr[0], compressed_bucket_arr_size); ProfEnd();