Skip to content

Commit 1d7f0ce

Browse files
honkstar1NikitaSmith057
authored andcommitted
radlink: satisfy default-library names with explicitly supplied paths
1 parent 0e2b7ed commit 1d7f0ce

3 files changed

Lines changed: 88 additions & 0 deletions

File tree

‎src/linker/lnk.c‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ lnk_inputer_init(void)
818818
inputer->arena = arena;
819819
inputer->objs_ht = hash_table_init(arena, 0x20000);
820820
inputer->libs_ht = hash_table_init(arena, 0x1000);
821+
inputer->cmd_lib_names_ht = hash_table_init(arena, 0x100);
821822
inputer->missing_lib_ht = hash_table_init(arena, 0x100);
822823
return inputer;
823824
}
@@ -928,6 +929,13 @@ lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSou
928929
if (lnk_is_lib_disallowed(config, path)) {
929930
goto exit;
930931
}
932+
// An explicitly supplied library also satisfies a bare /DEFAULTLIB name,
933+
// even when its directory is not on LIBPATH. Do not strip directory parts
934+
// from the request: path-qualified defaults still name distinct libraries.
935+
input = hash_table_search_path_raw(inputer->cmd_lib_names_ht, path);
936+
if (input) {
937+
goto exit;
938+
}
931939
}
932940

933941
// was library already loaded?
@@ -964,6 +972,14 @@ lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSou
964972
}
965973

966974
exit:;
975+
if (input && input_source == LNK_InputSource_CmdLine) {
976+
// Keep basename aliases separate from path identity so two explicitly
977+
// supplied libraries with the same basename can both be linked.
978+
String8 name = str8_skip_last_slash(input->path);
979+
if (!hash_table_search_path(inputer->cmd_lib_names_ht, name)) {
980+
hash_table_push_path_raw(inputer->arena, inputer->cmd_lib_names_ht, name, input);
981+
}
982+
}
967983
scratch_end(scratch);
968984
return input;
969985
}

‎src/linker/lnk.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ typedef struct LNK_Inputer
6464
LNK_InputList new_objs;
6565

6666
HashTable *libs_ht;
67+
HashTable *cmd_lib_names_ht;
6768
HashTable *missing_lib_ht;
6869
LNK_InputList libs;
6970
LNK_InputList new_libs[LNK_InputSource_Count];

‎src/linker/tests/linker_tests.c‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,6 +2663,77 @@ TEST(base_relocs)
26632663
}
26642664
}
26652665

