improve diagnostics for the missing entry point

This commit is contained in:
Nikita Smith committed 2026-08-13 15:02:19 -07:00
1 parent 6a34ee168f
commit 72c3dfd30c
5 files changed
+81 -30

No files matched your search

+1 -1
View File
@@ -199,7 +199,7 @@
#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1))
#define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1)
#define EachNode(it, T, first) (T *it = first; it != 0; it = it->next)
#define EachBit(it, flags) (U64 (_i_) = (flags), it = (flags) & -(flags); (_i_) != 0; (_i_) &= ((_i_) - 1), it = (flags) & -(flags))
#define EachBit(it, flags) (U64 (_i_) = (flags), it = (_i_) & -(_i_); (_i_) != 0; (_i_) &= ((_i_) - 1), it = (_i_) & -(_i_))
////////////////////////////////
//~ rjf: Memory Operation Macros
+31 -3
View File
@@ -1605,7 +1605,7 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
}
// by default terminal server is enabled for windows and console applications
if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_DLL) {
if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) {
config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE;
}
@@ -2397,7 +2397,35 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
// was entry point resolved?
//
if (config->entry_point_name.size == 0 || link->try_to_resolve_entry_point) {
lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol");
String8 machine_str = coff_string_from_machine_type(config->machine);
String8 subsystem_str = pe_string_from_subsystem(config->subsystem);
String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics);
String8List list = {0};
for EachIndex(i, entry_points.count) { str8_list_push(scratch.arena, &list, entry_points.v[i]); }
String8 default_entries = str8_list_join(scratch.arena, &list, &(StringJoin){.sep = ", "});
lnk_error(LNK_Error_EntryPoint,
"failed to infer entry point symbol from the inputs\n"
" Machine: %S\n"
" Subsystem: %S\n"
" Subsystem Ver: %llu.%llu\n"
" File Chars: %S\n"
" DLL Chars: %S\n"
" Default Entries: %S\n"
" User Entry: \"%S\"\n"
" Input Obj Count: %S\n"
" Input Lib Count: %S",
machine_str.size ? machine_str : str8_lit("Unknown"), // Machine
subsystem_str.size ? subsystem_str : str8_lit("Unknown"), // Version
config->subsystem_ver.major, config->subsystem_ver.minor, // Subsystem
pe_string_from_file_characteristics(scratch.arena, config->file_characteristics), // File Chars
pe_string_from_dll_characteristics(scratch.arena, config->dll_characteristics), // DLL Chars
default_entries.size ? default_entries : str8_lit("None"), // Default Entry Points
config->entry_point_name, // /ENTRY
str8_from_count(scratch.arena, config->input_list[LNK_Input_Obj].node_count), // Input Objects Count
str8_from_count(scratch.arena, config->input_list[LNK_Input_Lib].node_count) // Input Libs Count
);
}
//
@@ -6597,7 +6625,7 @@ lnk_run_linker(TP_Context *tp, TP_Arena *arena, LNK_Config *config)
//
// Import Library
//
if (config->build_imp_lib && (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL)) {
if (config->build_imp_lib && (config->file_characteristics & PE_ImageFileCharacteristic_DLL)) {
ProfBegin("Build Import Library");
lnk_timer_begin(LNK_Timer_Lib);
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
+9 -9
View File
@@ -897,9 +897,9 @@ lnk_get_base_addr(LNK_Config *config)
{
U64 base_addr = config->user_base_addr;
if (base_addr == 0) {
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
if (config->file_characteristics & PE_ImageFileCharacteristic_DLL) {
base_addr = coff_default_dll_base_from_machine(config->machine);
} else if (config->file_characteristics & PE_ImageFileCharacteristic_EXE) {
} else if (config->file_characteristics & PE_ImageFileCharacteristic_EXECUTABLE_IMAGE) {
if ((~config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE) && config->machine == COFF_MachineType_X64) {
base_addr = coff_default_exe_base_from_machine(COFF_MachineType_X86);
} else {
@@ -1397,7 +1397,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} break;
case LNK_CmdSwitch_Dll: {
config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL;
config->file_characteristics |= PE_ImageFileCharacteristic_DLL;
} break;
case LNK_CmdSwitch_DynamicBase: {
@@ -2112,7 +2112,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} break;
case LNK_CmdSwitch_Rad_Exe: {
lnk_cmd_switch_set_flag_16(obj, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_EXE);
lnk_cmd_switch_set_flag_16(obj, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_EXECUTABLE_IMAGE);
} break;
case LNK_CmdSwitch_Rad_Guid: {
@@ -2638,7 +2638,7 @@ lnk_apply_def_file_to_config(LNK_Config *config, String8 path, LNK_Obj *obj)
}
if (stmt == LNK_DefFileStmt_Library) {
config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL;
config->file_characteristics |= PE_ImageFileCharacteristic_DLL;
}
if (name.size != 0) {
@@ -2775,7 +2775,7 @@ lnk_config_init(LNK_CmdLine cmd_line)
// set default manifest resource id
if (config->manifest_resource_id == 0) {
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
if (config->file_characteristics & PE_ImageFileCharacteristic_DLL) {
config->manifest_resource_id = push_u64(arena, 2);
} else {
config->manifest_resource_id = push_u64(arena, 1);
@@ -2844,7 +2844,7 @@ lnk_config_init(LNK_CmdLine cmd_line)
}
// warn about unused large address aware flag
if ((~config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE) && (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL)) {
if ((~config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE) && (config->file_characteristics & PE_ImageFileCharacteristic_DLL)) {
lnk_error(LNK_Warning_NoLargeAddressAwarenessForDll, "/LARGEADDRESSAWARE:NO has no effect when specified together with /DLL");
}
@@ -2867,7 +2867,7 @@ lnk_config_init(LNK_CmdLine cmd_line)
// set flags for /FIXED
if (config->flags & LNK_ConfigFlag_Fixed) {
config->file_characteristics |= PE_ImageFileCharacteristic_STRIPPED;
config->file_characteristics |= PE_ImageFileCharacteristic_RELOCS_STRIPPED;
config->dll_characteristics &= ~PE_DllCharacteristic_DYNAMIC_BASE;
}
// if we don't have a fixed image and dynamic base switch
@@ -2886,7 +2886,7 @@ lnk_config_init(LNK_CmdLine cmd_line)
// handle empty /OUT
if (!config->out_path.size) {
String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]);
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_DLL) ? str8_lit("dll") : str8_lit("exe");
config->out_path = path_replace_file_extension(scratch.arena, name, ext);
}
+19 -1
View File
@@ -351,6 +351,24 @@ pe_string_from_load_config_guard_flags(Arena *arena, PE_LoadConfigGuardFlags fla
return result;
}
internal String8
pe_string_from_file_characteristics(Arena *arena, PE_ImageFileCharacteristics file_chars)
{
Temp scratch = scratch_begin(&arena, 1);
String8List result = {0};
for EachBit(i, file_chars) {
switch (i) {
#define X(ID, VAL, DISPLAY_STRING) case (1 << VAL): str8_list_push(scratch.arena, &result, str8_lit(DISPLAY_STRING)); break;
PE_ImageFileCharacteristic_XList
#undef X
default: str8_list_pushf(scratch.arena, &result, "%llu", i);
}
}
String8 string = str8_list_join(arena, &result, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return string;
}
internal String8
pe_string_from_dll_characteristics(Arena *arena, PE_DllCharacteristics dll_chars)
{
@@ -915,7 +933,7 @@ pe_get_entry_point_names(COFF_MachineType machine,
{
String8Array entry_point_names = {0};
if (file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
if (file_characteristics & PE_ImageFileCharacteristic_DLL) {
if (machine == COFF_MachineType_X86) {
read_only static String8 dll_entry_point_arr[] = {
str8_lit_comp("__DllMainCRTStartup@12"),
+21 -16
View File
@@ -53,25 +53,30 @@ enum
PE_WindowsSubsystem_COUNT = 14
};
#define PE_ImageFileCharacteristic_XList \
X(RELOCS_STRIPPED , 0 , "Relocations Stripped" ) \
X(EXECUTABLE_IMAGE , 1 , "Executable" ) \
X(LINE_NUMS_STRIPPED , 2 , "Line Numbers Stripped" ) \
X(LOCAL_SYMS_STRIPPED , 3 , "Local Symbols Stripped" ) \
X(AGGRESSIVE_WS_TRIM , 4 , "Aggressive Working Set Trim") \
X(LARGE_ADDRESS_AWARE , 5 , "Large Address Aware" ) \
X(RESERVED , 6 , "Reserved" ) \
X(BYTES_REVERSED_LO , 7 , "Bytes Reversed Low" ) \
X(32BIT_MACHINE , 8 , "32-Bit Machine" ) \
X(DEBUG_STRIPPED , 9 , "Debug Information Stripped" ) \
X(REMOVABLE_RUN_FROM_SWAP, 10, "Removable: Run from Swap" ) \
X(NET_RUN_FROM_SWAP , 11, "Network: Run from Swap" ) \
X(SYSTEM , 12, "System File" ) \
X(DLL , 13, "DLL" ) \
X(UP_SYSTEM_ONLY , 14, "Uniprocessor System Only" ) \
X(BYTES_REVERSED_HI , 15, "Bytes Reversed High" )
typedef U16 PE_ImageFileCharacteristics;
enum
{
PE_ImageFileCharacteristic_STRIPPED = (1 << 0),
PE_ImageFileCharacteristic_EXE = (1 << 1),
PE_ImageFileCharacteristic_NUMS_STRIPPED = (1 << 2),
PE_ImageFileCharacteristic_PE_STRIPPED = (1 << 3),
PE_ImageFileCharacteristic_AGGRESIVE_WS_TRIM = (1 << 4),
PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE = (1 << 5),
PE_ImageFileCharacteristic_UNUSED1 = (1 << 6),
PE_ImageFileCharacteristic_BYTES_RESERVED_LO = (1 << 7),
PE_ImageFileCharacteristic_32BIT_MACHINE = (1 << 8),
PE_ImageFileCharacteristic_DEBUG_STRIPPED = (1 << 9),
PE_ImageFileCharacteristic_FILE_REMOVABLE_RUN_FROM_SWAP = (1 << 10),
PE_ImageFileCharacteristic_NET_RUN_FROM_SWAP = (1 << 11),
PE_ImageFileCharacteristic_FILE_SYSTEM = (1 << 12),
PE_ImageFileCharacteristic_FILE_DLL = (1 << 13),
PE_ImageFileCharacteristic_FILE_UP_SYSTEM_ONLY = (1 << 14),
PE_ImageFileCharacteristic_BYTES_RESERVED_HI = (1 << 15),
#define X(ID, VAL, ...) PE_ImageFileCharacteristic_##ID = (1 << VAL),
PE_ImageFileCharacteristic_XList
#undef X
};
typedef U16 PE_DllCharacteristics;