mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-04 21:08:40 +00:00
do lightweight import gathering while resolving links
This commit is contained in:
committed by
Ryan Fleury
parent
d4ac5ede77
commit
630c3b42a7
@@ -294,6 +294,7 @@ typedef struct COFF_Symbol32
|
|||||||
typedef U32 COFF_WeakExtType;
|
typedef U32 COFF_WeakExtType;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
COFF_WeakExt_Null = 0,
|
||||||
COFF_WeakExt_NoLibrary = 1,
|
COFF_WeakExt_NoLibrary = 1,
|
||||||
COFF_WeakExt_SearchLibrary = 2,
|
COFF_WeakExt_SearchLibrary = 2,
|
||||||
COFF_WeakExt_SearchAlias = 3,
|
COFF_WeakExt_SearchAlias = 3,
|
||||||
|
|||||||
+119
-107
@@ -468,7 +468,7 @@ lnk_make_null_obj(Arena *arena)
|
|||||||
COFF_ObjSymbol *null_abs = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_NULL_SYMBOL), 0, COFF_SymStorageClass_External);
|
COFF_ObjSymbol *null_abs = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_NULL_SYMBOL), 0, COFF_SymStorageClass_External);
|
||||||
|
|
||||||
// push import stub
|
// push import stub
|
||||||
coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_SearchAlias, null_abs);
|
coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_Null, null_abs);
|
||||||
|
|
||||||
// push .debug$T sections with null leaf
|
// push .debug$T sections with null leaf
|
||||||
String8 null_debug_data;
|
String8 null_debug_data;
|
||||||
@@ -1198,8 +1198,8 @@ internal int
|
|||||||
lnk_lib_member_ref_is_before(void *raw_a, void *raw_b)
|
lnk_lib_member_ref_is_before(void *raw_a, void *raw_b)
|
||||||
{
|
{
|
||||||
LNK_LibMemberRef **a = raw_a, **b = raw_b;
|
LNK_LibMemberRef **a = raw_a, **b = raw_b;
|
||||||
LNK_Symbol *a_pull_in_ref = (*a)->lib->was_member_linked[(*a)->member_idx];
|
LNK_Symbol *a_pull_in_ref = (*a)->lib->member_links[(*a)->member_idx];
|
||||||
LNK_Symbol *b_pull_in_ref = (*b)->lib->was_member_linked[(*b)->member_idx];
|
LNK_Symbol *b_pull_in_ref = (*b)->lib->member_links[(*b)->member_idx];
|
||||||
return lnk_symbol_is_before(a_pull_in_ref, b_pull_in_ref);
|
return lnk_symbol_is_before(a_pull_in_ref, b_pull_in_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1478,17 +1478,14 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
ProfEnd();
|
ProfEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal force_inline void
|
internal void
|
||||||
lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *link_symbol, LNK_Lib *lib, U32 member_idx)
|
lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *link_symbol, LNK_Lib *lib, U32 member_idx)
|
||||||
{
|
{
|
||||||
B32 is_first_set = lnk_lib_set_link_symbol(lib, member_idx, link_symbol);
|
B32 was_linked = lnk_lib_set_link_symbol(lib, member_idx, link_symbol);
|
||||||
if (is_first_set) {
|
if (was_linked) {
|
||||||
link_symbol->is_lib_member_linked = 1;
|
|
||||||
|
|
||||||
LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1);
|
LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1);
|
||||||
member_ref->lib = lib;
|
member_ref->lib = lib;
|
||||||
member_ref->member_idx = member_idx;
|
member_ref->member_idx = member_idx;
|
||||||
|
|
||||||
lnk_lib_member_ref_list_push_node(queued_members, member_ref);
|
lnk_lib_member_ref_list_push_node(queued_members, member_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1502,10 +1499,9 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task)
|
|||||||
B32 search_anti_deps = task->search_anti_deps;
|
B32 search_anti_deps = task->search_anti_deps;
|
||||||
LNK_LibMemberRefList *member_ref_list = &task->member_ref_lists[task_id];
|
LNK_LibMemberRefList *member_ref_list = &task->member_ref_lists[task_id];
|
||||||
|
|
||||||
for EachNode(c, LNK_SymbolHashTrieChunk, symtab->weak_undef_chunks[task_id].first) {
|
for EachNode(c, LNK_SymbolHashTrieChunk, symtab->search_chunks[task_id].first) {
|
||||||
for EachIndex(i, c->count) {
|
for EachIndex(i, c->count) {
|
||||||
LNK_Symbol *symbol = c->v[i].symbol;
|
LNK_Symbol *symbol = c->v[i].symbol;
|
||||||
if (symbol->is_lib_member_linked) { continue; }
|
|
||||||
|
|
||||||
LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol);
|
LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol);
|
||||||
COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol);
|
COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol);
|
||||||
@@ -1548,31 +1544,33 @@ lnk_link_inputs(TP_Context *tp,
|
|||||||
LNK_Config *config,
|
LNK_Config *config,
|
||||||
LNK_Inputer *inputer,
|
LNK_Inputer *inputer,
|
||||||
LNK_SymbolTable *symtab,
|
LNK_SymbolTable *symtab,
|
||||||
LNK_Link *link,
|
LNK_Link *link)
|
||||||
LNK_ImportTables *imps)
|
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
ProfBeginFunction();
|
||||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
Temp scratch = scratch_begin(arena->v, arena->count);
|
||||||
|
|
||||||
B32 search_anti_deps = 0;
|
LNK_LibMemberRefList *member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count);
|
||||||
|
B32 search_anti_deps = 0;
|
||||||
for (U64 resolved_members_count = 0; ; resolved_members_count = 0) {
|
for (U64 resolved_members_count = 0; ; resolved_members_count = 0) {
|
||||||
lnk_load_inputs(tp, arena, config, inputer, symtab, link);
|
lnk_load_inputs(tp, arena, config, inputer, symtab, link);
|
||||||
|
|
||||||
for EachNode(lib_n, LNK_LibNode, link->libs.first) {
|
for EachNode(lib_n, LNK_LibNode, link->libs.first) {
|
||||||
ProfBeginV("Search %S", str8_skip_last_slash(lib_n->data.path));
|
LNK_Lib *lib = &lib_n->data;
|
||||||
|
|
||||||
|
ProfBeginV("Search %S", str8_skip_last_slash(lib->path));
|
||||||
do {
|
do {
|
||||||
lnk_load_inputs(tp, arena, config, inputer, symtab, link);
|
lnk_load_inputs(tp, arena, config, inputer, symtab, link);
|
||||||
|
|
||||||
|
// search symbols in lib
|
||||||
|
MemoryZeroTyped(member_ref_lists, tp->worker_count);
|
||||||
|
tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &(LNK_SearchLibTask){ .search_anti_deps = search_anti_deps, .lib = lib, .symtab = symtab, .member_ref_lists = member_ref_lists });
|
||||||
|
|
||||||
LNK_LibMemberRefList queued_members = {0};
|
LNK_LibMemberRefList queued_members = {0};
|
||||||
{
|
lnk_lib_member_ref_list_concat_in_place_array(&queued_members, member_ref_lists, tp->worker_count);
|
||||||
LNK_SearchLibTask task = { .search_anti_deps = search_anti_deps, .lib = &lib_n->data, .symtab = symtab };
|
|
||||||
task.member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count);
|
|
||||||
tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &task);
|
|
||||||
lnk_lib_member_ref_list_concat_in_place_array(&queued_members, task.member_ref_lists, tp->worker_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort library member refs to match the order of their appearance in obj symbol tables
|
// sort library member refs to match the order of their appearance in obj symbol tables
|
||||||
LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members);
|
LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members);
|
||||||
|
//qsort(member_refs, queued_members.count, sizeof(member_refs[0]), lnk_lib_member_ref_compar);
|
||||||
radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before);
|
radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before);
|
||||||
|
|
||||||
if (queued_members.count) {
|
if (queued_members.count) {
|
||||||
@@ -1583,7 +1581,7 @@ lnk_link_inputs(TP_Context *tp,
|
|||||||
|
|
||||||
LNK_LibMemberRef *member_ref = member_refs[i];
|
LNK_LibMemberRef *member_ref = member_refs[i];
|
||||||
LNK_Lib *lib = member_ref->lib;
|
LNK_Lib *lib = member_ref->lib;
|
||||||
LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx];
|
LNK_Symbol *link_symbol = lib->member_links[member_ref->member_idx];
|
||||||
|
|
||||||
COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]);
|
COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]);
|
||||||
COFF_DataType member_type = coff_data_type_from_data(member_info.data);
|
COFF_DataType member_type = coff_data_type_from_data(member_info.data);
|
||||||
@@ -1602,70 +1600,50 @@ lnk_link_inputs(TP_Context *tp,
|
|||||||
|
|
||||||
// push inputs for lib member refs
|
// push inputs for lib member refs
|
||||||
for EachIndex(i, queued_members.count) {
|
for EachIndex(i, queued_members.count) {
|
||||||
LNK_LibMemberRef *member_ref = member_refs[i];
|
LNK_LibMemberRef *member_ref = member_refs[i];
|
||||||
LNK_Lib *lib = member_ref->lib;
|
U64 member_idx = member_ref->member_idx;
|
||||||
LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx];
|
|
||||||
|
|
||||||
// parse member
|
// parse member info
|
||||||
COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]);
|
COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_idx]);
|
||||||
COFF_DataType member_type = coff_data_type_from_data(member_info.data);
|
COFF_DataType member_type = coff_data_type_from_data(member_info.data);
|
||||||
String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name);
|
String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name);
|
||||||
|
|
||||||
switch (member_type) {
|
switch (member_type) {
|
||||||
case COFF_DataType_Import: {
|
case COFF_DataType_Import: {
|
||||||
COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(member_info.data);
|
LNK_Symbol *link_symbol = lib->member_links[member_idx];
|
||||||
|
|
||||||
// import machine compat check
|
LNK_Symbol *import_symbols[2] = {0};
|
||||||
if (import_header.machine != config->machine) {
|
if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) {
|
||||||
LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol);
|
import_symbols[0] = link_symbol;
|
||||||
lnk_error_obj(LNK_Error_IncompatibleMachine,
|
import_symbols[1] = lnk_symbol_table_search(symtab, str8_skip(link_symbol->name, str8_lit("__imp_").size));
|
||||||
ref.obj,
|
} else {
|
||||||
"symbol %S pulls-in import from %S for an incompatible machine %S (expected machine %S)",
|
Temp temp = temp_begin(scratch.arena);
|
||||||
link_symbol->name,
|
String8 imp_name = push_str8f(temp.arena, "__imp_%S", link_symbol->name);
|
||||||
str8_chop_last_slash(lib->path),
|
import_symbols[0] = lnk_symbol_table_search(symtab, imp_name);
|
||||||
coff_string_from_machine_type(import_header.machine),
|
import_symbols[1] = link_symbol;
|
||||||
coff_string_from_machine_type(config->machine));
|
temp_end(temp);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// was import already created?
|
for EachIndex(i, ArrayCount(import_symbols)) {
|
||||||
LNK_Symbol *is_import_loaded = lnk_symbol_table_search(symtab, link_symbol->name);
|
LNK_Symbol *import_symbol = import_symbols[i];
|
||||||
if (is_import_loaded) {
|
if (import_symbol == 0) { continue; }
|
||||||
COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(is_import_loaded);
|
|
||||||
if (interp != COFF_SymbolValueInterp_Undefined) {
|
LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB));
|
||||||
break;
|
|
||||||
}
|
// same import symbol must never be queued more than once, if it is, there is a bug in the link set logic
|
||||||
|
AssertAlways(import_symbol->refs != import_stub->refs);
|
||||||
|
|
||||||
|
// replace the import symbol with a stub, which is later replaced with the real import symbol once import obj is ready
|
||||||
|
import_symbol->refs = import_stub->refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create import stub symbol (later replaced with actual import)
|
// push import member for import obj generation
|
||||||
LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB));
|
lnk_lib_member_ref_list_push_node(&link->imports, member_ref);
|
||||||
LNK_ObjSymbolRef import_symbol_ref = lnk_ref_from_symbol(import_stub);
|
|
||||||
LNK_Symbol *import_symbol = lnk_make_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx);
|
|
||||||
lnk_symbol_table_push(symtab, import_symbol);
|
|
||||||
|
|
||||||
// skip lib search
|
|
||||||
import_symbol->is_lib_member_linked = 1;
|
|
||||||
|
|
||||||
// find DLL with import symbols
|
|
||||||
B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name);
|
|
||||||
String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names;
|
|
||||||
HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports;
|
|
||||||
PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name);
|
|
||||||
|
|
||||||
// create record for a first time-DLL
|
|
||||||
if (import_symbols == 0) {
|
|
||||||
import_symbols = push_array(imps->arena, PE_MakeImportList, 1);
|
|
||||||
str8_list_push(imps->arena, dll_names, import_header.dll_name);
|
|
||||||
hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
// push make import info
|
|
||||||
pe_make_import_header_list_push(imps->arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) });
|
|
||||||
} break;
|
} break;
|
||||||
case COFF_DataType_BigObj:
|
case COFF_DataType_BigObj:
|
||||||
case COFF_DataType_Obj: {
|
case COFF_DataType_Obj: {
|
||||||
if (lib->type == COFF_Archive_Thin) {
|
if (lib->type == COFF_Archive_Thin) {
|
||||||
// obj path in thin archive is relative to the directory with archive
|
// obj path in thin archive is relative to the directory with lib
|
||||||
String8List obj_path_list = {0};
|
String8List obj_path_list = {0};
|
||||||
str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path));
|
str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path));
|
||||||
str8_list_push(scratch.arena, &obj_path_list, member_name);
|
str8_list_push(scratch.arena, &obj_path_list, member_name);
|
||||||
@@ -1747,18 +1725,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first;
|
link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first;
|
||||||
link->try_to_resolve_entry_point = 1;
|
link->try_to_resolve_entry_point = 1;
|
||||||
|
|
||||||
//
|
|
||||||
// init import hash tables
|
|
||||||
//
|
|
||||||
LNK_ImportTables *imps = 0;
|
|
||||||
{
|
|
||||||
Arena *imps_arena = arena_alloc();
|
|
||||||
imps = push_array(imps_arena, LNK_ImportTables, 1);
|
|
||||||
imps->arena = imps_arena;
|
|
||||||
imps->static_imports = hash_table_init(imps->arena, 0x1000);
|
|
||||||
imps->delayed_imports = hash_table_init(imps->arena, 0x1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// input :null_obj
|
// input :null_obj
|
||||||
String8 null_obj = lnk_make_null_obj(inputer->arena);
|
String8 null_obj = lnk_make_null_obj(inputer->arena);
|
||||||
lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null *"), null_obj);
|
lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null *"), null_obj);
|
||||||
@@ -1774,7 +1740,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// link inputer
|
// link inputer
|
||||||
lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps);
|
lnk_link_inputs(tp, arena, config, inputer, symtab, link);
|
||||||
|
|
||||||
// TODO: need to figure out under what condition to include load config
|
// TODO: need to figure out under what condition to include load config
|
||||||
//lnk_include_symbol(config, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME), 0);
|
//lnk_include_symbol(config, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME), 0);
|
||||||
@@ -1786,11 +1752,64 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
ProfEnd();
|
ProfEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
// make and input delayed imports
|
//
|
||||||
|
// make imports
|
||||||
|
//
|
||||||
{
|
{
|
||||||
String8List delayed_dll_names = imps->delayed_dll_names;
|
HashTable *static_imports_ht = hash_table_init(scratch.arena, 0x1000);
|
||||||
HashTable *delayed_imports_ht = imps->delayed_imports;
|
HashTable *delayed_imports_ht = hash_table_init(scratch.arena, 0x1000);
|
||||||
|
String8List delayed_dll_names = {0};
|
||||||
|
String8List static_dll_names = {0};
|
||||||
|
|
||||||
|
for EachNode(member_ref, LNK_LibMemberRef, link->imports.first) {
|
||||||
|
LNK_Lib *lib = member_ref->lib;
|
||||||
|
U64 member_idx = member_ref->member_idx;
|
||||||
|
LNK_Symbol *link_symbol = lib->member_links[member_idx];
|
||||||
|
|
||||||
|
COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_idx]);
|
||||||
|
COFF_DataType member_type = coff_data_type_from_data(member_info.data);
|
||||||
|
String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name);
|
||||||
|
COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(member_info.data);
|
||||||
|
|
||||||
|
// import machine compat check
|
||||||
|
if (import_header.machine != config->machine) {
|
||||||
|
LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol);
|
||||||
|
lnk_error_obj(LNK_Error_IncompatibleMachine,
|
||||||
|
ref.obj,
|
||||||
|
"symbol %S pulls-in import from %S with an incompatible machine %S (expected machine %S)",
|
||||||
|
link_symbol->name,
|
||||||
|
str8_chop_last_slash(lib->path),
|
||||||
|
coff_string_from_machine_type(import_header.machine),
|
||||||
|
coff_string_from_machine_type(config->machine));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find DLL with import symbols
|
||||||
|
B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name);
|
||||||
|
String8List *dll_names = is_delay_load ? &delayed_dll_names : &static_dll_names;
|
||||||
|
HashTable *imports_ht = is_delay_load ? delayed_imports_ht : static_imports_ht;
|
||||||
|
PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name);
|
||||||
|
|
||||||
|
// create record for a first time-DLL
|
||||||
|
if (import_symbols == 0) {
|
||||||
|
import_symbols = push_array(scratch.arena, PE_MakeImportList, 1);
|
||||||
|
str8_list_push(scratch.arena, dll_names, import_header.dll_name);
|
||||||
|
hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
B32 make_jump_thunk = 1;
|
||||||
|
if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) {
|
||||||
|
LNK_Symbol *thunk_symbol = lnk_symbol_table_search(symtab, str8_skip(link_symbol->name, str8_lit("__imp_").size));
|
||||||
|
make_jump_thunk = thunk_symbol != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push make import info
|
||||||
|
pe_make_import_header_list_push(scratch.arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = make_jump_thunk });
|
||||||
|
}
|
||||||
AssertAlways(delayed_dll_names.node_count == delayed_imports_ht->count);
|
AssertAlways(delayed_dll_names.node_count == delayed_imports_ht->count);
|
||||||
|
AssertAlways(static_dll_names.node_count == static_imports_ht->count);
|
||||||
|
|
||||||
|
// make and input delayed imports
|
||||||
if (delayed_imports_ht->count) {
|
if (delayed_imports_ht->count) {
|
||||||
ProfBegin("Build Delay Import Table");
|
ProfBegin("Build Delay Import Table");
|
||||||
|
|
||||||
@@ -1813,13 +1832,8 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// make and input static imports
|
// make and input static imports
|
||||||
{
|
|
||||||
String8List static_dll_names = imps->static_dll_names;
|
|
||||||
HashTable *static_imports_ht = imps->static_imports;
|
|
||||||
AssertAlways(static_dll_names.node_count == static_imports_ht->count);
|
|
||||||
if (static_imports_ht->count) {
|
if (static_imports_ht->count) {
|
||||||
ProfBegin("Build Static Import Table");
|
ProfBegin("Build Static Import Table");
|
||||||
|
|
||||||
@@ -1840,6 +1854,15 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// warn about unused delayloads
|
||||||
|
if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) {
|
||||||
|
for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) {
|
||||||
|
if (!hash_table_search_path_raw(delayed_imports_ht, dll_name_n->string)) {
|
||||||
|
lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->export_symbol_list.count) {
|
if (config->export_symbol_list.count) {
|
||||||
@@ -1967,7 +1990,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
//
|
//
|
||||||
// link linker made objs
|
// link linker made objs
|
||||||
//
|
//
|
||||||
lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps);
|
lnk_link_inputs(tp, arena, config, inputer, symtab, link);
|
||||||
|
|
||||||
//
|
//
|
||||||
// finalize symbol table
|
// finalize symbol table
|
||||||
@@ -2104,17 +2127,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
ProfEnd();
|
ProfEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// warn about unused delayloads
|
|
||||||
//
|
|
||||||
if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) {
|
|
||||||
for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) {
|
|
||||||
if (!hash_table_search_path_raw(imps->delayed_imports, dll_name_n->string)) {
|
|
||||||
lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// discard COMDAT sections that are not referenced
|
// discard COMDAT sections that are not referenced
|
||||||
//
|
//
|
||||||
|
|||||||
+12
-20
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
typedef struct LNK_LibMemberRef
|
typedef struct LNK_LibMemberRef
|
||||||
{
|
{
|
||||||
LNK_Lib *lib;
|
LNK_Lib *lib;
|
||||||
U32 member_idx;
|
U32 member_idx;
|
||||||
struct LNK_LibMemberRef *next;
|
struct LNK_LibMemberRef *next;
|
||||||
} LNK_LibMemberRef;
|
} LNK_LibMemberRef;
|
||||||
|
|
||||||
@@ -76,25 +76,17 @@ typedef struct LNK_Inputer
|
|||||||
#define LNK_SECTION_FLAG_IS_LIVE (1 << 0)
|
#define LNK_SECTION_FLAG_IS_LIVE (1 << 0)
|
||||||
#define LNK_SECTION_FLAG_DEBUG_INFO (1 << 1)
|
#define LNK_SECTION_FLAG_DEBUG_INFO (1 << 1)
|
||||||
|
|
||||||
typedef struct LNK_ImportTables
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
String8List delayed_dll_names;
|
|
||||||
String8List static_dll_names;
|
|
||||||
HashTable *static_imports;
|
|
||||||
HashTable *delayed_imports;
|
|
||||||
} LNK_ImportTables;
|
|
||||||
|
|
||||||
typedef struct LNK_Link
|
typedef struct LNK_Link
|
||||||
{
|
{
|
||||||
LNK_ObjList objs;
|
LNK_ObjList objs;
|
||||||
LNK_LibList libs;
|
LNK_LibList libs;
|
||||||
LNK_ObjNode **last_symbol_input;
|
LNK_ObjNode **last_symbol_input;
|
||||||
LNK_IncludeSymbolNode **last_include;
|
LNK_IncludeSymbolNode **last_include;
|
||||||
String8Node **last_cmd_lib;
|
String8Node **last_cmd_lib;
|
||||||
String8Node **last_default_lib;
|
String8Node **last_default_lib;
|
||||||
String8Node **last_obj_lib;
|
String8Node **last_obj_lib;
|
||||||
B32 try_to_resolve_entry_point;
|
LNK_LibMemberRefList imports;
|
||||||
|
B32 try_to_resolve_entry_point;
|
||||||
} LNK_Link;
|
} LNK_Link;
|
||||||
|
|
||||||
// -- Image Layout ------------------------------------------------------------
|
// -- Image Layout ------------------------------------------------------------
|
||||||
@@ -299,7 +291,7 @@ internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_Li
|
|||||||
|
|
||||||
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 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_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 void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link);
|
||||||
internal LNK_Link * lnk_link_image (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab);
|
internal LNK_Link * lnk_link_image (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab);
|
||||||
|
|
||||||
// --- Optimizations -----------------------------------------------------------
|
// --- Optimizations -----------------------------------------------------------
|
||||||
|
|||||||
+12
-19
@@ -137,10 +137,11 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L
|
|||||||
lib_out->path = push_str8_copy(arena, path);
|
lib_out->path = push_str8_copy(arena, path);
|
||||||
lib_out->data = data;
|
lib_out->data = data;
|
||||||
lib_out->type = type;
|
lib_out->type = type;
|
||||||
|
lib_out->member_count = member_count;
|
||||||
lib_out->symbol_count = Min(symbol_count, symbol_names.count); // TODO: warn about mismatched number of symbol names and symbol count in the header
|
lib_out->symbol_count = Min(symbol_count, symbol_names.count); // TODO: warn about mismatched number of symbol names and symbol count in the header
|
||||||
lib_out->member_offsets = member_offsets;
|
lib_out->member_offsets = member_offsets;
|
||||||
lib_out->symbol_indices = symbol_indices;
|
lib_out->symbol_indices = symbol_indices;
|
||||||
lib_out->was_member_linked = push_array(arena, LNK_Symbol *, member_count);
|
lib_out->member_links = push_array(arena, LNK_Symbol *, member_count);
|
||||||
lib_out->symbol_names = symbol_names;
|
lib_out->symbol_names = symbol_names;
|
||||||
lib_out->long_names = parse.long_names;
|
lib_out->long_names = parse.long_names;
|
||||||
lib_out->input_idx = input_idx;
|
lib_out->input_idx = input_idx;
|
||||||
@@ -225,41 +226,33 @@ lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol)
|
|||||||
{
|
{
|
||||||
local_persist LNK_Symbol null_symbol;
|
local_persist LNK_Symbol null_symbol;
|
||||||
|
|
||||||
B32 is_first_set;
|
LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], &null_symbol);
|
||||||
|
|
||||||
LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol);
|
B32 was_linked = (slot == 0);
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
is_first_set = (slot == 0);
|
|
||||||
|
|
||||||
|
for (LNK_Symbol *leader = link_symbol;;) {
|
||||||
// update slot symbol if it is empty or link symbol comes before symbol in the slot
|
// update slot symbol if it is empty or link symbol comes before symbol in the slot
|
||||||
if (slot && slot != &null_symbol) {
|
if (slot && slot != &null_symbol) {
|
||||||
if (!str8_starts_with(link_symbol->name, str8_lit("__imp_")) && str8_starts_with(slot->name, str8_lit("__imp_"))) {
|
if (lnk_symbol_is_before(slot, leader)) {
|
||||||
// replace import address symbol with jump thunk symbol
|
leader = slot;
|
||||||
slot = link_symbol;
|
|
||||||
is_first_set = 1;
|
|
||||||
} else if (str8_starts_with(link_symbol->name, str8_lit("__imp_")) && !str8_starts_with(slot->name, str8_lit("__imp_"))) {
|
|
||||||
// no need to replace
|
|
||||||
} else if (lnk_symbol_is_before(slot, link_symbol)) {
|
|
||||||
slot = link_symbol;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
slot = link_symbol;
|
leader = link_symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to insert back updated slot symbol
|
// try to insert back updated slot symbol
|
||||||
LNK_Symbol *was_replaced = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], slot, &null_symbol);
|
LNK_Symbol *swap = ins_atomic_ptr_eval_cond_assign(&lib->member_links[member_idx], leader, &null_symbol);
|
||||||
|
|
||||||
// exit if slot symbol was null
|
// exit if slot symbol was null
|
||||||
if (was_replaced == &null_symbol) {
|
if (swap == &null_symbol) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload slot symbol
|
// reload slot symbol
|
||||||
slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol);
|
slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], &null_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
return is_first_set;
|
return was_linked;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal force_inline B32
|
internal force_inline B32
|
||||||
|
|||||||
+11
-10
@@ -5,16 +5,17 @@
|
|||||||
|
|
||||||
typedef struct LNK_Lib
|
typedef struct LNK_Lib
|
||||||
{
|
{
|
||||||
String8 path;
|
String8 path;
|
||||||
String8 data;
|
String8 data;
|
||||||
COFF_ArchiveType type;
|
COFF_ArchiveType type;
|
||||||
U32 symbol_count;
|
U32 member_count;
|
||||||
U32 *member_offsets;
|
U32 symbol_count;
|
||||||
U16 *symbol_indices;
|
U32 *member_offsets;
|
||||||
LNK_Symbol **was_member_linked;
|
U16 *symbol_indices;
|
||||||
String8Array symbol_names;
|
LNK_Symbol **member_links;
|
||||||
String8 long_names;
|
String8Array symbol_names;
|
||||||
U64 input_idx;
|
String8 long_names;
|
||||||
|
U64 input_idx;
|
||||||
} LNK_Lib;
|
} LNK_Lib;
|
||||||
|
|
||||||
typedef struct LNK_LibNode
|
typedef struct LNK_LibNode
|
||||||
|
|||||||
@@ -551,7 +551,7 @@ lnk_symbol_table_init(TP_Arena *arena)
|
|||||||
LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1);
|
LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1);
|
||||||
symtab->arena = arena;
|
symtab->arena = arena;
|
||||||
symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count);
|
symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count);
|
||||||
symtab->weak_undef_chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count);
|
symtab->search_chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count);
|
||||||
return symtab;
|
return symtab;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +562,7 @@ lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK
|
|||||||
COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol);
|
COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol);
|
||||||
LNK_SymbolHashTrieChunkList *chunks;
|
LNK_SymbolHashTrieChunkList *chunks;
|
||||||
if (interp == COFF_SymbolValueInterp_Weak || interp == COFF_SymbolValueInterp_Undefined) {
|
if (interp == COFF_SymbolValueInterp_Weak || interp == COFF_SymbolValueInterp_Undefined) {
|
||||||
chunks = &symtab->weak_undef_chunks[worker_id];
|
chunks = &symtab->search_chunks[worker_id];
|
||||||
} else {
|
} else {
|
||||||
chunks = &symtab->chunks[worker_id];
|
chunks = &symtab->chunks[worker_id];
|
||||||
}
|
}
|
||||||
@@ -717,7 +717,7 @@ internal
|
|||||||
THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
|
THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
|
||||||
{
|
{
|
||||||
LNK_SymbolTable *symtab = raw_task;
|
LNK_SymbolTable *symtab = raw_task;
|
||||||
for EachNode(c, LNK_SymbolHashTrieChunk, symtab->weak_undef_chunks[task_id].first) {
|
for EachNode(c, LNK_SymbolHashTrieChunk, symtab->search_chunks[task_id].first) {
|
||||||
for EachIndex(i, c->count) {
|
for EachIndex(i, c->count) {
|
||||||
LNK_Symbol *symbol = c->v[i].symbol;
|
LNK_Symbol *symbol = c->v[i].symbol;
|
||||||
LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol);
|
LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol);
|
||||||
@@ -758,7 +758,7 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab)
|
|||||||
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_replace_weak_with_default_symbol_task, symtab, "Replace Weak With Default Symbols");
|
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_replace_weak_with_default_symbol_task, symtab, "Replace Weak With Default Symbols");
|
||||||
|
|
||||||
for EachIndex(i, tp->worker_count) {
|
for EachIndex(i, tp->worker_count) {
|
||||||
lnk_symbol_hash_trie_chunk_list_concat_in_place(&symtab->chunks[i], &symtab->weak_undef_chunks[i]);
|
lnk_symbol_hash_trie_chunk_list_concat_in_place(&symtab->chunks[i], &symtab->search_chunks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ typedef struct LNK_ObjSymbolRefNode
|
|||||||
typedef struct LNK_Symbol
|
typedef struct LNK_Symbol
|
||||||
{
|
{
|
||||||
String8 name;
|
String8 name;
|
||||||
B8 is_lib_member_linked;
|
|
||||||
LNK_ObjSymbolRefNode *refs;
|
LNK_ObjSymbolRefNode *refs;
|
||||||
} LNK_Symbol;
|
} LNK_Symbol;
|
||||||
|
|
||||||
@@ -76,7 +75,7 @@ typedef struct LNK_SymbolTable
|
|||||||
TP_Arena *arena;
|
TP_Arena *arena;
|
||||||
LNK_SymbolHashTrie *root;
|
LNK_SymbolHashTrie *root;
|
||||||
LNK_SymbolHashTrieChunkList *chunks;
|
LNK_SymbolHashTrieChunkList *chunks;
|
||||||
LNK_SymbolHashTrieChunkList *weak_undef_chunks;
|
LNK_SymbolHashTrieChunkList *search_chunks;
|
||||||
} LNK_SymbolTable;
|
} LNK_SymbolTable;
|
||||||
|
|
||||||
// --- Workers Contexts --------------------------------------------------------
|
// --- Workers Contexts --------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user