fix duplicate defer import link

This commit is contained in:
Nikita Smith
2026-05-18 18:11:48 -07:00
parent 2f2c975a4a
commit e1e8ba826d
5 changed files with 410 additions and 42 deletions
+13
View File
@@ -757,6 +757,19 @@ hash_map_push_path_raw(Arena *arena, HashMap *hm, String8 path, void *value)
//////////////////////////////// ////////////////////////////////
internal void *
hash_map_search_stringf_raw(HashMap *hm, char *fmt, ...)
{
Temp scratch = scratch_begin(0,0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
void *raw = hash_map_search_string_raw(hm, string);
va_end(args);
scratch_end(scratch);
return raw;
}
internal void * internal void *
hash_map_search_string_raw(HashMap *hm, String8 key) hash_map_search_string_raw(HashMap *hm, String8 key)
{ {
+1
View File
@@ -175,6 +175,7 @@ internal HashMapNode * hash_map_push_path_u64 (Arena *arena, HashMap *hm, St
internal HashMapNode * hash_map_push_path_string (Arena *arena, HashMap *hm, String8 path, String8 value); internal HashMapNode * hash_map_push_path_string (Arena *arena, HashMap *hm, String8 path, String8 value);
internal HashMapNode * hash_map_push_path_raw (Arena *arena, HashMap *hm, String8 path, void *value); internal HashMapNode * hash_map_push_path_raw (Arena *arena, HashMap *hm, String8 path, void *value);
internal void * hash_map_search_stringf_raw(HashMap *hm, char *fmt, ...);
internal void * hash_map_search_string_raw(HashMap *hm, String8 key); internal void * hash_map_search_string_raw(HashMap *hm, String8 key);
internal U32 * hash_map_search_string_u32(HashMap *hm, String8 key); internal U32 * hash_map_search_string_u32(HashMap *hm, String8 key);
internal U64 * hash_map_search_string_u64(HashMap *hm, String8 key); internal U64 * hash_map_search_string_u64(HashMap *hm, String8 key);
+71 -23
View File
@@ -1487,7 +1487,14 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
} }
internal void internal void
lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *link_symbol, LNK_Lib *lib, LNK_LibMemberInfo *member_infos, U32 member_idx) lnk_queue_lib_member(Arena *arena,
HashMap *imports_hm,
HashMap lib_member_info_hm,
LNK_LibMemberRefList *queued_members,
LNK_Symbol *link_symbol,
LNK_Lib *lib,
LNK_LibMemberInfo *member_infos,
U32 member_idx)
{ {
// associate link symbol to lib member // associate link symbol to lib member
for (LNK_Symbol *leader = link_symbol;;) { for (LNK_Symbol *leader = link_symbol;;) {
@@ -1511,17 +1518,36 @@ lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Sym
} }
} }
B32 was_linked; LNK_LibMemberRef *is_thunk_import;
LNK_LibMemberRef *is_addr_import;
if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) {
is_thunk_import = hash_map_search_string_raw(imports_hm, str8_skip(link_symbol->name, 6));
is_addr_import = hash_map_search_string_raw(imports_hm, link_symbol->name);
} else {
is_thunk_import = hash_map_search_string_raw(imports_hm, link_symbol->name);
is_addr_import = hash_map_search_stringf_raw(imports_hm, "__imp_%S", link_symbol->name);
}
LNK_LibMemberRef *is_queued_import = is_thunk_import ? is_thunk_import :
is_addr_import ? is_addr_import : 0;
if (is_queued_import) {
// do not queue second import member link -- flag member and continue
U8 flag = str8_starts_with(link_symbol->name, str8_lit("__imp_")) ? LNK_LibMemberFlag_LinkedImp : LNK_LibMemberFlag_LinkedRegular;
LNK_LibMemberInfo *import_member_infos = hash_map_search_raw_raw(&lib_member_info_hm, is_queued_import->lib);
ins_atomic_u8_or(&import_member_infos[member_idx].flags, flag);
} else {
B32 do_queue;
if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) { if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) {
U8 member_flags = ins_atomic_u8_or(&member_infos[member_idx].flags, LNK_LibMemberFlag_LinkedImp); U8 member_flags = ins_atomic_u8_or(&member_infos[member_idx].flags, LNK_LibMemberFlag_LinkedImp);
was_linked = !(member_flags & LNK_LibMemberFlag_LinkedImp); do_queue = !(member_flags & LNK_LibMemberFlag_LinkedImp);
} else { } else {
U8 flag = LNK_LibMemberFlag_LinkedRegular; U8 flag = LNK_LibMemberFlag_LinkedRegular;
U8 member_flags = ins_atomic_u8_or(&member_infos[member_idx].flags, LNK_LibMemberFlag_LinkedRegular); U8 member_flags = ins_atomic_u8_or(&member_infos[member_idx].flags, LNK_LibMemberFlag_LinkedRegular);
was_linked = !(member_flags & LNK_LibMemberFlag_LinkedRegular); do_queue = !(member_flags & LNK_LibMemberFlag_LinkedRegular);
} }
if (was_linked) { if (do_queue) {
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;
@@ -1529,6 +1555,7 @@ lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Sym
lnk_lib_member_ref_list_push_node(queued_members, member_ref); lnk_lib_member_ref_list_push_node(queued_members, member_ref);
} }
} }
}
internal internal
THREAD_POOL_TASK_FUNC(lnk_search_lib_task) THREAD_POOL_TASK_FUNC(lnk_search_lib_task)
@@ -1550,14 +1577,14 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task)
if (symbol_interp == COFF_SymbolValueInterp_Undefined) { if (symbol_interp == COFF_SymbolValueInterp_Undefined) {
U32 member_idx; U32 member_idx;
if (lnk_search_lib(lib, symbol->name, &member_idx)) { if (lnk_search_lib(lib, symbol->name, &member_idx)) {
lnk_queue_lib_member(arena, member_ref_list, symbol, lib, lib_member_infos, member_idx); lnk_queue_lib_member(arena, task->imports_hm, task->link->lib_member_infos_hm, member_ref_list, symbol, lib, lib_member_infos, member_idx);
} }
} else if (symbol_interp == COFF_SymbolValueInterp_Weak) { } else if (symbol_interp == COFF_SymbolValueInterp_Weak) {
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol_ref.obj->header.is_big_obj); COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol_ref.obj->header.is_big_obj);
if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) {
U32 member_idx; U32 member_idx;
if (lnk_search_lib(lib, symbol->name, &member_idx)) { if (lnk_search_lib(lib, symbol->name, &member_idx)) {
lnk_queue_lib_member(arena, member_ref_list, symbol, lib, lib_member_infos, member_idx); lnk_queue_lib_member(arena, task->imports_hm, task->link->lib_member_infos_hm, member_ref_list, symbol, lib, lib_member_infos, member_idx);
} }
} else if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { } else if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) {
if (search_anti_deps) { if (search_anti_deps) {
@@ -1568,7 +1595,7 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task)
if (dep_interp == COFF_SymbolValueInterp_Weak) { if (dep_interp == COFF_SymbolValueInterp_Weak) {
U32 member_idx; U32 member_idx;
if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) { if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) {
lnk_queue_lib_member(arena, member_ref_list, symbol, lib, lib_member_infos, member_idx); lnk_queue_lib_member(arena, task->imports_hm, task->link->lib_member_infos_hm, member_ref_list, symbol, lib, lib_member_infos, member_idx);
} }
} }
} }
@@ -1624,6 +1651,8 @@ lnk_link_inputs(TP_Context *tp,
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(arena->v, arena->count); Temp scratch = scratch_begin(arena->v, arena->count);
HashMap imports_hm = {0};
LNK_LibMemberRefList *member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count); LNK_LibMemberRefList *member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count);
B32 search_anti_deps = 0; 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) {
@@ -1683,10 +1712,10 @@ lnk_link_inputs(TP_Context *tp,
} }
} }
LNK_LibMemberInfo *lib_member_infos = hash_table_search_raw_raw(link->lib_member_infos_ht, lib); LNK_LibMemberInfo *lib_member_infos = hash_map_search_raw_raw(&link->lib_member_infos_hm, lib);
if (lib_member_infos == 0) { if (lib_member_infos == 0) {
lib_member_infos = push_array(link->arena, LNK_LibMemberInfo, lib->member_count); lib_member_infos = push_array(link->arena, LNK_LibMemberInfo, lib->member_count);
hash_table_push_raw_raw(link->arena, link->lib_member_infos_ht, lib, lib_member_infos); hash_map_push_raw_raw(link->arena, &link->lib_member_infos_hm, lib, lib_member_infos);
} }
B32 link_whole_archive = config->whole_archive_all; B32 link_whole_archive = config->whole_archive_all;
@@ -1708,12 +1737,20 @@ lnk_link_inputs(TP_Context *tp,
} }
LNK_LibMemberRef *member_refs = push_array(scratch.arena, LNK_LibMemberRef, lib->member_count); LNK_LibMemberRef *member_refs = push_array(scratch.arena, LNK_LibMemberRef, lib->member_count);
for EachIndex(member_idx, lib->member_count) { for EachIndex(member_idx, lib->member_count) {
lnk_queue_lib_member(arena->v[0], &member_ref_lists[0], null_symbol, lib, lib_member_infos, member_idx); lnk_queue_lib_member(arena->v[0], &imports_hm, link->lib_member_infos_hm, &member_ref_lists[0], null_symbol, lib, lib_member_infos, member_idx);
} }
} else { } else {
// search symbols in lib // search symbols in lib
MemoryZeroTyped(member_ref_lists, tp->worker_count); MemoryZeroTyped(member_ref_lists, tp->worker_count);
LNK_SearchLibTask search_task = { .search_anti_deps = search_anti_deps, .lib = lib, .symtab = symtab, .lib_member_infos = lib_member_infos, .member_ref_lists = member_ref_lists }; LNK_SearchLibTask search_task = {
.search_anti_deps = search_anti_deps,
.link = link,
.imports_hm = &imports_hm,
.lib = lib,
.symtab = symtab,
.lib_member_infos = lib_member_infos,
.member_ref_lists = member_ref_lists
};
tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &search_task); tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &search_task);
} }
@@ -1765,6 +1802,25 @@ lnk_link_inputs(TP_Context *tp,
switch (member_type) { switch (member_type) {
case COFF_DataType_Import: { case COFF_DataType_Import: {
{
LNK_LibMemberRef *is_thunk_import;
LNK_LibMemberRef *is_addr_import;
if (str8_starts_with(member_ref->link_symbol->name, str8_lit("__imp_"))) {
is_thunk_import = hash_map_search_string_raw(&imports_hm, str8_skip(member_ref->link_symbol->name, 6));
is_addr_import = hash_map_search_string_raw(&imports_hm, member_ref->link_symbol->name);
} else {
is_thunk_import = hash_map_search_string_raw(&imports_hm, member_ref->link_symbol->name);
is_addr_import = hash_map_search_stringf_raw(&imports_hm, "__imp_%S", member_ref->link_symbol->name);
}
if (is_thunk_import != 0 || is_addr_import != 0) {
lnk_invalid_path("duplicate import member queue detected");
break;
}
}
// store lib member ref to import
hash_map_push_string_raw(scratch.arena, &imports_hm, member_ref->link_symbol->name, member_ref);
// find import stub // find import stub
LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB));
@@ -1775,10 +1831,8 @@ lnk_link_inputs(TP_Context *tp,
member_ref->link_symbol->refs = import_stub->refs; member_ref->link_symbol->refs = import_stub->refs;
// push import member for import obj generation // push import member for import obj generation
if (!(lib_member_infos[member_ref->member_idx].flags & LNK_LibMemberFlag_WasGenQueued)) {
lib_member_infos[member_ref->member_idx].flags |= LNK_LibMemberFlag_WasGenQueued;
lnk_lib_member_ref_list_push_node(&link->imports, member_ref); lnk_lib_member_ref_list_push_node(&link->imports, member_ref);
} lib_member_infos[member_ref->member_idx].flags |= LNK_LibMemberFlag_WasGenQueued;
} break; } break;
case COFF_DataType_BigObj: case COFF_DataType_BigObj:
case COFF_DataType_Obj: { case COFF_DataType_Obj: {
@@ -1867,7 +1921,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
link->last_default_lib = &config->input_default_lib_list.first; link->last_default_lib = &config->input_default_lib_list.first;
link->last_obj_lib = &config->input_obj_lib_list.first; link->last_obj_lib = &config->input_obj_lib_list.first;
link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first; link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first;
link->lib_member_infos_ht = hash_table_init(link->arena, Max(config->input_list[LNK_Input_Lib].node_count * 2, 1024));
link->try_to_resolve_entry_point = 1; link->try_to_resolve_entry_point = 1;
// input :null_obj // input :null_obj
@@ -1909,7 +1962,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
for EachNode(member_ref, LNK_LibMemberRef, link->imports.first) { for EachNode(member_ref, LNK_LibMemberRef, link->imports.first) {
LNK_Lib *lib = member_ref->lib; LNK_Lib *lib = member_ref->lib;
U64 member_idx = member_ref->member_idx; U64 member_idx = member_ref->member_idx;
LNK_LibMemberInfo *member_infos = hash_table_search_raw_raw(link->lib_member_infos_ht, lib); LNK_LibMemberInfo *member_infos = hash_map_search_raw_raw(&link->lib_member_infos_hm, lib);
LNK_Symbol *link_symbol = member_infos[member_idx].link; LNK_Symbol *link_symbol = member_infos[member_idx].link;
U32 member_offset = memory_read32(lib->member_offsets + member_idx); U32 member_offset = memory_read32(lib->member_offsets + member_idx);
@@ -1944,13 +1997,8 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols); 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 // push make import info
B32 make_jump_thunk = !!(member_infos[member_idx].flags & LNK_LibMemberFlag_LinkedRegular);
pe_make_import_header_list_push(scratch.arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = make_jump_thunk }); 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);
+3 -1
View File
@@ -99,7 +99,7 @@ typedef struct LNK_Link
String8Node **last_cmd_lib; String8Node **last_cmd_lib;
String8Node **last_default_lib; String8Node **last_default_lib;
String8Node **last_obj_lib; String8Node **last_obj_lib;
HashTable *lib_member_infos_ht; HashMap lib_member_infos_hm;
LNK_LibMemberRefList imports; LNK_LibMemberRefList imports;
B32 try_to_resolve_entry_point; B32 try_to_resolve_entry_point;
B32 asan_libs_resolved; B32 asan_libs_resolved;
@@ -204,6 +204,8 @@ typedef struct LNK_BaseRelocPageArray
typedef struct typedef struct
{ {
B32 search_anti_deps; B32 search_anti_deps;
LNK_Link *link;
HashMap *imports_hm;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_Symbol *import_stub; LNK_Symbol *import_stub;
LNK_Lib *lib; LNK_Lib *lib;
+313 -9
View File
@@ -1,15 +1,17 @@
// Copyright (c) Epic Games Tools // Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
internal T_Linker // TODO:
t_id_linker(void) // [x] defer_duplicate_imp_link
{ // [ ] opt_ref_comdat_undef_section
String8 name = str8_chop_last_dot(str8_skip_last_slash(g_linker)); // [ ] opt_ref_weak_alias_comdat
if (str8_match(name, str8_lit("radlink"), StringMatchFlag_CaseInsensitive)) { return T_Linker_RAD; } // [ ] reloc_apply_off_out_of_bounds
if (str8_match(name, str8_lit("link"), StringMatchFlag_CaseInsensitive)) { return T_Linker_MSVC; } // [ ] lib_member_reloc_apply_off_out_of_bounds
if (str8_match(name, str8_lit("lld-link"), StringMatchFlag_CaseInsensitive)) { return T_Linker_LLVM; } // [ ] fold_two_funcs
return T_Linker_Null; // [ ] same_but_different
} // [ ] fold_diamond
// [ ] cyclic_icf
// [ ] fold_with_largest_align
//////////////////////////////// ////////////////////////////////
// Def -> COFF // Def -> COFF
@@ -4553,6 +4555,118 @@ TEST(defer_impl_link_to_second_search_pass)
T_Ok(g_last_exit_code == 0); T_Ok(g_last_exit_code == 0);
} }
TEST(defer_duplicate_imp_link)
{
T_COFF_DefLib bar_lib_any = {
.members = (T_COFF_DefLibMember[]){
{
.type = T_COFF_DefLibMember_DllImportStatic,
.dll_import = { .name = "bar.dll" }
},
{
.type = T_COFF_DefLibMember_Import,
.import = { "bar.dll", "bar", COFF_ImportBy_Name, COFF_ImportHeader_Code, .hit_or_ordinal = 0 }
},
{
.type = T_COFF_DefLibMember_Obj,
.obj = {
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"text", ".text", str8_lit_comp("\xff\x25\x00\x00\x00\x00"), .flags = "rx:code"
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Undef("__imp_bar"),
T_COFF_DefSymbol_ExternFunc("qwe", "text", 0),
{0},
}
}
},
{0}
}
};
T_COFF_DefLib foo_lib_any = {
.members = (T_COFF_DefLibMember[]){
{
.type = T_COFF_DefLibMember_DllImportStatic,
.dll_import = { .name = "foo.dll" }
},
{
.type = T_COFF_DefLibMember_Import,
.import = { "foo.dll", "bar", COFF_ImportBy_Name, COFF_ImportHeader_Code, .hit_or_ordinal = 0 }
},
{
.type = T_COFF_DefLibMember_Obj,
.obj = {
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"text", ".text",
str8_lit_comp("\xff\x25\x00\x00\x00\x00"),
.flags = "rx:code",
.relocs = (T_COFF_DefReloc[]){
T_COFF_DefReloc(X64_Rel32, 2, "bar"),
{0}
}
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Undef("bar"),
T_COFF_DefSymbol_Undef("qwe"),
T_COFF_DefSymbol_ExternFunc("thunk", "text", 0),
{0},
}
}
},
{0}
}
};
String8 bar_lib = t_coff_from_def_lib(arena, bar_lib_any);
String8 foo_lib = t_coff_from_def_lib(arena, foo_lib_any);
T_Ok(t_write_file(str8_lit("bar.lib"), bar_lib));
T_Ok(t_write_file(str8_lit("foo.lib"), foo_lib));
T_Ok(t_write_entry_obj());
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe bar.lib foo.lib entry.obj /include:thunk");
T_Ok(g_last_exit_code == 0);
String8 exe = t_read_file(arena, str8_lit("a.exe"));
PE_BinInfo pe = pe_bin_info_from_data(arena, exe);
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str;
PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, pe.is_pe32, pe.section_count, section_table, exe, pe.data_dir_franges[PE_DataDirectoryIndex_IMPORT]);
COFF_SectionHeader *data_sect = coff_section_header_from_name(str8_zero(), section_table, pe.section_count, str8_lit(".data"));
T_Ok(static_imptab.count == 1);
PE_ParsedStaticDLLImport *dll = &static_imptab.v[0];
T_Ok(str8_matchi(dll->name, str8_lit("foo.dll")));
T_Ok(dll->import_count == 1);
PE_ParsedImport *imp = &dll->imports[0];
T_Ok(imp->type == PE_ParsedImport_Name);
T_Ok(str8_match(imp->u.name.string, str8_lit("bar"), 0));
U64 iat_foff = pe_foff_from_voff(exe, &pe, dll->import_address_table_voff);
U64 ilt_foff = pe_foff_from_voff(exe, &pe, dll->import_name_table_voff);
U64 bar_idx = 0;
U64 bar_iat_addr = 0;
U64 bar_ilt_addr = 0;
str8_deserial_read_struct(exe, iat_foff + bar_idx * sizeof(U64), &bar_iat_addr);
str8_deserial_read_struct(exe, ilt_foff + bar_idx * sizeof(U64), &bar_ilt_addr);
T_Ok(bar_iat_addr != 0);
T_Ok(bar_ilt_addr != 0);
T_Ok(bar_iat_addr == bar_ilt_addr);
T_Ok(data_sect->voff <= bar_iat_addr && bar_iat_addr < data_sect->voff + data_sect->vsize);
}
TEST(opt_ref_dangling_section) TEST(opt_ref_dangling_section)
{ {
T_Ok(t_write_def_obj("entry.obj", (T_COFF_DefObj){ T_Ok(t_write_def_obj("entry.obj", (T_COFF_DefObj){
@@ -6893,4 +7007,194 @@ TEST(fold_with_largest_align)
#endif #endif
#if 0
TEST(reloc_apply_off_out_of_bounds)
{
T_Ok(t_write_def_obj("bad.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"text", ".text", str8_lit_comp("\x00\x00\x00\x00"), .flags = "rx:code@1",
.relocs = (T_COFF_DefReloc[]){
T_COFF_DefReloc(X64_Addr32, max_U32, "target"),
{0}
}
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_AbsStatic("target", 0),
T_COFF_DefSymbol_Extern("entry", "text", 0),
{0}
}
}));
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe bad.obj");
T_Ok(g_last_exit_code != 0);
}
#endif
#if 0
TEST(lib_member_reloc_apply_off_out_of_bounds)
{
T_Ok(t_write_def_lib("bad.lib", (T_COFF_DefLib){
.emit_second_member = 1,
.members = (T_COFF_DefLibMember[]){
{
.type = T_COFF_DefLibMember_Obj,
.obj = {
.path = str8_lit("bad_member.obj"),
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"data", ".data", str8_lit_comp("\x00\x00\x00\x00"), .flags = "rw:data@1",
.relocs = (T_COFF_DefReloc[]){
T_COFF_DefReloc(X64_Addr32, max_U32, "target"),
{0}
}
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_AbsStatic("target", 0),
T_COFF_DefSymbol_Extern("bad", "data", 0),
{0}
}
}
},
{0}
}
}));
T_Ok(t_write_def_obj("entry.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{ "text", ".text", str8_lit_comp("\xC3"), .flags = "rx:code@1" },
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Extern("entry", "text", 0),
{0}
}
}));
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /include:bad entry.obj bad.lib");
T_Ok(g_last_exit_code != 0);
}
#endif
#if 0
TEST(opt_ref_comdat_undef_section)
{
T_Ok(t_write_def_obj("entry.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"text", ".text", str8_lit_comp("\x48\xC7\xC0\x00\x00\x00\x00\xC3"), .flags = "rx:code@1",
.relocs = (T_COFF_DefReloc[]){
T_COFF_DefReloc(X64_Addr32Nb, 3, "caller"),
{0}
}
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Extern("entry", "text", 0),
T_COFF_DefSymbol_Undef("caller"),
{0}
}
}));
T_Ok(t_write_def_obj("caller.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"caller", ".caller", str8_lit_comp("\x00\x00\x00\x00"), .flags = "rw:data@1", .raw_flags = COFF_SectionFlag_LnkCOMDAT,
.relocs = (T_COFF_DefReloc[]){
T_COFF_DefReloc(X64_Addr32Nb, 0, ".target"),
{0}
}
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Secdef("caller", COFF_ComdatSelect_Any),
T_COFF_DefSymbol_Extern("caller", "caller", 0),
T_COFF_DefSymbol_UndefSec(".target", COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead),
{0}
}
}));
T_Ok(t_write_def_obj("target.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{ "target", ".target", str8_lit("target"), .flags = "r:data@1", .raw_flags = COFF_SectionFlag_LnkCOMDAT },
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Secdef("target", COFF_ComdatSelect_Any),
{0}
}
}));
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj caller.obj target.obj");
T_Ok(g_last_exit_code == 0);
String8 exe = t_read_file(arena, str8_lit("a.exe"));
PE_BinInfo pe = pe_bin_info_from_data(arena, exe);
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str;
String8 string_table = str8_substr(exe, pe.string_table_range);
COFF_SectionHeader *target_sect = coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".target"));
T_Ok(target_sect != 0);
}
#endif
#if 0
TEST(opt_ref_weak_alias_comdat)
{
T_Ok(t_write_def_obj("weak.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{ "target", ".target", str8_lit("target"), .flags = "r:data@1", .raw_flags = COFF_SectionFlag_LnkCOMDAT },
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Secdef("target", COFF_ComdatSelect_Any),
T_COFF_DefSymbol_Extern("target", "target", 0),
T_COFF_DefSymbol_Weak("weak_target", COFF_WeakExt_SearchAlias, "target"),
{0}
}
}));
T_Ok(t_write_def_obj("entry.obj", (T_COFF_DefObj){
.machine = T_COFF_DefSetMachine(X64),
.sections = (T_COFF_DefSection[]){
{
"text", ".text", str8_lit_comp("\x48\xC7\xC0\x00\x00\x00\x00\xC3"), .flags = "rx:code@1",
.relocs = (T_COFF_DefReloc[]){
T_COFF_DefReloc(X64_Addr32Nb, 3, "weak_target"),
{0}
}
},
{0}
},
.symbols = (T_COFF_DefSymbol[]){
T_COFF_DefSymbol_Extern("entry", "text", 0),
T_COFF_DefSymbol_Undef("weak_target"),
{0}
}
}));
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj weak.obj");
T_Ok(g_last_exit_code == 0);
String8 exe = t_read_file(arena, str8_lit("a.exe"));
PE_BinInfo pe = pe_bin_info_from_data(arena, exe);
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str;
String8 string_table = str8_substr(exe, pe.string_table_range);
COFF_SectionHeader *target_sect = coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".target"));
T_Ok(target_sect != 0);
}
#endif
#undef T_Group #undef T_Group