WIP: reorder input and library search order to match MSVC behavior

This commit is contained in:
Nikita Smith
2025-09-01 14:39:19 -07:00
committed by Ryan Fleury
parent 240935f0cc
commit 1aac27095e
15 changed files with 1652 additions and 1617 deletions
+52 -11
View File
@@ -211,11 +211,18 @@ hash_table_search_u64(HashTable *ht, U64 key_u64)
return 0;
}
internal void *
hash_table_search_u64_raw(HashTable *ht, U64 key_u64)
internal KeyValuePair *
hash_table_search_raw(HashTable *ht, void *key)
{
KeyValuePair *kv = hash_table_search_u64(ht, key_u64);
return kv ? kv->value_raw : 0;
U64 hash = hash_table_hasher(str8_struct(&key));
U64 ibucket = hash % ht->cap;
BucketList *bucket = ht->buckets + ibucket;
for (BucketNode *n = bucket->first; n != 0; n = n->next) {
if (n->v.key_raw == key) {
return &n->v;
}
}
return 0;
}
internal KeyValuePair *
@@ -230,13 +237,6 @@ hash_table_search_path(HashTable *ht, String8 path)
return result;
}
internal void *
hash_table_search_path_raw(HashTable *ht, String8 path)
{
KeyValuePair *kv = hash_table_search_path(ht, path);
return kv ? kv->value_raw : 0;
}
internal B32
hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out)
{
@@ -250,6 +250,27 @@ hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out)
return 0;
}
internal void *
hash_table_search_u64_raw(HashTable *ht, U64 key_u64)
{
KeyValuePair *kv = hash_table_search_u64(ht, key_u64);
return kv ? kv->value_raw : 0;
}
internal void *
hash_table_search_path_raw(HashTable *ht, String8 path)
{
KeyValuePair *kv = hash_table_search_path(ht, path);
return kv ? kv->value_raw : 0;
}
internal void *
hash_table_search_raw_raw(HashTable *ht, void *key)
{
KeyValuePair *kv = hash_table_search_raw(ht, key);
return kv ? kv->value_raw : 0;
}
internal B32
hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out)
{
@@ -283,6 +304,13 @@ hash_table_push_u32_u32(Arena *arena, HashTable *ht, U32 key, U32 value)
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u32 = key, .value_u32 = value });
}
internal BucketNode *
hash_table_push_raw_raw(Arena *arena, HashTable *ht, void *key, void *value)
{
U64 hash = hash_table_hasher(str8_struct(&key));
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_raw = key, .value_raw = value });
}
internal B32
hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out)
{
@@ -381,6 +409,19 @@ key_value_pairs_from_hash_table(Arena *arena, HashTable *ht)
return pairs;
}
internal void *
keys_from_hash_table_raw(Arena *arena, HashTable *ht)
{
void **result = push_array(arena, void *, ht->count);
for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) {
for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) {
Assert(cursor < ht->count);
result[cursor++] = n->v.key_raw;
}
}
return result;
}
internal void *
values_from_hash_table_raw(Arena *arena, HashTable *ht)
{
+1
View File
@@ -87,6 +87,7 @@ internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable
internal String8 keys_from_hash_table_str8 (Arena *arena, HashTable *ht);
internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht);
internal void * keys_from_hash_table_raw(Arena *arena, HashTable *ht);
internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht);
internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count);
+34
View File
@@ -17,6 +17,8 @@
<Type Name="LNK_ExportParseList">
<AlternativeType Name="LNK_InputObjList"/>
<AlternativeType Name="LNK_InputList"/>
<AlternativeType Name="LNK_LibMemberRefList"/>
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
<Expand>
<LinkedListItems>
@@ -92,6 +94,38 @@
</Expand>
</Type>
<Type Name="LNK_SymbolHashTrieChunkList">
<Expand>
<Item Name="[chunk count]">count</Item>
<CustomListItems MaxItemsPerView="5000">
<Variable Name="node" InitialValue="first"/>
<Variable Name="idx" InitialValue="0"/>
<Loop>
<Break Condition="node == 0"/>
<Exec>idx = 0</Exec>
<Loop>
<Break Condition="idx >= node->count"/>
<Item>node->v[idx]</Item>
<Exec>idx += 1</Exec>
</Loop>
<Exec>node = node->next</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
<Type Name="LNK_SymbolHashTrieChunk">
<DisplayString>{count,cap,v}</DisplayString>
<Expand>
<Item Name="[count]">count</Item>
<Item Name="[cap]">cap</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>v</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="RDIB_VariableChunkList">
<AlternativeType Name="RDIB_UnitChunkList"/>
<AlternativeType Name="RDIB_LineTableChunkList"/>
+1176 -1176
View File
File diff suppressed because it is too large Load Diff
+119 -33
View File
@@ -3,21 +3,99 @@
#pragma once
// --- Link --------------------------------------------------------------------
// --- Input -------------------------------------------------------------------
typedef struct LNK_LibMemberRef
{
LNK_Lib *lib;
U32 member_idx;
struct LNK_LibMemberRef *next;
} LNK_LibMemberRef;
typedef struct LNK_LibMemberRefList
{
U64 count;
LNK_LibMemberRef *first;
LNK_LibMemberRef *last;
} LNK_LibMemberRefList;
typedef enum
{
LNK_InputSource_CmdLine, // specified on command line
LNK_InputSource_Default, // specified through defaultlib switch
LNK_InputSource_Obj, // refrenced from objects
LNK_InputSource_Count
} LNK_InputSourceType;
typedef struct LNK_Input
{
String8 path;
String8 data;
B32 disallow;
B32 is_thin;
B32 has_disk_read_failed;
B32 exclude_from_debug_info;
LNK_LibMemberRef *trigger;
void *loaded_input;
struct LNK_Input *next;
} LNK_Input;
typedef struct LNK_InputList
{
U64 count;
LNK_Input *first;
LNK_Input *last;
} LNK_InputList;
typedef struct LNK_InputPtrArray
{
U64 count;
LNK_Input **v;
} LNK_InputPtrArray;
typedef struct LNK_Inputer
{
Arena *arena;
LNK_InputList objs;
HashTable *objs_ht;
LNK_InputList new_objs;
HashTable *libs_ht;
HashTable *missing_lib_ht;
LNK_InputList libs;
LNK_InputList new_libs[LNK_InputSource_Count];
} LNK_Inputer;
// --- Image Link -------------------------------------------------------------
#define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***"
#define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***"
#define LNK_SECTION_FLAG_IS_LIVE (1 << 0)
typedef struct LNK_LinkContext
typedef struct LNK_ImportTables
{
LNK_SymbolTable *symtab;
U64 objs_count;
LNK_Obj **objs;
LNK_LibList lib_index[LNK_InputSource_Count];
} LNK_LinkContext;
Arena *arena;
HashTable *static_imports;
HashTable *delayed_imports;
HashTable *import_stub_ht;
} LNK_ImportTables;
// -- Image --------------------------------------------------------------------
typedef struct LNK_Link
{
LNK_ObjList objs;
LNK_LibList libs;
LNK_IncludeSymbolNode **last_include;
String8Node **last_cmd_lib;
String8Node **last_default_lib;
String8Node **last_obj_lib;
B32 try_to_resolve_entry_point;
} LNK_Link;
// -- Image Layout ------------------------------------------------------------
#define LNK_REMOVED_SECTION_NUMBER_32 (U32)-3
#define LNK_REMOVED_SECTION_NUMBER_16 (U16)-3
@@ -135,24 +213,6 @@ typedef struct
B32 is_large_addr_aware;
} LNK_ObjBaseRelocTask;
typedef struct
{
LNK_InputObjList input_obj_list;
U64 input_imports_count;
LNK_InputImport *input_imports;
LNK_InputImportList input_import_list;
LNK_SymbolList unresolved_symbol_list;
} LNK_SymbolFinderResult;
typedef struct
{
PathStyle path_style;
LNK_SymbolTable *symtab;
LNK_SymbolNodeArray lookup_node_arr;
LNK_SymbolFinderResult *result_arr;
Rng1U64 *range_arr;
} LNK_SymbolFinder;
typedef struct
{
String8 image_data;
@@ -203,17 +263,43 @@ internal String8 lnk_make_null_obj(Arena *arena);
internal String8 lnk_make_res_obj(Arena *arena, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name);
internal String8 lnk_make_linker_obj(Arena *arena, LNK_Config *config);
// --- Inputer -----------------------------------------------------------------
internal void lnk_input_list_push_node(LNK_InputList *list, LNK_Input *node);
internal void lnk_input_list_concat_in_place(LNK_InputList *list, LNK_InputList *to_concat);
internal LNK_InputPtrArray lnk_array_from_input_list(Arena *arena, LNK_InputList list);
internal LNK_Inputer * lnk_inputer_init(void);
internal LNK_Input * lnk_input_push(Arena *arena, LNK_InputList *list, String8 path, String8 data);
internal LNK_Input * lnk_inputer_push_linkgen(Arena *arena, LNK_InputList *list, String8 path, String8 data);
internal LNK_Input * lnk_inputer_push_thin(Arena *arena, LNK_InputList *list, HashTable *ht, String8 full_path);
internal LNK_Input * lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data);
internal LNK_Input * lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data);
internal LNK_Input * lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path);
internal LNK_Input * lnk_inputer_push_lib(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data);
internal LNK_Input * lnk_inputer_push_lib_linkgen(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data);
internal LNK_Input * lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSourceType input_source, String8 lib_path);
internal B32 lnk_inputer_has_items(LNK_Inputer *inputer);
internal LNK_InputPtrArray lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Flags io_flags, LNK_InputList *all_inputs, LNK_InputList *new_inputs);
// --- Link Context ------------------------------------------------------------
internal String8 lnk_get_lib_name(String8 path);
internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path);
internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path);
internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path);
internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
internal void lnk_lib_member_ref_list_push_node(LNK_LibMemberRefList *list, LNK_LibMemberRef *node);
internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b);
internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list);
internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Lib *lib, U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list);
internal LNK_ObjNode * lnk_load_objs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out);
internal void lnk_load_libs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link);
internal void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, LNK_ImportTables *imps);
internal LNK_Link * lnk_link_image (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab);
internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config);
// --- Optimizations -----------------------------------------------------------
internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs);
// --- Win32 Image -------------------------------------------------------------
+102 -50
View File
@@ -944,6 +944,57 @@ lnk_is_dll_delay_load(LNK_Config *config, String8 dll_name)
return hash_table_search_path_u64(config->delay_load_ht, dll_name, 0);
}
internal String8
lnk_get_lib_name(String8 path)
{
static String8 LIB_EXT = str8_lit_comp(".LIB");
// strip path
String8 name = str8_skip_last_slash(path);
// strip extension
String8 name_ext = str8_postfix(name, LIB_EXT.size);
if (str8_match(name_ext, LIB_EXT, StringMatchFlag_CaseInsensitive)) {
name = str8_chop(name, LIB_EXT.size);
}
return name;
}
internal void
lnk_push_disallow_lib(LNK_Config *config, String8 path)
{
String8 lib_name = lnk_get_lib_name(path);
hash_table_push_path_u64(config->arena, config->disallow_lib_ht, lib_name, 0);
}
internal B32
lnk_is_lib_disallowed(LNK_Config *config, String8 path)
{
String8 lib_name = lnk_get_lib_name(path);
return hash_table_search_path(config->disallow_lib_ht, lib_name) != 0;
}
internal void
lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj)
{
// is this a duplicate symbol?
if (hash_table_search_string_raw(config->include_symbol_ht, name, 0)) {
return;
}
name = push_str8_copy(config->arena, name);
LNK_IncludeSymbolNode *node = push_array(config->arena, LNK_IncludeSymbolNode, 1);
node->v.name = name;
node->v.obj = obj;
SLLQueuePush(config->include_symbol_list.first, config->include_symbol_list.last, node);
config->include_symbol_list.count += 1;
hash_table_push_string_raw(config->arena, config->include_symbol_ht, name, node);
}
internal void
lnk_print_build_info()
{
@@ -1068,9 +1119,9 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list)
}
internal void
lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj)
lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj)
{
Temp scratch = scratch_begin(&arena,1);
Temp scratch = scratch_begin(&config->arena, 1);
LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name);
@@ -1111,12 +1162,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
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);
hash_table_push_string_string(config->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);
alt_name.from = push_str8_copy(config->arena, alt_name.from);
alt_name.to = push_str8_copy(config->arena, alt_name.to);
LNK_AltNameNode *alt_name_n = push_array(arena, LNK_AltNameNode, 1);
LNK_AltNameNode *alt_name_n = push_array(config->arena, LNK_AltNameNode, 1);
alt_name_n->data = alt_name;
SLLQueuePush(config->alt_name_list.first, config->alt_name_list.last, alt_name_n);
@@ -1182,7 +1233,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_DefaultLib: {
String8List default_lib_list = str8_list_copy(arena, &value_strings);
String8List default_lib_list = str8_list_copy(config->arena, &value_strings);
if (obj) {
str8_list_concat_in_place(&config->input_obj_lib_list, &default_lib_list);
} else {
@@ -1208,9 +1259,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
case LNK_CmdSwitch_DelayLoad: {
for (String8Node *name_n = value_strings.first; name_n != 0; name_n = name_n->next) {
if (hash_table_search_path_u64(config->delay_load_ht, name_n->string, 0)) { continue; }
String8 name = push_str8_copy(arena, name_n->string);
hash_table_push_path_u64(arena, config->delay_load_ht, name, 0);
str8_list_push(arena, &config->delay_load_dll_list, name);
String8 name = push_str8_copy(config->arena, name_n->string);
hash_table_push_path_u64(config->arena, config->delay_load_ht, name, 0);
str8_list_push(config->arena, &config->delay_load_dll_list, name);
}
} break;
@@ -1228,7 +1279,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
case LNK_CmdSwitch_Entry: {
String8 new_entry_point_name = {0};
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &new_entry_point_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &new_entry_point_name);
if (config->entry_point_name.size) {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, cmd_switch, "unable to redefine entry point \"%S\" to \"%S\"", config->entry_point_name, new_entry_point_name);
@@ -1240,7 +1291,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
case LNK_CmdSwitch_Export: {
PE_ExportParse export_parse = {0};
if (lnk_parse_export_directive_ex(arena, value_strings, obj, &export_parse)) {
if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) {
PE_ExportParseNode *exp_n = 0;
String8 export_name = pe_name_from_export_parse(&export_parse);
hash_table_search_string_raw(config->export_ht, export_name, &exp_n);
@@ -1248,13 +1299,13 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
if (exp_n == 0) {
// make sure export is defined
if (!export_parse.is_forwarder) {
str8_list_push(arena, &config->include_symbol_list, export_parse.name);
lnk_include_symbol(config, export_parse.name, 0);
}
// push new export
exp_n = pe_export_parse_list_push(arena, &config->export_symbol_list, export_parse);
exp_n = pe_export_parse_list_push(config->arena, &config->export_symbol_list, export_parse);
hash_table_push_string_raw(arena, config->export_ht, export_name, exp_n);
hash_table_push_string_raw(config->arena, config->export_ht, export_name, exp_n);
} else {
B32 is_ambiguous = 1;
PE_ExportParse *extant_export = &exp_n->data;
@@ -1352,19 +1403,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_ImpLib: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->imp_lib_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->imp_lib_name);
} break;
case LNK_CmdSwitch_Include: {
for (String8Node *value_n = value_strings.first; value_n != 0; value_n = value_n->next) {
// is this a duplicate symbol?
if (hash_table_search_string_raw(config->include_symbol_ht, value_n->string, 0)) {
continue;
}
String8 include_symbol = push_str8_copy(arena, value_n->string);
hash_table_push_string_raw(arena, config->include_symbol_ht, include_symbol, 0);
str8_list_push(arena, &config->include_symbol_list, include_symbol);
lnk_include_symbol(config, value_n->string, obj);
}
} break;
@@ -1386,7 +1430,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_LibPath: {
String8List lib_dir_list = str8_list_copy(arena, &value_strings);
String8List lib_dir_list = str8_list_copy(config->arena, &value_strings);
for (String8Node *dir_n = lib_dir_list.first; dir_n != 0; dir_n = dir_n->next) {
if (!os_folder_path_exists(dir_n->string)) {
String8 full_path = os_full_path_from_path(scratch.arena, dir_n->string);
@@ -1426,7 +1470,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
if (res_id_arr.count == 2) {
U64 resource_id;
if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) {
config->manifest_resource_id = push_u64(arena, resource_id);
config->manifest_resource_id = push_u64(config->arena, resource_id);
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]);
}
@@ -1455,7 +1499,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_ManifestDependency: {
String8List manifest_dependency_list = str8_list_copy(arena, &value_strings);
String8List manifest_dependency_list = str8_list_copy(config->arena, &value_strings);
str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list);
if (config->manifest_opt == LNK_ManifestOpt_Null) {
@@ -1464,7 +1508,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_ManifestFile: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->manifest_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->manifest_name);
} break;
case LNK_CmdSwitch_ManifestInput: {
@@ -1488,7 +1532,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
str8_match_lit("'requireAdministrator'", level, 0)) {
// manifest level was parsed!
config->manifest_uac = 1;
config->manifest_level = push_str8_copy(arena, level);
config->manifest_level = push_str8_copy(config->arena, level);
if (param_arr.count > 1) {
String8 ui_access_param = param_arr.v[1];
String8List ui_access_list = str8_split_by_string_chars(scratch.arena, ui_access_param, str8_lit("="), 0);
@@ -1497,7 +1541,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
if (str8_match_lit("'true'", ui_access, 0) ||
str8_match_lit("'false'", ui_access, 0)) {
// ui access was parsed!
config->manifest_ui_access = push_str8_copy(arena, ui_access);
config->manifest_ui_access = push_str8_copy(config->arena, ui_access);
} else {
lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, obj, cmd_switch, ui_access_param);
}
@@ -1531,9 +1575,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
if (value_strings.node_count == 1) {
LNK_MergeDirective merge = {0};
if (lnk_parse_merge_directive(value_strings.first->string, obj, &merge)) {
merge.src = push_str8_copy(arena, merge.src);
merge.dst = push_str8_copy(arena, merge.dst);
lnk_merge_directive_list_push(arena, &config->merge_list, merge);
merge.src = push_str8_copy(config->arena, merge.src);
merge.dst = push_str8_copy(config->arena, merge.dst);
lnk_merge_directive_list_push(config->arena, &config->merge_list, merge);
}
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "invalid number of parameters %d", value_strings.node_count);
@@ -1549,7 +1593,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
}
}
String8List natvis_list = str8_list_copy(arena, &value_strings);
String8List natvis_list = str8_list_copy(config->arena, &value_strings);
str8_list_concat_in_place(&config->natvis_list, &natvis_list);
} break;
@@ -1558,8 +1602,13 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
if (value_strings.node_count == 0) {
config->no_default_libs = 1;
} else {
String8List no_default_lib_list = str8_list_copy(arena, &value_strings);
str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list);
for (String8Node *lib_n = value_strings.first; lib_n != 0; lib_n = lib_n->next) {
String8 lib_name = lnk_get_lib_name(lib_n->string);
if (hash_table_search_path_raw(config->disallow_lib_ht, lib_name)) {
continue;
}
hash_table_push_path_raw(config->arena, config->disallow_lib_ht, lib_name, 0);
}
}
} break;
@@ -1614,16 +1663,16 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_Out: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->image_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->image_name);
} break;
case LNK_CmdSwitch_Pdb: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->pdb_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->pdb_name);
} break;
case LNK_CmdSwitch_PdbAltPath: {
// see :PdbAltPath
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->pdb_alt_path);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->pdb_alt_path);
} break;
case LNK_CmdSwitch_PdbPageSize: {
@@ -1723,7 +1772,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_Rad_Map: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->rad_chunk_map_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_chunk_map_name);
config->rad_chunk_map = LNK_SwitchState_Yes;
} break;
@@ -1737,11 +1786,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
case LNK_CmdSwitch_Rad_DebugName: {
// :Rad_DebugAltPath
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->rad_debug_name);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_debug_name);
} break;
case LNK_CmdSwitch_Rad_DebugAltPath: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->rad_debug_alt_path);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_debug_alt_path);
} break;
case LNK_CmdSwitch_Rad_DelayBind: {
@@ -1839,7 +1888,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_Rad_MtPath: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->mt_path);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->mt_path);
} break;
case LNK_CmdSwitch_Rad_OsVer: {
@@ -1880,7 +1929,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} break;
case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: {
lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->pdb_hash_type_name_map);
lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->pdb_hash_type_name_map);
} break;
case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: {
@@ -1890,8 +1939,8 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
case LNK_CmdSwitch_Rad_RemoveSection: {
String8 sect_name = {0};
if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &sect_name)) {
sect_name = push_str8_copy(arena, sect_name);
str8_list_push(arena, &config->remove_sections, sect_name);
sect_name = push_str8_copy(config->arena, sect_name);
str8_list_push(config->arena, &config->remove_sections, sect_name);
}
} break;
@@ -1991,12 +2040,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
}
internal LNK_Config *
lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd_line)
lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
Temp scratch = scratch_begin(0, 0);
LNK_Config *config = push_array(arena, LNK_Config, 1);
Arena *arena = arena_alloc();
LNK_Config *config = push_array(arena, LNK_Config, 1);
config->arena = arena;
config->raw_cmd_line = str8_list_copy(arena, &raw_cmd_line);
config->work_dir = os_get_current_path(arena);
config->build_imp_lib = 1;
@@ -2012,10 +2063,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd
config->alt_name_ht = hash_table_init(arena, 0x100);
config->include_symbol_ht = hash_table_init(arena, 0x100);
config->delay_load_ht = hash_table_init(arena, 0x100);
config->disallow_lib_ht = hash_table_init(arena, 0x100);
// process command line switches
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) {
lnk_apply_cmd_option_to_config(arena, config, cmd->string, cmd->value_strings, 0);
lnk_apply_cmd_option_to_config(config, cmd->string, cmd->value_strings, 0);
}
// :manifest_input
+34 -8
View File
@@ -249,6 +249,25 @@ typedef enum
LNK_ManifestOpt_No,
} LNK_ManifestOpt;
typedef struct LNK_IncludeSymbol
{
String8 name;
struct LNK_Obj *obj;
} LNK_IncludeSymbol;
typedef struct LNK_IncludeSymbolNode
{
struct LNK_IncludeSymbolNode *next;
LNK_IncludeSymbol v;
} LNK_IncludeSymbolNode;
typedef struct LNK_IncludeSymbolList
{
U64 count;
LNK_IncludeSymbolNode *first;
LNK_IncludeSymbolNode *last;
} LNK_IncludeSymbolList;
typedef struct LNK_AltName
{
String8 from;
@@ -304,6 +323,7 @@ typedef enum
typedef struct LNK_Config
{
Arena *arena;
LNK_ConfigFlags flags;
LNK_DebugMode debug_mode;
LNK_SwitchState opt_ref;
@@ -362,7 +382,6 @@ typedef struct LNK_Config
String8List input_list[LNK_Input_Count];
String8List input_obj_lib_list;
String8List input_default_lib_list;
String8List disallow_lib_list;
String8List delay_load_dll_list;
String8List natvis_list;
String8 manifest_name;
@@ -375,7 +394,7 @@ typedef struct LNK_Config
String8 rad_chunk_map_name;
String8 rad_debug_name;
String8 rad_debug_alt_path;
String8List include_symbol_list;
LNK_IncludeSymbolList include_symbol_list;
LNK_AltNameList alt_name_list;
LNK_MergeDirectiveList merge_list;
U64 symbol_table_cap_defined;
@@ -397,6 +416,7 @@ typedef struct LNK_Config
HashTable *alt_name_ht;
HashTable *include_symbol_ht;
HashTable *delay_load_ht;
HashTable *disallow_lib_ht;
} LNK_Config;
// --- MSVC Error Codes --------------------------------------------------------
@@ -573,20 +593,26 @@ internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LN
// --- Getters -----------------------------------------------------------------
internal String8 lnk_get_image_name(LNK_Config *config);
internal U64 lnk_get_default_function_pad_min(COFF_MachineType machine);
internal U64 lnk_get_base_addr(LNK_Config *config);
internal String8 lnk_get_image_name (LNK_Config *config);
internal U64 lnk_get_default_function_pad_min (COFF_MachineType machine);
internal U64 lnk_get_base_addr (LNK_Config *config);
internal Version lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal Version lnk_get_min_subsystem_version (PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal B32 lnk_do_debug_info (LNK_Config *config);
internal B32 lnk_is_thread_pool_shared(LNK_Config *config);
internal B32 lnk_is_section_removed (LNK_Config *config, String8 section_name);
internal B32 lnk_is_dll_delay_load (LNK_Config *config, String8 dll_name);
internal String8 lnk_get_lib_name (String8 path);
internal void lnk_push_disallow_lib(LNK_Config *config, String8 path);
internal B32 lnk_is_lib_disallowed(LNK_Config *config, String8 path);
internal void lnk_include_symbol(LNK_Config *config, String8 name, struct LNK_Obj *obj);
// --- Config ------------------------------------------------------------------
internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj);
internal void lnk_apply_cmd_option_to_config(LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj);
internal LNK_Config * lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd_line);
internal LNK_Config * lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line);
-175
View File
@@ -1,175 +0,0 @@
// Copyright (c) 2025 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
lnk_error_input_obj(LNK_ErrorCode code, LNK_InputObj *input, char *fmt, ...)
{
va_list args; va_start(args, fmt);
lnk_error_with_loc_fv(code, input->path, input->lib ? input->lib->path : str8_zero(), fmt, args);
va_end(args);
}
internal String8
lnk_string_from_input_source(LNK_InputSourceType input_source)
{
String8 result = str8_zero();
switch (input_source) {
case LNK_InputSource_CmdLine: result = str8_lit("CmdLine"); break;
case LNK_InputSource_Default: result = str8_lit("Default"); break;
case LNK_InputSource_Obj: result = str8_lit("Obj"); break;
default: InvalidPath;
}
return result;
}
internal void
lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node)
{
SLLQueuePush(list->first, list->last, node);
++list->count;
}
internal LNK_InputObj *
lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list)
{
LNK_InputObj *node = push_array(arena, LNK_InputObj, 1);
lnk_input_obj_list_push_node(list, node);
return node;
}
internal void
lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat)
{
SLLConcatInPlace(list, to_concat);
}
internal LNK_InputObj **
lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list)
{
LNK_InputObj **result = push_array_no_zero(arena, LNK_InputObj *, list.count);
U64 i = 0;
for (LNK_InputObj *n = list.first; n != 0; n = n->next, ++i) {
Assert(i < list.count);
result[i] = n;
}
return result;
}
internal LNK_InputObj **
lnk_thin_array_from_input_obj_list(Arena *arena, LNK_InputObjList list, U64 *count_out)
{
for (LNK_InputObj *input = list.first; input != 0; input = input->next) {
if (input->is_thin) { *count_out += 1; }
}
LNK_InputObj **thin_inputs = push_array(arena, LNK_InputObj *, *count_out);
U64 input_idx = 0;
for (LNK_InputObj *input = list.first; input != 0; input = input->next) {
if (input->is_thin) { thin_inputs[input_idx++] = input; }
}
return thin_inputs;
}
internal String8Array
lnk_path_array_from_input_obj_array(Arena *arena, LNK_InputObj **arr, U64 count)
{
String8Array paths = {0};
paths.count = count;
paths.v = push_array(arena, String8, count);
for (U64 i = 0; i < count; i += 1) {
paths.v[i] = arr[i]->path;
}
return paths;
}
internal int
lnk_input_obj_compar(const void *raw_a, const void *raw_b)
{
LNK_InputObj * const *a = raw_a, * const *b = raw_b;
return u64_compar(&(*a)->input_idx, &(*b)->input_idx);
}
internal int
lnk_input_obj_compar_is_before(void *raw_a, void *raw_b)
{
LNK_InputObj **a = raw_a, **b = raw_b;
return lnk_input_obj_compar(a, b) < 0;
}
internal LNK_InputObjList
lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count)
{
LNK_InputObjList list = {0};
for (U64 i = 0; i < count; ++i) {
SLLQueuePush(list.first, list.last, arr[i]);
++list.count;
}
return list;
}
internal LNK_InputObjList
lnk_input_obj_list_from_string_list(Arena *arena, String8List list)
{
LNK_InputObjList input_list = {0};
for (String8Node *path = list.first; path != 0; path = path->next) {
LNK_InputObj *input = lnk_input_obj_list_push(arena, &input_list);
input->is_thin = 1;
input->dedup_id = path->string;
input->path = path->string;
}
return input_list;
}
internal LNK_InputImportNode *
lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list)
{
LNK_InputImportNode *node = push_array(arena, LNK_InputImportNode, 1);
SLLQueuePush(list->first, list->last, node);
list->count += 1;
return node;
}
internal void
lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat)
{
SLLConcatInPlace(list, to_concat);
}
internal LNK_InputImportNode **
lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list)
{
LNK_InputImportNode **result = push_array_no_zero(arena, LNK_InputImportNode *, list.count);
U64 idx = 0;
for (LNK_InputImportNode *node = list.first; node != 0; node = node->next) {
Assert(idx < list.count);
result[idx++] = node;
}
return result;
}
internal LNK_InputImportList
lnk_list_from_input_import_arr(LNK_InputImportNode **arr, U64 count)
{
LNK_InputImportList list = {0};
for (U64 i = 0; i < count; i += 1) {
SLLQueuePush(list.first, list.last, arr[i]);
list.count += 1;
}
return list;
}
int
lnk_input_import_is_before(void *raw_a, void *raw_b)
{
LNK_InputImport *a = *(LNK_InputImport **)raw_a;
LNK_InputImport *b = *(LNK_InputImport **)raw_b;
return a->input_idx < b->input_idx;
}
int
lnk_input_import_node_compar(const void *raw_a, const void *raw_b)
{
LNK_InputImportNode * const *a = raw_a;
LNK_InputImportNode * const *b = raw_b;
return u64_compar(&(*a)->data.input_idx, &(*b)->data.input_idx);
}
-77
View File
@@ -1,77 +0,0 @@
// Copyright (c) 2025 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#pragma once
typedef enum
{
LNK_InputSource_CmdLine, // specified on command line
LNK_InputSource_Default, // specified through defaultlib switch
LNK_InputSource_Obj, // refrenced from objects
LNK_InputSource_Count
} LNK_InputSourceType;
typedef String8Node LNK_InputLib;
typedef String8List LNK_InputLibList;
typedef struct LNK_InputImport
{
String8 coff_import;
U64 input_idx;
struct LNK_Lib *lib;
} LNK_InputImport;
typedef struct LNK_InputImportNode
{
struct LNK_InputImportNode *next;
LNK_InputImport data;
} LNK_InputImportNode;
typedef struct LNK_InputImportList
{
U64 count;
LNK_InputImportNode *first;
LNK_InputImportNode *last;
} LNK_InputImportList;
typedef struct LNK_InputObj
{
String8 path;
String8 dedup_id;
String8 data;
B8 is_thin;
B8 exclude_from_debug_info;
B8 has_disk_read_failed;
struct LNK_Lib *lib;
U64 input_idx;
struct LNK_InputObj *next;
} LNK_InputObj;
typedef struct LNK_InputObjList
{
U64 count;
LNK_InputObj *first;
LNK_InputObj *last;
} LNK_InputObjList;
////////////////////////////////
internal void lnk_error_input_obj(LNK_ErrorCode code, LNK_InputObj *input, char *fmt, ...);
internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source);
internal void lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node);
internal LNK_InputObj * lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list);
internal void lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat);
internal LNK_InputObj ** lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list);
internal LNK_InputObj ** lnk_thin_array_from_input_obj_list(Arena *arena, LNK_InputObjList list, U64 *count_out);
internal String8Array lnk_path_array_from_input_obj_array(Arena *arena, LNK_InputObj **arr, U64 count);
internal LNK_InputObjList lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count);
internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list);
internal LNK_InputImportNode * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list);
internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat);
internal LNK_InputImportNode ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list);
internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImportNode **arr, U64 count);
+33 -16
View File
@@ -10,8 +10,7 @@ lnk_lib_node_is_before(void *a, void *b)
internal int
lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b)
{
LNK_LibNode **a = raw_a, **b = raw_b;
return lnk_lib_node_is_before(*a, *b);
return raw_a < raw_b;
}
internal B32
@@ -117,7 +116,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out)
lib_out->symbol_count = symbol_count;
lib_out->member_offsets = member_offsets;
lib_out->symbol_indices = symbol_indices;
lib_out->was_member_queued = push_array(arena, B8, member_count);
lib_out->was_member_linked = push_array(arena, LNK_Symbol *, member_count);
lib_out->symbol_names = symbol_names;
lib_out->long_names = parse.long_names;
@@ -128,13 +127,13 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out)
internal
THREAD_POOL_TASK_FUNC(lnk_lib_initer)
{
LNK_LibIniter *task = raw_task;
LNK_LibIniter *task = raw_task;
LNK_Input *input = task->inputs[task_id];
U64 lib_node_idx = ins_atomic_u64_inc_eval(&task->next_free_lib_idx)-1;
LNK_LibNode *lib_node = &task->free_libs[lib_node_idx];
lib_node->data.input_idx = task_id;
B32 is_valid_lib = lnk_lib_from_data(arena, task->data_arr[task_id], task->path_arr[task_id], &lib_node->data);
B32 is_valid_lib = lnk_lib_from_data(arena, input->data, input->path, &lib_node->data);
if (is_valid_lib) {
U64 valid_lib_idx = ins_atomic_u64_inc_eval(&task->valid_libs_count)-1;
task->valid_libs[valid_lib_idx] = lib_node;
@@ -144,6 +143,17 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer)
}
}
internal LNK_Lib **
lnk_array_from_lib_list(Arena *arena, LNK_LibList list)
{
LNK_Lib **arr = push_array_no_zero(arena, LNK_Lib *, list.count);
U64 idx = 0;
for (LNK_LibNode *node = list.first; node != 0; node = node->next, ++idx) {
arr[idx] = &node->data;
}
return arr;
}
internal void
lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node)
{
@@ -152,32 +162,31 @@ lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node)
}
internal LNK_LibNodeArray
lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr)
lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U64 inputs_count, LNK_Input **inputs)
{
Temp scratch = scratch_begin(arena->v, arena->count);
Assert(data_arr.count == path_arr.count);
U64 lib_count = data_arr.count;
U64 lib_id_base = list->count;
// parse libs in parallel
LNK_LibIniter task = {0};
task.free_libs = push_array(arena->v[0], LNK_LibNode, lib_count);
task.valid_libs = push_array(scratch.arena, LNK_LibNode *, lib_count);
task.invalid_libs = push_array(scratch.arena, LNK_LibNode *, lib_count);
task.data_arr = data_arr.v;
task.path_arr = path_arr.v;
tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task);
task.free_libs = push_array(arena->v[0], LNK_LibNode, inputs_count);
task.valid_libs = push_array(scratch.arena, LNK_LibNode *, inputs_count);
task.invalid_libs = push_array(scratch.arena, LNK_LibNode *, inputs_count);
task.inputs = inputs;
tp_for_parallel(tp, arena, inputs_count, lnk_lib_initer, &task);
// report invalid libs
radsort(task.invalid_libs, task.invalid_libs_count, lnk_lib_node_ptr_is_before);
for EachIndex(i, task.invalid_libs_count) {
U64 input_idx = task.invalid_libs[i]->data.input_idx;
lnk_error(LNK_Error_InvalidLib, "%S: failed to parse library", path_arr.v[input_idx]);
lnk_error(LNK_Error_InvalidLib, "%S: failed to parse library", inputs[input_idx]->path);
}
// push parsed libs
radsort(task.valid_libs, task.valid_libs_count, lnk_lib_node_ptr_is_before);
for EachIndex(i, task.valid_libs_count) {
task.valid_libs[i]->data.input_idx = lib_id_base + i;
lnk_lib_list_push_node(list, task.valid_libs[i]);
}
@@ -187,6 +196,14 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S
return result;
}
internal B32
lnk_flag_member_as_queued(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger)
{
LNK_Symbol *slot = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], trigger, 0);
B32 is_first_queue_attempt = (slot == 0);
return is_first_queue_attempt;
}
internal B32
lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out)
{
+12 -10
View File
@@ -11,7 +11,7 @@ typedef struct LNK_Lib
U32 symbol_count;
U32 *member_offsets;
U16 *symbol_indices;
B8 *was_member_queued;
LNK_Symbol **was_member_linked;
String8Array symbol_names;
String8 long_names;
U64 input_idx;
@@ -40,14 +40,13 @@ typedef struct LNK_LibList
typedef struct
{
String8 *data_arr;
String8 *path_arr;
U64 next_free_lib_idx;
U64 valid_libs_count;
U64 invalid_libs_count;
LNK_LibNode *free_libs;
LNK_LibNode **valid_libs;
LNK_LibNode **invalid_libs;
struct LNK_Input **inputs;
U64 next_free_lib_idx;
U64 valid_libs_count;
U64 invalid_libs_count;
LNK_LibNode *free_libs;
LNK_LibNode **valid_libs;
LNK_LibNode **invalid_libs;
} LNK_LibIniter;
// -----------------------------------------------------------------------------
@@ -56,8 +55,11 @@ internal int lnk_lib_node_is_before(void *a, void *b);
internal int lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b);
internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out);
internal LNK_Lib ** lnk_array_from_lib_list(Arena *arena, LNK_LibList list);
internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node);
internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr);
internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U64 inputs_count, struct LNK_Input **inputs);
internal B32 lnk_flag_member_as_queued(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger);
internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out);
+50 -41
View File
@@ -11,6 +11,14 @@ lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...)
va_end(args);
}
internal void
lnk_error_input_obj(LNK_ErrorCode code, LNK_Input *input, char *fmt, ...)
{
va_list args; va_start(args, fmt);
lnk_error_with_loc_fv(code, input->path, input->trigger->lib ? input->trigger->lib->path : str8_zero(), fmt, args);
va_end(args);
}
internal LNK_Obj **
lnk_array_from_obj_list(Arena *arena, LNK_ObjList list)
{
@@ -26,9 +34,8 @@ internal
THREAD_POOL_TASK_FUNC(lnk_obj_initer)
{
LNK_ObjIniter *task = raw_task;
LNK_InputObj *input = task->inputs[task_id];
LNK_Obj *obj = &task->objs.v[task_id].data;
U64 obj_idx = task->obj_id_base + task_id;
LNK_Input *input = task->inputs[task_id];
LNK_Obj *obj = &task->objs[task_id].data;
ProfBeginV("Init Obj [%S%s%S]", input->lib_path, (input->lib_path.size ? ": " : 0), input->path);
@@ -281,58 +288,60 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
// fill out obj
obj->data = input->data;
obj->path = push_str8_copy(arena, input->path);
obj->lib = input->lib;
obj->input_idx = obj_idx;
obj->lib = input->trigger ? input->trigger->lib : 0;
obj->header = header;
obj->comdats = comdats;
obj->exclude_from_debug_info = input->exclude_from_debug_info;
obj->hotpatch = hotpatch;
obj->associated_sections = associated_sections;
obj->node = &task->objs[task_id];
obj->trigger_symbol = input->trigger;
ProfEnd();
}
internal LNK_ObjNodeArray
lnk_obj_list_push_parallel(TP_Context *tp,
TP_Arena *arena,
LNK_ObjList *list,
COFF_MachineType machine,
U64 input_count,
LNK_InputObj **inputs)
internal LNK_ObjNode *
lnk_obj_from_input_many(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, U64 inputs_count, LNK_Input **inputs)
{
ProfBeginFunction();
// store base id
U64 obj_id_base = list->count;
// reserve obj nodes
LNK_ObjNodeArray objs = {0};
if (input_count > 0) {
objs.count = input_count;
objs.v = push_array(arena->v[0], LNK_ObjNode, input_count);
for (LNK_ObjNode *ptr = objs.v, *opl = objs.v + input_count; ptr < opl; ++ptr) {
SLLQueuePush(list->first, list->last, ptr);
}
list->count += input_count;
LNK_ObjNode *objs = 0;
if (inputs_count) {
objs = push_array(arena->v[0], LNK_ObjNode, inputs_count);
tp_for_parallel(tp, arena, inputs_count, lnk_obj_initer, &(LNK_ObjIniter){ .inputs = inputs, .objs = objs, .machine = machine });
}
// fill out & run task
LNK_ObjIniter task = {0};
task.inputs = inputs;
task.obj_id_base = obj_id_base;
task.objs = objs;
task.machine = machine;
tp_for_parallel(tp, arena, input_count, lnk_obj_initer, &task);
ProfEnd();
return objs;
}
internal LNK_ObjNode *
lnk_obj_from_input(Arena *arena, COFF_MachineType machine, LNK_Input *input)
{
Temp scratch = scratch_begin(&arena, 1);
TP_Context *tp = tp_alloc(scratch.arena, 1, 1, str8_zero());
TP_Arena tp_arena = { .count = 1, .v = &arena };
LNK_ObjNode *result = lnk_obj_from_input_many(tp, &tp_arena, machine, 1, &input);
scratch_end(scratch);
return result;
}
internal void
lnk_obj_list_push_node_many(LNK_ObjList *list, U64 count, LNK_ObjNode *nodes)
{
for EachIndex(i, count) {
DLLPushBack(list->first, list->last, &nodes[i]);
}
list->count += count;
}
internal void
lnk_obj_list_push_node(LNK_ObjList *list, LNK_ObjNode *node)
{
lnk_obj_list_push_node_many(list, 1, node);
}
internal
THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
{
LNK_InputCoffSymbolTable *task = raw_task;
LNK_Obj *obj = &task->objs.v[task_id].data;
LNK_Obj *obj = task->objs[task_id];
COFF_ParsedSymbol symbol = {0};
for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx);
@@ -400,17 +409,17 @@ internal
THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task)
{
LNK_InputCoffSymbolTable *task = raw_task;
LNK_Obj *obj = &task->objs.v[task_id].data;
LNK_Obj *obj = task->objs[task_id];
obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj);
}
internal void
lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs)
lnk_push_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs)
{
ProfBeginFunction();
LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs };
tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task);
tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task);
tp_for_parallel(tp, arena, objs_count, lnk_input_coff_symbol_table, &task);
tp_for_parallel(tp, arena, objs_count, lnk_assign_comdat_symlinks_task, &task);
ProfEnd();
}
+26 -19
View File
@@ -7,21 +7,25 @@
typedef struct LNK_Obj
{
String8 data;
String8 path;
struct LNK_Lib *lib;
U32 input_idx;
COFF_FileHeaderInfo header;
U32 *comdats;
B8 hotpatch;
B8 exclude_from_debug_info;
U32Node **associated_sections;
LNK_SymbolHashTrie **symlinks;
String8 path;
String8 data;
struct LNK_Lib *lib;
struct LNK_LibMemberRef *trigger_symbol;
U32 input_idx;
COFF_FileHeaderInfo header;
U32 *comdats;
B8 hotpatch;
B8 exclude_from_debug_info;
U32Node **associated_sections;
LNK_SymbolHashTrie **symlinks;
struct LNK_ObjNode *node;
} LNK_Obj;
typedef struct LNK_ObjNode
{
struct LNK_ObjNode *next;
struct LNK_ObjNode *prev;
LNK_Obj data;
} LNK_ObjNode;
@@ -63,16 +67,16 @@ typedef struct LNK_DirectiveInfo
typedef struct
{
LNK_InputObj **inputs;
LNK_ObjNodeArray objs;
U64 obj_id_base;
U32 machine;
struct LNK_Input **inputs;
LNK_ObjNode *objs;
U64 obj_id_base;
U32 machine;
} LNK_ObjIniter;
typedef struct
{
LNK_SymbolTable *symtab;
LNK_ObjNodeArray objs;
LNK_SymbolTable *symtab;
LNK_Obj **objs;
} LNK_InputCoffSymbolTable;
typedef struct
@@ -86,12 +90,15 @@ typedef struct
// --- Error -------------------------------------------------------------------
internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...);
internal void lnk_error_input_obj(LNK_ErrorCode code, struct LNK_Input *input, char *fmt, ...);
// --- Input -------------------------------------------------------------------
internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list);
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs);
internal void lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs);
internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list);
internal void lnk_obj_list_push_node_many(LNK_ObjList *list, U64 count, LNK_ObjNode *nodes);
internal void lnk_obj_list_push_node(LNK_ObjList *list, LNK_ObjNode *node);
internal void lnk_inputer_push_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_ObjNode *objs);
// --- Metadata ----------------------------------------------------------------
+12 -1
View File
@@ -15,7 +15,18 @@ internal B32
lnk_symbol_defined_is_before(void *raw_a, void *raw_b)
{
LNK_Symbol *a = raw_a, *b = raw_b;
return a->defined.obj->input_idx < b->defined.obj->input_idx;
U32 a_lib_input_idx = a->defined.obj->lib ? a->defined.obj->lib->input_idx : 0;
U32 b_lib_input_idx = b->defined.obj->lib ? b->defined.obj->lib->input_idx : 0;
if (a_lib_input_idx == b_lib_input_idx) {
if (a->defined.obj->input_idx == b->defined.obj->input_idx) {
return a->defined.symbol_idx < b->defined.symbol_idx;
}
return a->defined.obj->input_idx < b->defined.obj->input_idx;
}
return a_lib_input_idx < b_lib_input_idx;
}
internal B32
+1
View File
@@ -14,6 +14,7 @@ typedef struct LNK_SymbolDefined
typedef struct LNK_Symbol
{
String8 name;
B8 is_lib_member_linked;
LNK_SymbolDefined defined;
} LNK_Symbol;