2666+
TEST(default_lib_matches_explicit_path)
2667+
{
2668+
COFF_ObjWriter *entry = coff_obj_writer_alloc(0, COFF_MachineType_X64);
2669+
COFF_ObjSection *text = coff_obj_writer_push_section(entry, str8_lit(".text"),
2670+
COFF_SectionFlag_CntCode|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemExecute|COFF_SectionFlag_Align1Bytes,
2671+
str8_lit("\x31\xc0\xc3"));
2672+
coff_obj_writer_push_symbol_extern_func(entry, str8_lit("entry"), 0, text);
2673+
T_Ok(t_write_file(str8_lit("entry.obj"), coff_obj_writer_serialize(arena, entry)));
2674+
coff_obj_writer_release(&entry);
2675+
char *dirs[] = {"sdk libs", "other libs"};
2676+
char *symbols[] = {"first_provider", "second_provider"};
2677+
for EachIndex(i, ArrayCount(dirs)) {
2678+
T_Ok(make_directory(t_make_file_path(arena, str8_cstring(dirs[i]))));
2679+
COFF_ObjWriter *obj = coff_obj_writer_alloc(0, COFF_MachineType_X64);
2680+
coff_obj_writer_push_symbol_abs(obj, str8_cstring(symbols[i]), 1, COFF_SymStorageClass_External);
2681+
COFF_LibWriter *lib = coff_lib_writer_alloc();
2682+
coff_lib_writer_push_obj(lib, str8_lit("provider.obj"), coff_obj_writer_serialize(arena, obj));
2683+
T_Ok(t_write_file(str8f(arena, "%s/provider.lib", dirs[i]), coff_lib_writer_serialize(arena, lib, 0, 0, 1)));
2684+
coff_lib_writer_release(&lib);
2685+
coff_obj_writer_release(&obj);
2686+
}
2687+
2688+
char *args = "/subsystem:console /entry:entry /out:default.exe entry.obj /include:first_provider";
2689+
String8 paths[] = {str8_lit("sdk libs/provider.lib"), t_make_file_path(arena, str8_lit("sdk libs/provider.lib"))};
2690+
// Debug builds also write normal progress to stderr; reject only the missing-library diagnostic.
2691+
char *names[] = {"provider.lib", "PROVIDER.LIB", "provider"};
2692+
// RAD accepts an omitted extension; LLD checks visited names before adding it.
2693+
U64 name_count = t_id_linker() == Linker_radlink ? ArrayCount(names) : 2;
2694+
for EachIndex(path_idx, ArrayCount(paths)) {
2695+
for EachIndex(name_idx, name_count) {
2696+
t_invoke_linkerf("%s \"%S\" /defaultlib:%s", args, paths[path_idx], names[name_idx]);
2697+
T_Ok(g_last_exit_code == 0);
2698+
T_Ok(str8_find_needle(g_errors, 0, str8_lit("unable to find library"), 0) == g_errors.size);
2699+
}
2700+
}
2701+
2702+
// Embedded directives use a separate input-source queue from /DEFAULTLIB.
2703+
COFF_ObjWriter *directive = coff_obj_writer_alloc(0, COFF_MachineType_X64);
2704+
coff_obj_writer_push_directive(directive, str8_lit("/DEFAULTLIB:provider.lib"));
2705+
T_Ok(t_write_file(str8_lit("directive.obj"), coff_obj_writer_serialize(arena, directive)));
2706+
coff_obj_writer_release(&directive);
2707+
t_invoke_linkerf("%s \"%S\" directive.obj", args, paths[1]);
2708+
T_Ok(g_last_exit_code == 0);
2709+
T_Ok(str8_find_needle(g_errors, 0, str8_lit("unable to find library"), 0) == g_errors.size);
2710+
2711+
// A basename match must not swallow another explicitly named library, or a
2712+
// path-qualified default, with the same basename but a different provider.
2713+
t_invoke_linkerf("%s \"%S\" \"other libs/provider.lib\" /include:second_provider", args, paths[1]);
2714+
T_Ok(g_last_exit_code == 0);
2715+
T_Ok(str8_find_needle(g_errors, 0, str8_lit("unable to find library"), 0) == g_errors.size);
2716+
t_invoke_linkerf("%s \"%S\" /defaultlib:\"other libs/provider.lib\" /include:second_provider", args, paths[1]);
2717+
T_Ok(g_last_exit_code == 0);
2718+
T_Ok(str8_find_needle(g_errors, 0, str8_lit("unable to find library"), 0) == g_errors.size);
2719+
2720+
// Missing defaults must still warn; explicit bare paths are not defaults.
2721+
t_invoke_linkerf("%s \"%S\" /defaultlib:missing_provider.lib", args, paths[1]);
2722+
if (t_id_linker() == Linker_radlink) {
2723+
T_Ok(g_last_exit_code == 0);
2724+
T_Ok(str8_find_needle(g_errors, 0, str8_lit("unable to find library `missing_provider.lib`"), 0) < g_errors.size);
2725+
} else {
2726+
T_Ok(g_last_exit_code != 0);
2727+
}
2728+
t_invoke_linkerf("%s \"%S\" provider.lib", args, paths[1]);
2729+
if (t_id_linker() == Linker_radlink) {
2730+
T_Ok(g_last_exit_code == 0);
2731+
T_Ok(str8_find_needle(g_errors, 0, str8_lit("unable to find library `provider.lib`"), 0) < g_errors.size);
2732+
} else {
2733+
T_Ok(g_last_exit_code != 0);
2734+
}
2735+
}
2736+
26662737
TEST(simple_lib_test)
26672738
{
26682739
String8 test_payload = str8_lit("The quick brown fox jumps over the lazy dog");

0 commit comments

Comments
 (0)