make use of undocumented anti-dependency search property on weak symbols

to implement alternate name using weak symbols
This commit is contained in:
Nikita Smith
2025-07-30 15:21:10 -07:00
committed by Ryan Fleury
parent 8d246d0c6a
commit c1958809eb
6 changed files with 123 additions and 41 deletions
+4 -3
View File
@@ -294,9 +294,10 @@ typedef struct COFF_Symbol32
typedef U32 COFF_WeakExtType;
enum
{
COFF_WeakExt_NoLibrary = 1,
COFF_WeakExt_SearchLibrary = 2,
COFF_WeakExt_SearchAlias = 3
COFF_WeakExt_NoLibrary = 1,
COFF_WeakExt_SearchLibrary = 2,
COFF_WeakExt_SearchAlias = 3,
COFF_WeakExt_AntiDependency = 4, // default symbol must not reference a weak symbol
};
// storage class: External
+30 -6
View File
@@ -1076,6 +1076,7 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder)
case COFF_WeakExt_NoLibrary: {
// NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member.
} break;
case COFF_WeakExt_AntiDependency:
case COFF_WeakExt_SearchLibrary: {
member_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Lib, symbol->name);
} break;
@@ -1550,9 +1551,32 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
ProfEnd();
} break;
case State_InputAlternateNames: {
ProfBegin("Input Alternate Names");
COFF_ObjWriter *obj_writer = 0;
for (; *last_alt_name; last_alt_name = &(*last_alt_name)->next) {
lnk_symbol_table_push_alt_name(symtab, 0, (*last_alt_name)->data.from, (*last_alt_name)->data.to);
// make object writer if it was reset
if (obj_writer == 0) {
obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown);
}
// append weak symbol
COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_undef(obj_writer, (*last_alt_name)->data.to);
coff_obj_writer_push_symbol_weak(obj_writer, (*last_alt_name)->data.from, COFF_WeakExt_AntiDependency, tag);
// flush on last directive or next directive is issued from a different obj
if ((*last_alt_name)->next == 0 || (*last_alt_name)->data.obj != (*last_alt_name)->next->data.obj) {
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->path = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->path : str8_lit("RADLINK");
input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAMES FOR %S *", input->path);
input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer);
input->lib = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->lib : 0;
// reset obj writer
coff_obj_writer_release(&obj_writer);
obj_writer = 0;
}
}
ProfEnd();
} break;
case State_PushDllHelperUndefSymbol: {
ProfBegin("Push Dll Helper Undef Symbol");
@@ -1997,6 +2021,10 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
state_list_push(scratch.arena, state_list, State_InputSymbols);
continue;
}
if (*last_alt_name != 0) {
state_list_push(scratch.arena, state_list, State_InputAlternateNames);
continue;
}
if (input_obj_list.count) {
state_list_push(scratch.arena, state_list, State_InputObjs);
continue;
@@ -2014,10 +2042,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
continue;
}
}
if (*last_alt_name != 0) {
state_list_push(scratch.arena, state_list, State_InputAlternateNames);
continue;
}
if (lookup_undef_list.count) {
state_list_push(scratch.arena, state_list, State_LookupUndef);
continue;
@@ -2054,7 +2078,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
}
// pass over symbol table and replace weak symbols without a strong definition with fallback definitions
lnk_finalize_weak_symbols(tp, symtab);
lnk_finalize_weak_symbols(tp_arena, tp, symtab);
// log
{
+21 -6
View File
@@ -609,6 +609,7 @@ lnk_parse_alt_name_directive(String8 string, LNK_Obj *obj, LNK_AltName *alt_out)
if (pair.node_count == 2) {
alt_out->from = pair.first->string;
alt_out->to = pair.last->string;
alt_out->obj = obj;
is_parse_ok = 1;
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_AlternateName, "syntax error in \"%S\", expected format \"FROM=TO\"", string);
@@ -1092,12 +1093,25 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
if (value_strings.node_count == 1) {
LNK_AltName alt_name;
if (lnk_parse_alt_name_directive(value_strings.first->string, obj, &alt_name)) {
alt_name.from = push_str8_copy(arena, alt_name.from);
alt_name.to = push_str8_copy(arena, alt_name.to);
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;
String8 to_extant = {0};
if (hash_table_search_string_string(config->alt_name_ht, alt_name.from, &to_extant)) {
if (str8_match(to_extant, alt_name.to, 0)) {
// ignore, duplicate
} else {
lnk_error_obj(LNK_Error_AlternateNameConflict, obj, "conflicting alternative name: existing '%S=%S' vs. new '%S=%S'", alt_name.from, to_extant, alt_name.from, alt_name.to);
}
} else {
hash_table_push_string_string(arena, config->alt_name_ht, alt_name.from, alt_name.to);
alt_name.from = push_str8_copy(arena, alt_name.from);
alt_name.to = push_str8_copy(arena, alt_name.to);
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, cmd_switch, "invalid number of parameters");
@@ -1973,6 +1987,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd
config->pdb_hash_type_name_length = 8;
config->data_dir_count = PE_DataDirectoryIndex_COUNT;
config->export_ht = hash_table_init(scratch.arena, max_U16/2);
config->alt_name_ht = hash_table_init(scratch.arena, 0x100);
// process command line switches
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) {
+3
View File
@@ -253,6 +253,7 @@ typedef struct LNK_AltName
{
String8 from;
String8 to;
struct LNK_Obj *obj;
} LNK_AltName;
typedef struct LNK_AltNameNode
@@ -392,6 +393,7 @@ typedef struct LNK_Config
String8List remove_sections;
LNK_IO_Flags io_flags;
HashTable *export_ht;
HashTable *alt_name_ht;
} LNK_Config;
// --- MSVC Error Codes --------------------------------------------------------
@@ -563,6 +565,7 @@ internal B32 lnk_parse_merge_directive (String8 string, struct LNK_Obj *obj,
internal B32 lnk_parse_export_directive (Arena *arena, String8 directive, struct LNK_Obj *obj, PE_ExportParse *export_out);
internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, struct LNK_Obj *obj, PE_ExportParse *export_out);
internal LNK_AltNameNode * lnk_alt_name_list_push(Arena *arena, LNK_AltNameList *list, LNK_AltName data);
internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data);
// --- Getters -----------------------------------------------------------------
+62 -22
View File
@@ -75,6 +75,12 @@ lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat)
SLLConcatInPlace(list, to_concat);
}
internal void
lnk_symbol_concat_in_place_array(LNK_SymbolList *list, LNK_SymbolList *to_concat, U64 to_concat_count)
{
SLLConcatInPlaceArray(list, to_concat, to_concat_count);
}
internal LNK_SymbolList
lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr)
{
@@ -467,7 +473,6 @@ 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;
}
@@ -487,15 +492,8 @@ lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_SymbolScope scope, LNK_Symbol
internal LNK_Symbol *
lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name)
{
U64 hash = lnk_symbol_hash(name);
U64 hash = lnk_symbol_hash(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;
}
@@ -514,16 +512,39 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *f
return symbol;
}
internal void
lnk_symbol_table_push_alt_name(LNK_SymbolTable *symtab, LNK_Obj *obj, String8 from, String8 to)
internal
THREAD_POOL_TASK_FUNC(lnk_check_anti_dependecy_task)
{
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);
LNK_FinalizeWeakSymbolsTask *task = raw_task;
LNK_SymbolTable *symtab = task->symtab;
LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id];
for EachIndex(i, chunk->count) {
LNK_Symbol *symbol = chunk->v[i].symbol;
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol);
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
if (symbol_interp == COFF_SymbolValueInterp_Weak) {
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj);
if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) {
COFF_ParsedSymbol default_symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, weak_ext->tag_index);
COFF_SymbolValueInterpType default_symbol_interp = coff_interp_from_parsed_symbol(default_symbol_parsed);
COFF_SymbolValueInterpType actual_default_symbol_interp = default_symbol_interp;
if (default_symbol_interp == COFF_SymbolValueInterp_Undefined) {
LNK_Symbol *actual_default_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, default_symbol_parsed.name);
if (actual_default_symbol) {
COFF_ParsedSymbol actual_default_symbol_parsed = lnk_parsed_symbol_from_defined(actual_default_symbol);
actual_default_symbol_interp = coff_interp_from_parsed_symbol(actual_default_symbol_parsed);
}
}
if (actual_default_symbol_interp == COFF_SymbolValueInterp_Weak) {
LNK_SymbolNode *symbol_n = push_array(arena, LNK_SymbolNode, 1);
symbol_n->data = symbol;
lnk_symbol_list_push_node(&task->anti_dependency_symbols[task_id], symbol_n);
}
}
}
} else {
hash_table_push_string_string(symtab->arena->v[0], symtab->alt_names, from, to);
}
}
@@ -538,10 +559,10 @@ THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task)
for EachIndex(i, chunk->count) {
LNK_Symbol *symbol = chunk->v[i].symbol;
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class);
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol);
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
if (symbol_interp == COFF_SymbolValueInterp_Weak) {
struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; };
struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; B32 is_anti_dependency; };
struct LookupLocation *lookup_first = 0, *lookup_last = 0;
LNK_SymbolDefined current_symbol = symbol->u.defined;
@@ -615,10 +636,10 @@ THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task)
}
internal void
lnk_finalize_weak_symbols(TP_Context *tp, LNK_SymbolTable *symtab)
lnk_finalize_weak_symbols(TP_Arena *arena, TP_Context *tp, LNK_SymbolTable *symtab)
{
ProfBeginFunction();
Temp scratch = scratch_begin(0,0);
Temp scratch = scratch_begin(arena->v, arena->count);
U64 chunks_count = 0;
for EachIndex(worker_id, tp->worker_count) { chunks_count += symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].count; }
@@ -632,6 +653,25 @@ lnk_finalize_weak_symbols(TP_Context *tp, LNK_SymbolTable *symtab)
}
LNK_FinalizeWeakSymbolsTask task = { .symtab = symtab, .chunks = chunks };
{
TP_Temp temp = tp_temp_begin(arena);
task.anti_dependency_symbols = push_array(scratch.arena, LNK_SymbolList, tp->worker_count);
tp_for_parallel(tp, arena, chunks_count, lnk_check_anti_dependecy_task, &task);
LNK_SymbolList anti_dependency_symbol_list = {0};
lnk_symbol_concat_in_place_array(&anti_dependency_symbol_list, task.anti_dependency_symbols, tp->worker_count);
LNK_SymbolArray anti_dependency_symbols = lnk_symbol_array_from_list(scratch.arena, anti_dependency_symbol_list);
radsort(anti_dependency_symbols.v, anti_dependency_symbols.count, lnk_symbol_defined_is_before);
for EachIndex(symbol_idx, anti_dependency_symbols.count) {
LNK_Symbol *s = &anti_dependency_symbols.v[symbol_idx];
lnk_error_obj(LNK_Error_UnresolvedSymbol, s->u.defined.obj, "unresolved symbol %S", s->name);
}
tp_temp_end(temp);
}
tp_for_parallel(tp, 0, chunks_count, lnk_finalize_weak_symbols_task, &task);
scratch_end(scratch);
+3 -4
View File
@@ -104,7 +104,6 @@ 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;
// --- Workers Contensts -------------------------------------------------------
@@ -113,6 +112,7 @@ typedef struct
{
LNK_SymbolTable *symtab;
LNK_SymbolHashTrieChunk **chunks;
LNK_SymbolList *anti_dependency_symbols;
} LNK_FinalizeWeakSymbolsTask;
// --- Symbol Make -------------------------------------------------------------
@@ -127,6 +127,7 @@ internal LNK_Symbol * lnk_make_import_symbol(Arena *arena, String8 name, String8
internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node);
internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol);
internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat);
internal void lnk_symbol_concat_in_place_array(LNK_SymbolList *list, LNK_SymbolList *to_concat, U64 to_concat_count);
internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr);
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list);
@@ -146,9 +147,7 @@ internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Sy
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name);
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...);
internal void lnk_symbol_table_push_alt_name(LNK_SymbolTable *symtab, struct LNK_Obj *obj, String8 from, String8 to);
internal void lnk_finalize_weak_symbols(TP_Context *tp, LNK_SymbolTable *symtab);
internal void lnk_finalize_weak_symbols(TP_Arena *arena, TP_Context *tp, LNK_SymbolTable *symtab);
// --- Symbol Contrib Helpers --------------------------------------------------