factored out logic for splitting function chunks into separate pass

over symbol table; associations are now assigned to sub chunks too;
inherit function chunk align from parent chunk
This commit is contained in:
Nikita Smith
2025-01-16 13:46:47 -08:00
parent c000817b9a
commit b405ed4873
7 changed files with 258 additions and 251 deletions
+15 -3
View File
@@ -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
+10 -3
View File
@@ -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
+1 -1
View File
@@ -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);
+227 -241
View File
@@ -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 {
+3 -1
View File
@@ -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;
+1 -1
View File
@@ -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 *
+1 -1
View File
@@ -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();