handle /ALTERNATENAME directive

This commit is contained in:
Nikita Smith
2025-05-18 18:04:24 -07:00
committed by Ryan Fleury
parent 60d3f25057
commit 73fe9d223a
13 changed files with 142 additions and 99 deletions
+4 -4
View File
@@ -174,11 +174,11 @@ coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x)
internal COFF_RelocValue
coff_pick_reloc_value_x64(COFF_Reloc_X64 type,
U64 image_base,
U64 reloc_virtual_offset,
U32 symbol_section_number,
U32 symbol_section_offset,
U32 symbol_virtual_offset,
U64 symbol_address)
U32 symbol_virtual_offset)
{
U64 reloc_value_size = 0;
S64 reloc_value = 0;
@@ -187,11 +187,11 @@ coff_pick_reloc_value_x64(COFF_Reloc_X64 type,
case COFF_Reloc_X64_Abs: {} break;
case COFF_Reloc_X64_Addr64: {
reloc_value_size = 8;
reloc_value = symbol_address;
reloc_value = symbol_virtual_offset + image_base;
} break;
case COFF_Reloc_X64_Addr32: {
reloc_value_size = 4;
reloc_value = symbol_address;
reloc_value = symbol_virtual_offset + image_base;
} break;
case COFF_Reloc_X64_Addr32Nb: {
reloc_value_size = 4;
+1 -1
View File
@@ -602,7 +602,7 @@ internal String8 coff_read_symbol_name(String8 string_table, COFF_SymbolName *na
internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x);
internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x);
internal COFF_RelocValue coff_pick_reloc_value_x64(COFF_Reloc_X64 type, U64 reloc_virtual_offset, U32 symbol_section_number, U32 symbol_section_offset, U32 symbol_virtual_offset, U64 symbol_address);
internal COFF_RelocValue coff_pick_reloc_value_x64(COFF_Reloc_X64 type, U64 image_base, U64 reloc_virtual_offset, U32 symbol_section_number, U32 symbol_section_offset, U32 symbol_virtual_offset);
////////////////////////////////
// Import
+13 -7
View File
@@ -237,13 +237,6 @@ hash_table_search_path_raw(HashTable *ht, String8 path)
return kv ? kv->value_raw : 0;
}
internal void *
hash_table_(HashTable *ht, String8 path)
{
KeyValuePair *result = hash_table_search_path(ht, path);
return result ? result->value_raw : 0;
}
internal B32
hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out)
{
@@ -283,6 +276,19 @@ hash_table_search_string_raw(HashTable *ht, String8 key, void *value_out)
return 0;
}
internal B32
hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out)
{
KeyValuePair *result = hash_table_search_string(ht, key);
if (result) {
if (value_out) {
*value_out = result->value_string;
}
return 1;
}
return 0;
}
////////////////////////////////
internal int
+3
View File
@@ -74,6 +74,9 @@ internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 path
internal void * hash_table_search_path_raw(HashTable *ht, String8 path );
internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out);
internal B32 hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out);
internal B32 hash_table_search_string_raw(HashTable *ht, String8 key, void *value_out);
internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out);
//- key-value helpers
+55 -51
View File
@@ -1102,14 +1102,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
COFF_Reloc *reloc = &relocs[reloc_idx];
// compute relocation file/virtual offsets
U64 reloc_file_offset = section_header->foff + reloc->apply_off;
U64 reloc_virtual_offset = section_header->voff + reloc->apply_off;
U64 reloc_foff = section_header->foff + reloc->apply_off;
U64 reloc_voff = section_header->voff + reloc->apply_off;
// compute symbol location values
U32 symbol_section_number = 0;
U32 symbol_section_offset = 0;
U32 symbol_virtual_offset = 0;
U64 symbol_address = 0;
U32 symbol_secnum = 0;
U32 symbol_secoff = 0;
U32 symbol_voff = 0;
{
COFF_ParsedSymbol symbol;
if (obj_header.is_big_obj) {
@@ -1120,15 +1119,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
if (interp == COFF_SymbolValueInterp_Regular) {
symbol_section_number = symbol.section_number;
symbol_section_offset = symbol.value;
symbol_virtual_offset = task->image_section_table[symbol.section_number]->voff + symbol_section_offset;
symbol_address = task->base_addr + symbol_virtual_offset;
symbol_secnum = symbol.section_number;
symbol_secoff = symbol.value;
symbol_voff = task->image_section_table[symbol.section_number]->voff + symbol_secoff;
} else if (interp == COFF_SymbolValueInterp_Abs) {
symbol_section_number = max_U32;
symbol_section_offset = max_U32;
symbol_virtual_offset = symbol.value - task->base_addr;
symbol_address = symbol.value;
symbol_secnum = 0;
symbol_secoff = 0;
symbol_voff = safe_cast_u32(symbol.value);
} else if (interp == COFF_SymbolValueInterp_Weak) {
// unresolved weak
} else if (interp == COFF_SymbolValueInterp_Undefined) {
@@ -1142,21 +1139,21 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
COFF_RelocValue reloc_value = {0};
switch (obj_header.machine) {
case COFF_MachineType_Unknown: {} break;
case COFF_MachineType_X64: { reloc_value = coff_pick_reloc_value_x64(reloc->type, reloc_virtual_offset, symbol_section_number, symbol_section_offset, symbol_virtual_offset, symbol_address); } break;
case COFF_MachineType_X64: { reloc_value = coff_pick_reloc_value_x64(reloc->type, task->image_base, reloc_voff, symbol_secnum, symbol_secoff, symbol_voff); } break;
default: { NotImplemented; } break;
}
// read addend
Assert(reloc_file_offset + reloc_value.size <= task->image_data.size);
Assert(reloc_foff + reloc_value.size <= task->image_data.size);
U64 raw_addend = 0;
str8_deserial_read(task->image_data, reloc_file_offset, &raw_addend, reloc_value.size, reloc_value.size);
str8_deserial_read(task->image_data, reloc_foff, &raw_addend, reloc_value.size, reloc_value.size);
// compute new reloc value
S64 addend = extend_sign64(raw_addend, reloc_value.size);
U64 reloc_result = reloc_value.value + addend;
// commit new reloc value
MemoryCopy(task->image_data.str + reloc_file_offset, &reloc_result, reloc_value.size);
MemoryCopy(task->image_data.str + reloc_foff, &reloc_result, reloc_value.size);
}
}
}
@@ -2270,9 +2267,12 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *sect_header = &section_table[sect_idx];
if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) {
LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symlinks[sect_idx]);
COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx);
sect_map[obj_idx][sect_idx] = sect_map[defn->u.defined.obj->input_idx][symbol.section_number-1];
String8 comdat_name = symlinks[sect_idx];
if (comdat_name.size) {
LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, comdat_name);
COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx);
sect_map[obj_idx][sect_idx] = sect_map[defn->u.defined.obj->input_idx][symbol.section_number-1];
}
}
}
}
@@ -2473,15 +2473,25 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
if (interp == COFF_SymbolValueInterp_Regular) {
LNK_SectionContrib *sc = sect_map[obj_idx][symbol.section_number-1];
U32 section_number = 0;
U32 value = 0;
{
COFF_SectionHeader *sect_header = lnk_section_header_from_section_number(obj, symbol.section_number);
if (~sect_header->flags & COFF_SectionFlag_LnkRemove) {
LNK_SectionContrib *sc = sect_map[obj_idx][symbol.section_number-1];
section_number = safe_cast_u32(sc->u.sect_idx + 1);
value = sc->u.off + symbol.value;
}
}
if (obj->header.is_big_obj) {
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
symbol32->section_number = safe_cast_u32(sc->u.sect_idx + 1);
symbol32->value = safe_cast_u32(sc->u.off + symbol32->value);
symbol32->section_number = section_number;
symbol32->value = value;
} else {
COFF_Symbol16 *symbol16 = symbol.raw_symbol;
symbol16->section_number = safe_cast_u16(sc->u.sect_idx + 1);
symbol16->value = safe_cast_u32(sc->u.off + symbol16->value);
symbol16->section_number = safe_cast_u16(section_number);
symbol16->value = value;
}
}
}
@@ -2918,7 +2928,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
LNK_ObjRelocPatcher task = {0};
task.image_data = image_data;
task.objs = objs;
task.base_addr = pe.image_base;
task.image_base = pe.image_base;
task.image_section_table = image_section_table;
tp_for_parallel(tp, 0, objs_count, lnk_obj_reloc_patcher, &task);
ProfEnd();
@@ -3546,7 +3556,6 @@ lnk_run(int argc, char **argv)
String8List manifest_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list);
PE_ExportParseList export_symbol_list = config->export_symbol_list;
HashTable *export_ht = hash_table_init(scratch.arena, max_U16/2);
LNK_AltNameList alt_name_list = config->alt_name_list;
LNK_InputObjList input_obj_list = {0};
LNK_InputImportList input_import_list = {0};
LNK_SymbolList input_weak_list = {0};
@@ -3624,6 +3633,13 @@ lnk_run(int argc, char **argv)
for (PE_ExportParseNode *exp_n = config->export_symbol_list.first; exp_n != 0; exp_n = exp_n->next) {
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, exp_n->data);
}
//
// Push config alternative names
//
for (LNK_AltNameNode *alt_n = config->alt_name_list.first; alt_n != 0; alt_n = alt_n->next) {
lnk_symbol_table_push_alt_name(symtab, 0, alt_n->data.from, alt_n->data.to);
}
ProfBegin("Image"); // :EndImage
lnk_timer_begin(LNK_Timer_Image);
@@ -3711,21 +3727,6 @@ lnk_run(int argc, char **argv)
lnk_symbol_list_push(scratch.arena, &lookup_undef_list, symbol);
}
ProfEnd();
#if 0
ProfBegin("Push /ALTERNATIVENAME Symbols");
Assert(alt_name_list.from_list.node_count == alt_name_list.to_list.node_count);
for (String8Node *from_node = alt_name_list.from_list.first, *to_node = alt_name_list.to_list.first;
from_node != 0;
from_node = from_node->next, to_node = to_node->next) {
LNK_Symbol *fallback = lnk_make_undefined_symbol(scratch.arena, to_node->string);
LNK_Symbol *weak = lnk_make_weak_symbol(scratch.arena, from_node->string, COFF_WeakExt_SearchAlias, fallback);
lnk_symbol_list_push(scratch.arena, &lookup_undef_list, fallback);
lnk_symbol_list_push(scratch.arena, &input_weak_list, weak);
lnk_symbol_table_push(symtab, weak);
}
ProfEnd();
#endif
// we defined new symbols, give unresolved symbols another chance to be resolved
lnk_symbol_list_concat_in_place(&lookup_undef_list, &unresolved_undef_list);
@@ -3734,7 +3735,6 @@ lnk_run(int argc, char **argv)
// reset inputs
MemoryZeroStruct(&include_symbol_list);
MemoryZeroStruct(&alt_name_list);
MemoryZeroStruct(&input_weak_list);
ProfEnd();
@@ -3880,10 +3880,16 @@ lnk_run(int argc, char **argv)
}
// /ALTERNATENAME
for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) {
String8 *invalid_string = lnk_parse_alt_name_directive_list(scratch.arena, dir->value_list, &alt_name_list);
if (invalid_string) {
lnk_error_obj(LNK_Error_Cmdl, obj, "invalid syntax \"%S\", expected format \"FROM=TO\"", *invalid_string);
{
for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) {
for (String8Node *string_n = dir->value_list.first; string_n != 0; string_n = string_n->next) {
LNK_AltName alt_name;
if (lnk_parse_alt_name_directive(string_n->string, &alt_name)) {
lnk_symbol_table_push_alt_name(symtab, obj, alt_name.from, alt_name.to);
} else {
lnk_error_obj(LNK_Error_Cmdl, obj, "syntax error in \"%S\", expected format \"FROM=TO\"", string_n->string);
}
}
}
}
@@ -4573,9 +4579,7 @@ lnk_run(int argc, char **argv)
state_list_push(scratch.arena, state_list, State_InputImports);
continue;
}
if (input_weak_list.count ||
include_symbol_list.node_count ||
alt_name_list.from_list.node_count) {
if (input_weak_list.count || include_symbol_list.node_count) {
state_list_push(scratch.arena, state_list, State_InputSymbols);
continue;
}
+1 -1
View File
@@ -102,7 +102,7 @@ typedef struct
{
String8 image_data;
LNK_Obj **objs;
U64 base_addr;
U64 image_base;
COFF_SectionHeader **image_section_table;
} LNK_ObjRelocPatcher;
+16 -27
View File
@@ -776,40 +776,21 @@ lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_pat
////////////////////////////////
internal void
lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat)
{
str8_list_concat_in_place(&list->from_list, &to_concat->from_list);
str8_list_concat_in_place(&list->to_list, &to_concat->to_list);
}
internal B32
lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out)
lnk_parse_alt_name_directive(String8 input, LNK_AltName *alt_out)
{
Temp scratch = scratch_begin(&arena, 1);
Temp scratch = scratch_begin(0,0);
B32 is_parse_ok = 0;
String8List pair = str8_split_by_string_chars(scratch.arena, input, str8_lit("="), 0);
if (pair.node_count == 2) {
str8_list_push(arena, &list_out->from_list, pair.first->string);
str8_list_push(arena, &list_out->to_list, pair.last->string);
alt_out->from = pair.first->string;
alt_out->to = pair.last->string;
is_parse_ok = 1;
}
scratch_end(scratch);
return is_parse_ok;
}
internal String8 *
lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out)
{
for (String8Node *str_n = list.first; str_n != 0; str_n = str_n->next) {
B32 is_parse_ok = lnk_parse_alt_name_directive(arena, str_n->string, list_out);
if ( ! is_parse_ok) {
return &str_n->string;
}
}
return 0;
}
internal B32
lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out)
{
@@ -1076,10 +1057,18 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_AlternateName: {
String8List value_strings_copy = str8_list_copy(arena, &value_strings);
String8 *error_string = lnk_parse_alt_name_directive_list(arena, value_strings_copy, &config->alt_name_list);
if (error_string != 0) {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid syntax \"%S\", expected format \"FROM=TO\"", *error_string);
if (value_strings.node_count == 1) {
LNK_AltName alt_name;
if (lnk_parse_alt_name_directive(value_strings.first->string, &alt_name)) {
LNK_AltNameNode *alt_name_n = push_array(arena, LNK_AltNameNode, 1);
alt_name_n->data = alt_name;
SLLQueuePush(config->alt_name_list.first, config->alt_name_list.last, alt_name_n);
config->alt_name_list.count += 1;
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "syntax error in \"%S\", expected format \"FROM=TO\"", value_strings.first->string);
}
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters");
}
} break;
+16 -6
View File
@@ -232,10 +232,23 @@ typedef enum
LNK_ManifestOpt_No,
} LNK_ManifestOpt;
typedef struct LNK_AltName
{
String8 from;
String8 to;
} LNK_AltName;
typedef struct LNK_AltNameNode
{
struct LNK_AltNameNode *next;
LNK_AltName data;
} LNK_AltNameNode;
typedef struct LNK_AltNameList
{
String8List from_list;
String8List to_list;
U64 count;
LNK_AltNameNode *first;
LNK_AltNameNode *last;
} LNK_AltNameList;
typedef struct LNK_MergeDirective
@@ -556,10 +569,7 @@ internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, S
////////////////////////////////
internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat);
internal B32 lnk_parse_alt_name_directive (Arena *arena, String8 input, LNK_AltNameList *list_out);
internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out);
internal B32 lnk_parse_alt_name_directive(String8 input, LNK_AltName *alt_out);
internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out);
internal B32 lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out);
-1
View File
@@ -139,7 +139,6 @@ THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task)
String8Node *name_node = lib->symbol_name_list.first;
for (U64 symbol_idx = 0; symbol_idx < lib->symbol_count; ++symbol_idx, name_node = name_node->next) {
LNK_Symbol *symbol = lnk_make_lib_symbol(arena, name_node->string, lib, lib->member_off_arr[symbol_idx]);
U64 hash = lnk_symbol_hash(symbol->name);
lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, hash, symbol);
}
+10
View File
@@ -233,6 +233,16 @@ lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx)
return result;
}
internal COFF_SectionHeader *
lnk_section_header_from_section_number(LNK_Obj *obj, U64 section_number)
{
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
if (section_number > 0 && section_number <= obj->header.section_count_no_null) {
return &section_table[section_number-1];
}
return 0;
}
internal String8List *
lnk_collect_obj_chunks_parallel(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8 name, String8 postfix, B32 collect_discarded)
{
-1
View File
@@ -63,7 +63,6 @@ lnk_section_contrib_chunk_list_concat_in_place(LNK_SectionContribChunkList *list
list->last->next = to_concat->first;
list->last = to_concat->last;
list->chunk_count += to_concat->chunk_count;
MemoryZeroStruct(to_concat);
}
}
+20
View File
@@ -457,6 +457,7 @@ lnk_symbol_table_init(TP_Arena *arena)
for (U64 i = 0; i < LNK_SymbolScope_Count; ++i) {
symtab->chunk_lists[i] = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count);
}
symtab->alt_names = hash_table_init(arena->v[0], 1024);
return symtab;
}
@@ -464,6 +465,13 @@ internal LNK_Symbol *
lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScope scope, U64 hash, String8 name)
{
LNK_SymbolHashTrie *trie = lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name);
if (trie == 0) {
String8 alt_name = {0};
if (hash_table_search_string_string(symtab->alt_names, name, &alt_name)) {
U64 alt_hash = lnk_symbol_hash(alt_name);
trie = lnk_symbol_hash_trie_search(symtab->scopes[scope], alt_hash, alt_name);
}
}
return trie ? trie->symbol : 0;
}
@@ -525,4 +533,16 @@ lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8
}
}
internal void
lnk_symbol_table_push_alt_name(LNK_SymbolTable *symtab, LNK_Obj *obj, String8 from, String8 to)
{
String8 to_extant;
if (hash_table_search_string_string(symtab->alt_names, from, &to_extant)) {
if (!str8_match(to_extant, to, 0)) {
lnk_error_obj(LNK_Error_AlternateNameConflict, obj, "conflicting alternative name: existing '%S=%S' vs. new '%S=%S'", from, to_extant, from, to);
}
} else {
hash_table_push_string_string(symtab->arena->v[0], symtab->alt_names, from, to);
}
}
+3
View File
@@ -108,6 +108,7 @@ typedef struct LNK_SymbolTable
TP_Arena *arena;
LNK_SymbolHashTrie *scopes[LNK_SymbolScope_Count];
LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScope_Count];
HashTable *alt_names;
} LNK_SymbolTable;
////////////////////////////////
@@ -162,3 +163,5 @@ internal void lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U
internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name);
internal void lnk_symbol_table_push_alt_name(LNK_SymbolTable *symtab, struct LNK_Obj *obj, String8 from, String8 to);