From 3cec629a8c7ca48f2032c3c5975116a93df6a2b4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 13 Jan 2025 15:22:18 -0800 Subject: [PATCH] pipe obj directives through config path --- src/linker/lnk.c | 19 +- src/linker/lnk_config.c | 1709 ++++++++++++++++++------------------ src/linker/lnk_config.h | 41 +- src/linker/lnk_directive.c | 94 +- src/linker/lnk_directive.h | 20 +- src/linker/lnk_error.c | 25 + src/linker/lnk_error.h | 2 + src/linker/lnk_obj.c | 24 +- 8 files changed, 993 insertions(+), 941 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index adab3ac3..1f80d3a2 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2895,7 +2895,7 @@ lnk_init_merge_directive_list(Arena *arena, LNK_ObjList obj_list) // collect merge directives from objs for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) { LNK_Obj *obj = &obj_node->data; - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Merge].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Merge].first; dir != 0; dir = dir->next) { for (String8Node *value_node = dir->value_list.first; value_node != 0; value_node = value_node->next) { LNK_MergeDirective merge_dir; if (lnk_parse_merge_directive(value_node->string, &merge_dir)) { lnk_merge_directive_list_push(arena, &result, merge_dir); @@ -3569,11 +3569,26 @@ lnk_run(int argc, char **argv) ProfBegin("Collect Directives"); for (U64 i = 0; i < obj_node_arr.count; ++i) { LNK_Obj *obj = &obj_node_arr.v[i].data; + str8_list_concat_in_place(&include_symbol_list, &obj->include_symbol_list); + lnk_alt_name_list_concat_in_place(&alt_name_list, &obj->alt_name_list); - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_DisallowLib].first; dir != 0; dir = dir->next) { + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_DisallowLib].first; dir != 0; dir = dir->next) { str8_list_concat_in_place(&input_disallow_lib_list, &dir->value_list); } + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Entry].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path); + } + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_SubSystem].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path); + } + + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Stack].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path); + } } ProfEnd(); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index b7610398..eb754b40 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -38,6 +38,7 @@ read_only struct { LNK_CmdSwitch_Dll, "DLL", "", "" }, { LNK_CmdSwitch_NotImplemented, "DRIVER", "", "" }, { LNK_CmdSwitch_DisallowLib, "DISALLOWLIB", ":LIBRARY", "", }, + { LNK_CmdSwitch_EditAndContinue, "EDITANDCONTINUE", "[:NO]", "" }, { LNK_CmdSwitch_DynamicBase, "DYNAMICBASE", "[:NO]", "" }, { LNK_CmdSwitch_NotImplemented, "EMITVOLATILEMETADATA", "", "" }, { LNK_CmdSwitch_Entry, "ENTRY", ":FUNCTION", "" }, @@ -46,11 +47,13 @@ read_only struct { LNK_CmdSwitch_NotImplemented, "EXPORTADMIN", "", "" }, { LNK_CmdSwitch_FastFail, "FASTFAIL", "", "Not used." }, { LNK_CmdSwitch_NotImplemented, "FASTGENPROFILE", "", "" }, + { LNK_CmdSwitch_FailIfMismatch, "FAILIFMISMATCH", "", "" }, { LNK_CmdSwitch_FileAlign, "FILEALIGN", ":#", "" }, { LNK_CmdSwitch_Fixed, "FIXED", "[:NO]", "" }, { LNK_CmdSwitch_NotImplemented, "FORCE", "", "" }, { LNK_CmdSwitch_FunctionPadMin, "FUNCTIONPADMIN", ":#", "Not Implemented" }, { LNK_CmdSwitch_NotImplemented, "GUARD", "", "" }, + { LNK_CmdSwitch_GuardSym, "GUARDSYM", "", "", }, { LNK_CmdSwitch_NotImplemented, "GENPROFILE", "", "" }, { LNK_CmdSwitch_Heap, "HEAP", "RESERVE[,COMMIT]", "" }, { LNK_CmdSwitch_HighEntropyVa, "HIGHENTROPYVA", "[:NO]", "" }, @@ -62,6 +65,8 @@ read_only struct { LNK_CmdSwitch_Include, "INCLUDE", "", "" }, { LNK_CmdSwitch_Incremental, "INCREMENTAL", "[:NO]", "Incremental linking is not supported." }, { LNK_CmdSwitch_NotImplemented, "INTEGRITYCHECK", "", "" }, + { LNK_CmdSwitch_InferAsanLibs, "INFERASANLIBS", "[:NO]", "" }, + { LNK_CmdSwitch_InferAsanLibsNo, "INFERASANLIBSNO", "", "", }, { LNK_CmdSwitch_NotImplemented, "KERNEL", "", "" }, { LNK_CmdSwitch_NotImplemented, "KEYCONTAINER", "", "" }, { LNK_CmdSwitch_NotImplemented, "KEYFILE", "", "" }, @@ -79,7 +84,7 @@ read_only struct { LNK_CmdSwitch_ManifestUac, "MANIFESTUAC", ":{NO|{'level'={'asInvoker'|'highestAvailable'|'requireAdministrator'} ['uiAccess'={'true'|'false'}]}}", "" }, { LNK_CmdSwitch_NotImplemented, "MAP", "", "" }, { LNK_CmdSwitch_NotImplemented, "MAPINFO", "", "" }, - { LNK_CmdSwitch_NotImplemented, "MERGE", "", "" }, + { LNK_CmdSwitch_Merge, "MERGE", ":from=to", "" }, { LNK_CmdSwitch_NotImplemented, "MIDL", "", "" }, { LNK_CmdSwitch_Natvis, "NATVIS", ":FILENAME", "" }, { LNK_CmdSwitch_NotImplemented, "NOASSEMBLY", "", "" }, @@ -110,6 +115,7 @@ read_only struct { LNK_CmdSwitch_NotImplemented, "TLBOUT", "", "" }, { LNK_CmdSwitch_NotImplemented, "TIME", "", "" }, { LNK_CmdSwitch_TsAware, "TSAWARE", "[:NO]", "" }, + { LNK_CmdSwitch_ThrowingNew, "THROWINGNEW", "", "" }, { LNK_CmdSwitch_NotImplemented, "USERPROFILE", "", "" }, { LNK_CmdSwitch_NotImplemented, "VERBOSE", "", "" }, { LNK_CmdSwitch_Version, "VERSION", "", "" }, @@ -158,6 +164,18 @@ read_only struct { LNK_CmdSwitch_Help, "?", "", "" }, }; +internal LNK_CmdSwitchType +lnk_cmd_switch_type_from_string(String8 name) +{ + for (U64 i = 0; i < ArrayCount(g_cmd_switch_map); ++i) { + String8 curr_name = str8_cstring(g_cmd_switch_map[i].name); + if (str8_match(curr_name, name, StringMatchFlag_CaseInsensitive)) { + return g_cmd_switch_map[i].type; + } + } + return LNK_CmdSwitch_Null; +} + internal String8 lnk_string_from_cmd_switch_type(LNK_CmdSwitchType type) { @@ -169,21 +187,6 @@ lnk_string_from_cmd_switch_type(LNK_CmdSwitchType type) return str8(0,0); } -internal LNK_CmdSwitchType -lnk_cmd_switch_type_from_string(String8 string) -{ - LNK_CmdSwitchType type = LNK_CmdSwitch_Null; - for (U64 icmd = 0; icmd < ArrayCount(g_cmd_switch_map); icmd += 1) { - String8 cmd_name = str8_cstring(g_cmd_switch_map[icmd].name); - if (str8_match(cmd_name, string, StringMatchFlag_CaseInsensitive)) { - type = g_cmd_switch_map[icmd].type; - break; - } - } - - return type; -} - read_only struct { char *name; LNK_InputType type; @@ -290,17 +293,16 @@ lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch) //////////////////////////////// internal void -lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt, ...) +lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...) { Temp scratch = scratch_begin(0,0); - va_list args; - va_start(args, fmt); + va_list args; va_start(args, fmt); String8 switch_name = lnk_string_from_cmd_switch_type(cmd_switch); - String8 message = push_str8fv(scratch.arena, fmt, args); - String8 output = push_str8f(scratch.arena, "/%S: %S", switch_name, message); - lnk_error(code, "%S", output); + String8 message = push_str8fv(scratch.arena, fmt, args); + String8 output = push_str8f(scratch.arena, "/%S: %S", switch_name, message); + lnk_error_with_loc(code, obj_path, lib_path, "%S", output); va_end(args); @@ -308,19 +310,19 @@ lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt } internal void -lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch) +lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch) { - lnk_error_cmd_switch(code, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(code, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } internal void -lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, String8 param) +lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param) { - lnk_error_cmd_switch(code, cmd_switch, "invalid parameter \"%S\"", param); + lnk_error_cmd_switch(code, obj_path, lib_path, cmd_switch, "invalid parameter \"%S\"", param); } internal String8 -lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd_switch, String8 string) +lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 string) { String8 result = string; B32 starts_with_quote = str8_match(str8_lit("\""), string, StringMatchFlag_RightSideSloppy); @@ -329,22 +331,22 @@ lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd result = str8_skip(result, 1); result = str8_chop(result, 1); } else { - lnk_error_cmd_switch(error_code, cmd_switch, "detected unmatched \" in \"%S\"", string); + lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "detected unmatched \" in \"%S\"", string); } } return result; } internal void -lnk_error_invalid_uac_level_param(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd_switch, String8 input) +lnk_error_invalid_uac_level_param(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 input) { - lnk_error_cmd_switch(error_code, cmd_switch, "invalid param format, expected \"level={'asInvoker'|'highestAvailable'|'requireAdministrator'}\" but got \"%S\"", input); + lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "invalid param format, expected \"level={'asInvoker'|'highestAvailable'|'requireAdministrator'}\" but got \"%S\"", input); } internal void -lnk_error_invalid_uac_ui_access_param(LNK_ErrorCode error_code, LNK_CmdSwitchType cmd_switch, String8 input) +lnk_error_invalid_uac_ui_access_param(LNK_ErrorCode error_code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 input) { - lnk_error_cmd_switch(error_code, cmd_switch, "invalid param format, expected \"uiAccess={'true'|'false'}\" but got \"%S\"", input); + lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "invalid param format, expected \"uiAccess={'true'|'false'}\" but got \"%S\"", input); } //////////////////////////////// @@ -363,6 +365,8 @@ lnk_get_default_function_pad_min(COFF_MachineType machine) } break; default: { lnk_error_cmd_switch(LNK_Error_Cmdl, + str8_zero(), + str8_zero(), LNK_CmdSwitch_FunctionPadMin, "default paramter is not defined for: %S", coff_string_from_machine_type(machine)); @@ -524,7 +528,7 @@ lnk_do_debug_info(LNK_Config *config) //////////////////////////////// internal B32 -lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_switch, Version *ver_out) +lnk_cmd_switch_parse_version(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out) { Temp scratch = scratch_begin(0,0); B32 is_parsed = 0; @@ -540,7 +544,7 @@ lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_sw maj_str = split_list.first->string; min_str = split_list.last->string; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid version format, too many dots, expected format: {N[.N]}"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid version format, too many dots, expected format: {N[.N]}"); goto exit; } @@ -550,13 +554,13 @@ lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_sw *ver_out = make_version(maj, min); is_parsed = 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse minor version"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse minor version"); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse major version"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse major version"); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } exit:; @@ -565,7 +569,7 @@ exit:; } internal B32 -lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_switch, Rng1U64 *tuple_out) +lnk_cmd_switch_parse_tuple(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out) { if (value_strings.node_count == 1) { U64 value; @@ -573,7 +577,7 @@ lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_swit tuple_out->v[0] = value; return 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse the parameter \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse the parameter \"%S\"", value_strings.first->string); } } else if (value_strings.node_count == 2) { U64 a,b; @@ -583,13 +587,13 @@ lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_swit tuple_out->v[1] = b; return 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable ot parse second parameter \"%S\"", value_strings.last->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable ot parse second parameter \"%S\"", value_strings.last->string); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse first parameter \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse first parameter \"%S\"", value_strings.first->string); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } return 0; } @@ -615,24 +619,24 @@ lnk_try_parse_u64(String8 string, LNK_ParseU64Flags flags, U64 *value_out) } internal B32 -lnk_cmd_switch_parse_u64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *value_out, LNK_ParseU64Flags flags) +lnk_cmd_switch_parse_u64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags) { if (value_strings.node_count != 1) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters, exepcted integer number as input"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters, exepcted integer number as input"); return 0; } if (!lnk_try_parse_u64(value_strings.first->string, flags, value_out)) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse string \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse string \"%S\"", value_strings.first->string); return 0; } return 1; } internal B32 -lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *value_out, LNK_ParseU64Flags flags) +lnk_cmd_switch_parse_u32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags) { U64 value; - if (lnk_cmd_switch_parse_u64(value_strings, cmd_switch, &value, flags | LNK_ParseU64Flag_CheckUnder32bit)) { + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &value, flags | LNK_ParseU64Flag_CheckUnder32bit)) { *value_out = (U32)value; return 1; } @@ -640,7 +644,7 @@ lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch } internal B32 -lnk_cmd_switch_parse_u64_list(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, U64List *list_out, LNK_ParseU64Flags flags) +lnk_cmd_switch_parse_u64_list(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64List *list_out, LNK_ParseU64Flags flags) { for (String8Node *string_n = value_strings.first; string_n != 0; string_n = string_n->next) { U64 value; @@ -653,11 +657,11 @@ lnk_cmd_switch_parse_u64_list(Arena *arena, String8List value_strings, LNK_CmdSw } internal B32 -lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switch, LNK_SwitchState *value_out) +lnk_cmd_switch_parse_flag(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out) { B32 is_parsed = 0; if (value_strings.node_count > 1) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "too many parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters"); } else if (value_strings.node_count == 1) { if (str8_match(value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { *value_out = LNK_SwitchState_No; @@ -669,7 +673,7 @@ lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switc *value_out = 1; is_parsed = 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid parameter \"%S\"", value_strings.first->string); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter \"%S\"", value_strings.first->string); } } else { *value_out = LNK_SwitchState_Yes; @@ -679,10 +683,10 @@ lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switc } internal void -lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits) +lnk_cmd_switch_set_flag_inv_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -692,10 +696,10 @@ lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_ } internal void -lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits) +lnk_cmd_switch_set_flag_inv_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -705,10 +709,10 @@ lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_ } internal void -lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits) +lnk_cmd_switch_set_flag_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -718,10 +722,10 @@ lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_swit } internal void -lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *flags, U32 bits) +lnk_cmd_switch_set_flag_32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -731,10 +735,10 @@ lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_swit } internal void -lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits) +lnk_cmd_switch_set_flag_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits) { LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(value_strings, cmd_switch, &state)) { + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { switch (state) { case LNK_SwitchState_Null: break; case LNK_SwitchState_Yes : *flags |= bits; break; @@ -744,25 +748,25 @@ lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_swit } internal B32 -lnk_cmd_switch_parse_string(String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out) +lnk_cmd_switch_parse_string(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out) { if (value_strings.node_count == 1) { if (value_strings.first->string.size > 0) { *string_out = value_strings.first->string; return 1; } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "empty string is not permitted"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "empty string is not permitted"); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); } return 0; } internal void -lnk_cmd_switch_parse_string_copy(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out) +lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out) { - if (lnk_cmd_switch_parse_string(value_strings, cmd_switch, string_out)) { + if (lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, string_out)) { *string_out = push_str8_copy(arena, *string_out); } } @@ -883,6 +887,798 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string) return result; } +internal void +lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, String8 obj_path, String8 lib_path) +{ + Temp scratch = scratch_begin(&arena,1); + + LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name); + + switch (cmd_switch) { + case LNK_CmdSwitch_Null: { + String8 value = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); + lnk_error_with_loc(LNK_Warning_UnknownSwitch, obj_path, lib_path, "unknown switch: \"/%S%s%S\"", cmd_name, value.size ? ":" : "", value); + } break; + + default: { InvalidPath; } break; + + case LNK_CmdSwitch_NotImplemented: { + String8 value = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); + lnk_not_implemented("switch \"%S\" is not implemented \"%S\"", cmd_name, value); + } break; + + case LNK_CmdSwitch_Align: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->sect_align, LNK_ParseU64Flag_CheckPow2); + } break; + + case LNK_CmdSwitch_AllowBind: { + lnk_cmd_switch_set_flag_inv_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_NO_BIND); + } break; + + case LNK_CmdSwitch_AllowIsolation: { + lnk_cmd_switch_set_flag_inv_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_NO_ISOLATION); + } break; + + case LNK_CmdSwitch_AlternateName: { + String8 *error_string = lnk_parse_alt_name_directive_list(arena, value_strings, &config->alt_name_list); + if (error_string != 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid syntax \"%S\", expected format \"FROM=TO\"", *error_string); + } + } break; + + case LNK_CmdSwitch_AppContainer: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_APPCONTAINER); + } break; + + case LNK_CmdSwitch_Base: { + if (value_strings.node_count == 2) { + String8Node *first_node = value_strings.first; + //String8Node *second_node = first_node->next; + B32 is_response_file = str8_match(str8_lit("@"), first_node->string, StringMatchFlag_RightSideSloppy); + if (is_response_file) { + //String8 file_path = first_node->string; + //String8 tag = second_node->string; + lnk_not_implemented("Response files are not implemented for /BASE"); + } else { + Rng1U64 addr_size = {0}; + if (lnk_cmd_switch_parse_tuple(obj_path, lib_path, cmd_switch, value_strings, &addr_size)) { + config->user_base_addr = addr_size.v[0]; + config->max_image_size = addr_size.v[1]; + } + } + } else if (value_strings.node_count == 1) { + U64 addr; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &addr, 0)) { + config->user_base_addr = addr; + } + } else if (value_strings.node_count == 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "expected at least 1 parameter"); + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters"); + } + } break; + + case LNK_CmdSwitch_Debug: { + if (value_strings.node_count == 0) { + config->debug_mode = LNK_DebugMode_Full; + } else if (value_strings.node_count == 1) { + LNK_DebugMode debug_mode = lnk_debug_mode_from_string(value_strings.first->string); + if (debug_mode == LNK_DebugMode_GHash) { + config->debug_mode = LNK_DebugMode_Full; + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "GHASH is not supported, switching to FULL"); + } else if (debug_mode == LNK_DebugMode_FastLink) { + config->debug_mode = LNK_DebugMode_Full; + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "FASTLINK is not supported, switching to FULL"); + } else if (debug_mode != LNK_DebugMode_Null) { + config->debug_mode = debug_mode; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_DefaultLib: { + String8List default_lib_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->input_default_lib_list, &default_lib_list); + } break; + + case LNK_CmdSwitch_Delay: { + if (value_strings.node_count == 0 || value_strings.node_count > 1) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } else { + String8 value = value_strings.first->string; + if (str8_match(value, str8_lit("unload"), StringMatchFlag_CaseInsensitive)) { + config->flags |= LNK_ConfigFlag_DelayUnload; + } else if (str8_match(value, str8_lit("nobind"), StringMatchFlag_CaseInsensitive)) { + config->flags &= ~LNK_ConfigFlag_DelayBind; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value); + } + } + } break; + + case LNK_CmdSwitch_DelayLoad: { + String8List delay_load_dll_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->delay_load_dll_list, &delay_load_dll_list); + } break; + + case LNK_CmdSwitch_Dll: { + config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL; + } break; + + case LNK_CmdSwitch_DisallowLib: { + lnk_not_implemented("TODO: how is this switch different from /nodefaultlib?"); + } break; + + case LNK_CmdSwitch_DynamicBase: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_DYNAMIC_BASE); + } break; + + case LNK_CmdSwitch_Entry: { + String8 new_entry_point_name = {0}; + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &new_entry_point_name); + + if (config->entry_point_name.size) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "unable to redefine entry point \"%S\" to \"%S\"", config->entry_point_name, new_entry_point_name); + break; + } + + config->entry_point_name = new_entry_point_name; + } break; + + case LNK_CmdSwitch_FastFail: { + // do nothing + } break; + + case LNK_CmdSwitch_FileAlign: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->file_align, LNK_ParseU64Flag_CheckPow2); + } break; + + case LNK_CmdSwitch_Fixed: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_Fixed); + } break; + + case LNK_CmdSwitch_FunctionPadMin: { + if (value_strings.node_count == 0) { + config->function_pad_min = 0; // :function_pad_min + } else { + local_persist U64 function_pad_min; + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &function_pad_min, LNK_ParseU64Flag_CheckUnder32bit); + config->function_pad_min = &function_pad_min; + } + } break; + + case LNK_CmdSwitch_Heap: { + Rng1U64 reserve_commit; + reserve_commit.v[0] = config->heap_reserve; + reserve_commit.v[1] = config->heap_commit; + if (lnk_cmd_switch_parse_tuple(obj_path, lib_path, cmd_switch, value_strings, &reserve_commit)) { + if (reserve_commit.v[0] >= reserve_commit.v[1]) { + U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); + U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); +#if 0 + if (reserve_aligned != reserve_commit.v[0]) { + lnk_error_cmd_switch(LNK_WARNING_CMDL, obj_path, lib_path, cmd_switch, "reserve is not power of two, aligned to %u bytes", reserve_aligned); + } + if (commit_aligned != reserve_commit.v[1]) { + lnk_error_cmd_switch(LNK_WARNING_CMDL, obj_path, lib_path, cmd_switch, "commit is not power of two, aligned to %u bytes", commit_aligned); + } +#endif + config->heap_reserve = reserve_aligned; + config->heap_commit = commit_aligned; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); + } + } + } break; + + case LNK_CmdSwitch_HighEntropyVa: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_HIGH_ENTROPY_VA); + } break; + + case LNK_CmdSwitch_Ignore: { + U64 error_code; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &error_code, 0)) { + switch (error_code) { + case LNK_MsWarningCode_UnsuedDelayLoadDll: { + lnk_suppress_error(LNK_Warning_UnusedDelayLoadDll); + } break; + case LNK_MsWarningCode_MissingExternalTypeServer: { + lnk_suppress_error(LNK_Warning_MissingExternalTypeServer); + } break; + case LNK_MsWarningCode_SectionFlagsConflict: { + lnk_suppress_error(LNK_Warning_SectionFlagsConflict); + } break; + default: { + lnk_not_implemented("TODO: /IGNORE:%llu", error_code); + } break; + } + } + } break; + + case LNK_CmdSwitch_ImpLib: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->imp_lib_name); + } break; + + case LNK_CmdSwitch_Include: { + String8List include_symbol_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->include_symbol_list, &include_symbol_list); + } break; + + case LNK_CmdSwitch_Incremental: { + LNK_SwitchState state; + if (lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &state)) { + if (state == LNK_SwitchState_Yes) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "incremental linkage is not supported"); + } + } + } break; + + case LNK_CmdSwitch_LargeAddressAware: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); + } break; + + case LNK_CmdSwitch_LibPath: { + String8List lib_dir_list = str8_list_copy(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); + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "path doesn't exist %S", full_path); + } + } + str8_list_concat_in_place(&config->lib_dir_list, &lib_dir_list); + } break; + + case LNK_CmdSwitch_Machine: { + if (value_strings.node_count == 1) { + COFF_MachineType machine = coff_machine_from_string(value_strings.first->string); + if (machine != COFF_MachineType_UNKNOWN) { + config->machine = machine; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Manifest: { + if (value_strings.node_count == 1) { + String8List param_list = str8_split_by_string_chars(scratch.arena, value_strings.first->string, str8_lit(","), 0); + String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); + if (param_arr.count > 0) { + if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { + config->manifest_opt = LNK_ManifestOpt_Embed; + + if (param_arr.count == 1) { + config->manifest_resource_id = 0; + } else if (param_arr.count > 1) { + // parse resource id + if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); + String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); + 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); + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]); + } + } else { + lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); + } + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } else if (str8_match(param_arr.v[0], str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + config->manifest_opt = LNK_ManifestOpt_No; + } else { + lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); + } + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } else if (value_strings.node_count == 0) { + config->manifest_opt = LNK_ManifestOpt_WriteToFile; + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } break; + + case LNK_CmdSwitch_ManifestDependency: { + String8List manifest_dependency_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); + + if (config->manifest_opt == LNK_ManifestOpt_Null) { + config->manifest_opt = LNK_ManifestOpt_WriteToFile; + } + } break; + + case LNK_CmdSwitch_ManifestFile: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->manifest_name); + } break; + + case LNK_CmdSwitch_ManifestInput: { + // see :manifest_input + } break; + + case LNK_CmdSwitch_ManifestUac: { + if (value_strings.node_count == 1) { + String8 uac = lnk_error_check_and_strip_quotes(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, value_strings.first->string); + String8List param_list = str8_split_by_string_chars(scratch.arena, uac, str8_lit(" "), 0); + String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); + if (param_arr.count > 0) { + if (str8_match(str8_lit("level="), param_arr.v[0], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + String8 level_param = param_arr.v[0]; + String8List level_list = str8_split_by_string_chars(scratch.arena, level_param, str8_lit("="), 0); + if (level_list.node_count == 2) { + if (str8_match(level_list.first->string, str8_lit("level"), StringMatchFlag_CaseInsensitive)) { + String8 level = level_list.last->string; + if (str8_match(level, str8_lit("'asInvoker'"), 0) || + str8_match(level, str8_lit("'highestAvailable'"), 0) || + str8_match(level, str8_lit("'requireAdministrator'"), 0)) { + // manifest level was parsed! + config->manifest_uac = 1; + config->manifest_level = push_str8_copy(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); + if (ui_access_list.node_count == 2) { + String8 ui_access = ui_access_list.last->string; + if (str8_match(ui_access, str8_lit("'true'"), 0) || + str8_match(ui_access, str8_lit("'false'"), 0)) { + // ui access was parsed! + config->manifest_ui_access = push_str8_copy(arena, ui_access); + } else { + lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, ui_access_param); + } + } else { + lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, ui_access_param); + } + } + } else { + lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); + } + } else { + lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); + } + } else { + lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, level_param); + } + } else if (str8_match(str8_lit("no"), param_arr.v[0], StringMatchFlag_CaseInsensitive)) { + config->manifest_uac = 0; + } else { + lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, param_arr.v[0]); + } + } else { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "empty param string"); + } + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch); + } + } break; + + case LNK_CmdSwitch_Natvis: { + // warn about invalid natvis extension + for (String8Node *node = value_strings.first; node != 0; node = node->next) { + String8 ext = str8_skip_last_dot(node->string); + if (!str8_match(ext, str8_lit("natvis"), StringMatchFlag_CaseInsensitive)) { + lnk_error_cmd_switch(LNK_Warning_InvalidNatvisFileExt, obj_path, lib_path, cmd_switch, "Visual Studio expects .natvis extension: \"%S\"", node->string); + } + } + + String8List natvis_list = str8_list_copy(arena, &value_strings); + str8_list_concat_in_place(&config->natvis_list, &natvis_list); + } break; + + case LNK_CmdSwitch_NoDefaultLib: { + 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); + } + } break; + + case LNK_CmdSwitch_NoExp: { + config->build_exp = 0; + } break; + + case LNK_CmdSwitch_NoImpLib: { + config->build_imp_lib = 0; + } break; + + case LNK_CmdSwitch_NoLogo: { + // we don't print logo + } break; + + case LNK_CmdSwitch_NxCompat: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->dll_characteristics, PE_DllCharacteristic_NX_COMPAT); + } break; + + case LNK_CmdSwitch_Opt: { + for (String8Node *n = value_strings.first; n != 0; n = n->next) { + String8 param = n->string; + if (str8_match(param, str8_lit("ref"), StringMatchFlag_CaseInsensitive)) { + config->opt_ref = LNK_SwitchState_Yes; + } else if (str8_match(param, str8_lit("noref"), StringMatchFlag_CaseInsensitive)) { + config->opt_ref = LNK_SwitchState_No; + } else if (str8_match(param, str8_lit("icf"), StringMatchFlag_CaseInsensitive) || + str8_match(param, str8_lit("icf="), StringMatchFlag_CaseInsensitive | StringMatchFlag_RightSideSloppy)) { + String8List vals = str8_split_by_string_chars(scratch.arena, param, str8_lit("="), 0); + if (vals.node_count > 2) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "too many parameters for iteration"); + continue; + } + if (vals.node_count == 2) { + B32 is_parsed = try_u64_from_str8_c_rules(vals.last->string, &config->opt_iter_count); + if (!is_parsed) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse iterations \"%S\"", vals.last->string); + continue; + } + } + config->opt_icf = LNK_SwitchState_Yes; + } else if (str8_match(param, str8_lit("noicf"), StringMatchFlag_CaseInsensitive)) { + config->opt_icf = LNK_SwitchState_No; + } else if (str8_match(param, str8_lit("lbr"), StringMatchFlag_CaseInsensitive)) { + config->opt_lbr = LNK_SwitchState_Yes; + } else if (str8_match(param, str8_lit("nolibr"), StringMatchFlag_CaseInsensitive)) { + config->opt_lbr = LNK_SwitchState_No; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown option \"%S\"", param); + } + } + } break; + + case LNK_CmdSwitch_Out: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->image_name); + } break; + + case LNK_CmdSwitch_Pdb: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->pdb_name); + } break; + + case LNK_CmdSwitch_PdbAltPath: { + // see :PdbAltPath + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->pdb_alt_path); + } break; + + case LNK_CmdSwitch_PdbPageSize: { + U64 page_size; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &page_size, LNK_ParseU64Flag_CheckPow2)) { + if (page_size >= MSF_MIN_PAGE_SIZE) { + if (page_size < MSF_MAX_PAGE_SIZE) { + config->pdb_page_size = page_size; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "page size must be <= %u bytes", MSF_MAX_PAGE_SIZE); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "page size must be >= %u bytes", MSF_MIN_PAGE_SIZE); + } + } + } break; + + case LNK_CmdSwitch_Release: { + if (value_strings.node_count == 0) { + config->flags |= LNK_ConfigFlag_WriteImageChecksum; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Stack: { + Rng1U64 reserve_commit; + reserve_commit.v[0] = config->stack_reserve; + reserve_commit.v[1] = config->stack_commit; + if (lnk_cmd_switch_parse_tuple(obj_path, lib_path, cmd_switch, value_strings, &reserve_commit)) { + if (reserve_commit.v[0] >= reserve_commit.v[1]) { + U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); + U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); +#if 0 + if (reserve_aligned != reserve_commit.v[0]) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "reserve is not power of two, aligned to %u", reserve_aligned); + } + if (commit_aligned != reserve_commit.v[1]) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "commit is not power of two, aligned to %u", commit_aligned); + } +#endif + config->stack_reserve = reserve_aligned; + config->stack_commit = commit_aligned; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); + } + } + } break; + + case LNK_CmdSwitch_SubSystem: { + if (value_strings.node_count <= 2 && value_strings.node_count > 0) { + // set subsystem type + PE_WindowsSubsystem subsystem = pe_subsystem_from_string(value_strings.first->string); + if (subsystem != PE_WindowsSubsystem_UNKNOWN) { + if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "overriding subystem \"%S\" with \"%S\"", + pe_string_from_subsystem(config->subsystem), + pe_string_from_subsystem(subsystem)); + } + config->subsystem = subsystem; + + // parse version (optional) + if (value_strings.node_count == 2) { + str8_list_pop_front(&value_strings); // pop subsystem parameter + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->subsystem_ver); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid subsystem \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Time: { + } break; + + case LNK_CmdSwitch_TsAware: { + lnk_cmd_switch_set_flag_inv_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_NoTsAware); + } break; + + case LNK_CmdSwitch_Version: { + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->image_ver); + } break; + + case LNK_CmdSwitch_Rad_Age: { + lnk_cmd_switch_parse_u32(obj_path, lib_path, cmd_switch, value_strings, &config->age, 0); + } break; + + case LNK_CmdSwitch_Rad_BuildInfo: { + lnk_print_build_info(); + os_abort(0); + } break; + + case LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll); + } break; + + case LNK_CmdSwitch_Rad_Debug: { + lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug); + } break; + case LNK_CmdSwitch_Rad_DebugName: { + // :Rad_DebugAltPath + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug_name); + } break; + + case LNK_CmdSwitch_Rad_DebugAltPath: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug_alt_path); + } break; + + case LNK_CmdSwitch_Rad_DelayBind: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_DelayBind); + } break; + + case LNK_CmdSwitch_Rad_DoMerge: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_Merge); + } break; + + case LNK_CmdSwitch_Rad_EnvLib: { + lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_EnvLib); + } break; + + case LNK_CmdSwitch_Rad_Exe: { + lnk_cmd_switch_set_flag_16(obj_path, lib_path, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_EXE); + } break; + + case LNK_CmdSwitch_Rad_Guid: { + if (value_strings.node_count == 1) { + if (str8_match(value_strings.first->string, str8_lit("imageblake3"), StringMatchFlag_CaseInsensitive)) { + config->guid_type = Lnk_DebugInfoGuid_ImageBlake3; + } else if (str8_match(value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) { + config->guid = os_make_guid(); + } else { + Guid guid; + if (try_guid_from_string(value_strings.first->string, &guid)) { + config->guid = guid; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse \"%S\"", value_strings.first->string); + } + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters, expected GUID formatted as following: \"0000000-0000-0000-0000-000000000000\""); + } + } break; + + case LNK_CmdSwitch_Rad_IdleWorkers: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->idle_worker_count, 0); + } break; + + case LNK_CmdSwitch_Rad_LargePages: { + if (value_strings.node_count == 0) { + OS_ProcessInfo *process_info = os_get_process_info(); + if (process_info->large_pages_allowed) { + arena_default_flags |= ArenaFlag_LargePages; + } else { + lnk_error_cmd_switch(LNK_Warning_LargePages, obj_path, lib_path, cmd_switch, "Large pages aren't enabled on this system."); +#if OS_WINDOWS + lnk_supplement_error("To enable large pages:"); + lnk_supplement_error("\t- Press Win+R and open \"gpedit.msc\""); + lnk_supplement_error("\t- Navigate to Local Computer Policy > Computer Configuration > Windows Settings > Security Settings > Local Policies > User Rights And Assignments"); + lnk_supplement_error("\t- Double-click on \"Lock pages in memory\""); + lnk_supplement_error("\t- Click \"Add User or Group...\""); + lnk_supplement_error("\t- Type in your user name"); + lnk_supplement_error("\t- Click Oks and reboot the machine"); +#endif + } + } else if (value_strings.node_count == 1) { + if (str8_match(value_strings.first->string, str8_lit("quiet"), StringMatchFlag_CaseInsensitive)) { + OS_ProcessInfo *process_info = os_get_process_info(); + if (process_info->large_pages_allowed) { + arena_default_flags |= ArenaFlag_LargePages; + } + } else if (str8_match(value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { + arena_default_flags &= ~ArenaFlag_LargePages; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid parameter: \"%S\", expected NO or QUIET", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Rad_LinkVer: { + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->link_ver); + } break; + + case LNK_CmdSwitch_Rad_Log: { + if (value_strings.node_count == 1) { + if (str8_match(value_strings.first->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { + for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { + lnk_set_log_status((LNK_LogType)ilog, 1); + } + } else if (str8_match(value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) { + lnk_set_log_status(LNK_Log_IO_Read, 1); + lnk_set_log_status(LNK_Log_IO_Write, 1); + } else { + LNK_LogType log_type = lnk_log_type_from_string(value_strings.first->string); + if (log_type == LNK_Log_Null) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); + } else { + lnk_set_log_status(log_type, 1); + } + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters, expected 1"); + } + } break; + + case LNK_CmdSwitch_Rad_MtPath: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->mt_path); + } break; + + case LNK_CmdSwitch_Rad_OsVer: { + lnk_cmd_switch_parse_version(obj_path, lib_path, cmd_switch, value_strings, &config->os_ver); + } break; + + case LNK_CmdSwitch_Rad_PageSize: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->page_size, 0); + } break; + + case LNK_CmdSwitch_Rad_PathStyle: { + if (value_strings.node_count == 1) { + PathStyle path_style = path_style_from_string(str8_list_first(&value_strings)); + if (path_style != PathStyle_Null) { + config->path_style = path_style; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unable to parse parameter \"%S\"", value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters"); + } + } break; + + case LNK_CmdSwitch_Rad_PdbHashTypeNames: { + String8 mode_string = str8_list_first(&value_strings); + + LNK_TypeNameHashMode mode; + if (mode_string.size == 0) { + config->pdb_hash_type_names = LNK_TypeNameHashMode_Lenient; + } else { + mode = lnk_type_name_hash_mode_from_string(mode_string); + if (mode == LNK_TypeNameHashMode_Null) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter: \"%S\"", mode_string); + } else { + config->pdb_hash_type_names = mode; + } + } + } break; + + case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->pdb_hash_type_name_map); + } break; + + case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->pdb_hash_type_name_length, 0); + } break; + + case LNK_CmdSwitch_Rad_SectVirtOff: { + U64 sect_virt_off; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, §_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) { + if (sect_virt_off >= 0x1000) { + config->section_virt_off = sect_virt_off; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "section virtual offset must be >= 0x1000"); + } + } + } break; + + case LNK_CmdSwitch_Rad_SuppressError: { + U64List error_code_list = {0}; + if (lnk_cmd_switch_parse_u64_list(scratch.arena, obj_path, lib_path, cmd_switch, value_strings, &error_code_list, 0)) { + for (U64Node *error_code_n = error_code_list.first; error_code_n != 0; error_code_n = error_code_n->next) { + if (error_code_n->data < LNK_Error_Count) { + lnk_suppress_error(error_code_n->data); + } else { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "unknown error code %llu", error_code_n->data); + } + } + } + } break; + + case LNK_CmdSwitch_Rad_SymbolTableCapDefined: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_defined, 0); + } break; + case LNK_CmdSwitch_Rad_SymbolTableCapInternal: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_internal, 0); + } break; + case LNK_CmdSwitch_Rad_SymbolTableCapWeak: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_weak, 0); + } break; + case LNK_CmdSwitch_Rad_SymbolTableCapLib: { + lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->symbol_table_cap_lib, 0); + } break; + + case LNK_CmdSwitch_Rad_TargetOs: { + if (value_strings.node_count == 1) { + String8 os_string = str8_list_first(&value_strings); + OperatingSystem target_os = operating_system_from_string(os_string); + if (target_os != OperatingSystem_Null) { + config->target_os = target_os; + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown operating system type %S", os_string); + } + } else { + lnk_error_cmd_switch(LNK_Warning_Cmdl, obj_path, lib_path, cmd_switch, "expected 1 parameter"); + } + } break; + + case LNK_CmdSwitch_Rad_TimeStamp: { + lnk_cmd_switch_parse_u32(obj_path, lib_path, cmd_switch, value_strings, &config->time_stamp, 0); + } break; + + case LNK_CmdSwitch_Rad_Version: { + fprintf(stdout, "%s\n", BUILD_TITLE_STRING_LITERAL); + os_abort(0); + } break; + + case LNK_CmdSwitch_Rad_Workers: { + U64 worker_count; + if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &worker_count, 0)) { + config->worker_count = worker_count; + } + } break; + + case LNK_CmdSwitch_Help: { + lnk_print_help(); + os_abort(0); + } break; + } + + scratch_end(scratch); +} + internal LNK_Config * lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) { @@ -894,8 +1690,8 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); // setup default flags - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FileAlign, "%u", 512); if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); @@ -928,7 +1724,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); - #if BUILD_DEBUG lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write"); @@ -954,777 +1749,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // process command line switches for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { - LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string); - switch (cmd_switch) { - case LNK_CmdSwitch_Null: { - String8 value = str8_list_join(scratch.arena, &cmd->value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); - lnk_error(LNK_Warning_UnknownSwitch, "unknown switch: \"/%S%s%S\"", cmd->string, value.size ? ":" : "", value); - } break; - - default: { InvalidPath; } break; - - case LNK_CmdSwitch_NotImplemented: { - String8 value = str8_list_join(scratch.arena, &cmd->value_strings, &(StringJoin){.sep=str8_lit_comp(",")}); - lnk_not_implemented("switch \"%S\" is not implemented \"%S\"", cmd->string, value); - } break; - - case LNK_CmdSwitch_Align: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->sect_align, LNK_ParseU64Flag_CheckPow2); - } break; - - case LNK_CmdSwitch_AllowBind: { - lnk_cmd_switch_set_flag_inv_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_NO_BIND); - } break; - - case LNK_CmdSwitch_AllowIsolation: { - lnk_cmd_switch_set_flag_inv_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_NO_ISOLATION); - } break; - - case LNK_CmdSwitch_AlternateName: { - String8 *error_string = lnk_parse_alt_name_directive_list(arena, cmd->value_strings, &config->alt_name_list); - if (error_string != 0) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax \"%S\", expected format \"FROM=TO\"", *error_string); - } - } break; - - case LNK_CmdSwitch_AppContainer: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_APPCONTAINER); - } break; - - case LNK_CmdSwitch_Base: { - if (cmd->value_strings.node_count == 2) { - String8Node *first_node = cmd->value_strings.first; - //String8Node *second_node = first_node->next; - B32 is_response_file = str8_match(str8_lit("@"), first_node->string, StringMatchFlag_RightSideSloppy); - if (is_response_file) { - //String8 file_path = first_node->string; - //String8 tag = second_node->string; - lnk_not_implemented("Response files are not implemented for /BASE"); - } else { - Rng1U64 addr_size = {0}; - if (lnk_cmd_switch_parse_tuple(cmd->value_strings, cmd_switch, &addr_size)) { - config->user_base_addr = addr_size.v[0]; - config->max_image_size = addr_size.v[1]; - } - } - } else if (cmd->value_strings.node_count == 1) { - U64 addr; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &addr, 0)) { - config->user_base_addr = addr; - } - } else if (cmd->value_strings.node_count == 0) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "expected at least 1 parameter"); - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "too many parameters"); - } - } break; - - case LNK_CmdSwitch_Debug: { - if (cmd->value_strings.node_count == 0) { - config->debug_mode = LNK_DebugMode_Full; - } else if (cmd->value_strings.node_count == 1) { - LNK_DebugMode debug_mode = lnk_debug_mode_from_string(cmd->value_strings.first->string); - if (debug_mode == LNK_DebugMode_GHash) { - config->debug_mode = LNK_DebugMode_Full; - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "GHASH is not supported, switching to FULL"); - } else if (debug_mode == LNK_DebugMode_FastLink) { - config->debug_mode = LNK_DebugMode_Full; - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "FASTLINK is not supported, switching to FULL"); - } else if (debug_mode != LNK_DebugMode_Null) { - config->debug_mode = debug_mode; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid parameter \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_DefaultLib: { - String8List default_lib_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->input_default_lib_list, &default_lib_list); - } break; - - case LNK_CmdSwitch_Delay: { - if (cmd->value_strings.node_count == 0 || cmd->value_strings.node_count > 1) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } else { - String8 value = cmd->value_strings.first->string; - if (str8_match(value, str8_lit("unload"), StringMatchFlag_CaseInsensitive)) { - config->flags |= LNK_ConfigFlag_DelayUnload; - } else if (str8_match(value, str8_lit("nobind"), StringMatchFlag_CaseInsensitive)) { - config->flags &= ~LNK_ConfigFlag_DelayBind; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter \"%S\"", value); - } - } - } break; - - case LNK_CmdSwitch_DelayLoad: { - String8List delay_load_dll_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->delay_load_dll_list, &delay_load_dll_list); - } break; - - case LNK_CmdSwitch_Dll: { - config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL; - } break; - - case LNK_CmdSwitch_DisallowLib: { - lnk_not_implemented("TODO: how is this switch different from /nodefaultlib?"); - } break; - - case LNK_CmdSwitch_DynamicBase: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_DYNAMIC_BASE); - } break; - - case LNK_CmdSwitch_Entry: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->user_entry_point_name); - config->entry_point_name = config->user_entry_point_name; - } break; - - case LNK_CmdSwitch_FastFail: { - // do nothing - } break; - - case LNK_CmdSwitch_FileAlign: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->file_align, LNK_ParseU64Flag_CheckPow2); - } break; - - case LNK_CmdSwitch_Fixed: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Fixed); - } break; - - case LNK_CmdSwitch_FunctionPadMin: { - if (cmd->value_strings.node_count == 0) { - config->function_pad_min = 0; // :function_pad_min - } else { - local_persist U64 function_pad_min; - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &function_pad_min, LNK_ParseU64Flag_CheckUnder32bit); - config->function_pad_min = &function_pad_min; - } - } break; - - case LNK_CmdSwitch_Heap: { - Rng1U64 reserve_commit; - reserve_commit.v[0] = config->heap_reserve; - reserve_commit.v[1] = config->heap_commit; - if (lnk_cmd_switch_parse_tuple(cmd->value_strings, cmd_switch, &reserve_commit)) { - if (reserve_commit.v[0] >= reserve_commit.v[1]) { - U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); - U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); -#if 0 - if (reserve_aligned != reserve_commit.v[0]) { - lnk_error_cmd_switch(LNK_WARNING_CMDL, cmd_switch, "reserve is not power of two, aligned to %u bytes", reserve_aligned); - } - if (commit_aligned != reserve_commit.v[1]) { - lnk_error_cmd_switch(LNK_WARNING_CMDL, cmd_switch, "commit is not power of two, aligned to %u bytes", commit_aligned); - } -#endif - config->heap_reserve = reserve_aligned; - config->heap_commit = commit_aligned; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); - } - } - } break; - - case LNK_CmdSwitch_HighEntropyVa: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_HIGH_ENTROPY_VA); - } break; - - case LNK_CmdSwitch_Ignore: { - U64 error_code; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &error_code, 0)) { - switch (error_code) { - case LNK_MsWarningCode_UnsuedDelayLoadDll: { - lnk_suppress_error(LNK_Warning_UnusedDelayLoadDll); - } break; - case LNK_MsWarningCode_MissingExternalTypeServer: { - lnk_suppress_error(LNK_Warning_MissingExternalTypeServer); - } break; - case LNK_MsWarningCode_SectionFlagsConflict: { - lnk_suppress_error(LNK_Warning_SectionFlagsConflict); - } break; - default: { - lnk_not_implemented("TODO: /IGNORE:%llu", error_code); - } break; - } - } - } break; - - case LNK_CmdSwitch_ImpLib: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->imp_lib_name); - } break; - - case LNK_CmdSwitch_Include: { - String8List include_symbol_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->include_symbol_list, &include_symbol_list); - } break; - - case LNK_CmdSwitch_Incremental: { - LNK_SwitchState state; - if (lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &state)) { - if (state == LNK_SwitchState_Yes) { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "incremental linkage is not supported"); - } - } - } break; - - case LNK_CmdSwitch_LargeAddressAware: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->file_characteristics, PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); - } break; - - case LNK_CmdSwitch_LibPath: { - String8List lib_dir_list = str8_list_copy(arena, &cmd->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); - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "path doesn't exist %S", full_path); - } - } - str8_list_concat_in_place(&config->lib_dir_list, &lib_dir_list); - } break; - - case LNK_CmdSwitch_Machine: { - if (cmd->value_strings.node_count == 1) { - COFF_MachineType machine = coff_machine_from_string(cmd->value_strings.first->string); - if (machine != COFF_MachineType_UNKNOWN) { - config->machine = machine; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Manifest: { - if (cmd->value_strings.node_count == 1) { - String8List param_list = str8_split_by_string_chars(scratch.arena, cmd->value_strings.first->string, str8_lit(","), 0); - String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); - if (param_arr.count > 0) { - if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) { - config->manifest_opt = LNK_ManifestOpt_Embed; - - if (param_arr.count == 1) { - config->manifest_resource_id = 0; - } else if (param_arr.count > 1) { - // parse resource id - if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); - String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); - 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); - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]); - } - } else { - lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); - } - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } else if (str8_match(param_arr.v[0], str8_lit("no"), StringMatchFlag_CaseInsensitive)) { - config->manifest_opt = LNK_ManifestOpt_No; - } else { - lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); - } - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } else if (cmd->value_strings.node_count == 0) { - config->manifest_opt = LNK_ManifestOpt_WriteToFile; - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } break; - - case LNK_CmdSwitch_ManifestDependency: { - String8List manifest_dependency_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); - - if (config->manifest_opt == LNK_ManifestOpt_Null) { - config->manifest_opt = LNK_ManifestOpt_WriteToFile; - } - } break; - - case LNK_CmdSwitch_ManifestFile: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->manifest_name); - } break; - - case LNK_CmdSwitch_ManifestInput: { - // see :manifest_input - } break; - - case LNK_CmdSwitch_ManifestUac: { - if (cmd->value_strings.node_count == 1) { - String8 uac = lnk_error_check_and_strip_quotes(LNK_Error_Cmdl, cmd_switch, cmd->value_strings.first->string); - String8List param_list = str8_split_by_string_chars(scratch.arena, uac, str8_lit(" "), 0); - String8Array param_arr = str8_array_from_list(scratch.arena, ¶m_list); - if (param_arr.count > 0) { - if (str8_match(str8_lit("level="), param_arr.v[0], StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - String8 level_param = param_arr.v[0]; - String8List level_list = str8_split_by_string_chars(scratch.arena, level_param, str8_lit("="), 0); - if (level_list.node_count == 2) { - if (str8_match(level_list.first->string, str8_lit("level"), StringMatchFlag_CaseInsensitive)) { - String8 level = level_list.last->string; - if (str8_match(level, str8_lit("'asInvoker'"), 0) || - str8_match(level, str8_lit("'highestAvailable'"), 0) || - str8_match(level, str8_lit("'requireAdministrator'"), 0)) { - // manifest level was parsed! - config->manifest_uac = 1; - config->manifest_level = push_str8_copy(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); - if (ui_access_list.node_count == 2) { - String8 ui_access = ui_access_list.last->string; - if (str8_match(ui_access, str8_lit("'true'"), 0) || - str8_match(ui_access, str8_lit("'false'"), 0)) { - // ui access was parsed! - config->manifest_ui_access = push_str8_copy(arena, ui_access); - } else { - lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, cmd_switch, ui_access_param); - } - } else { - lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, cmd_switch, ui_access_param); - } - } - } else { - lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, cmd_switch, level_param); - } - } else { - lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, cmd_switch, level_param); - } - } else { - lnk_error_invalid_uac_level_param(LNK_Error_Cmdl, cmd_switch, level_param); - } - } else if (str8_match(str8_lit("no"), param_arr.v[0], StringMatchFlag_CaseInsensitive)) { - config->manifest_uac = 0; - } else { - lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); - } - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "empty param string"); - } - } else { - lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); - } - } break; - - case LNK_CmdSwitch_Natvis: { - // warn about invalid natvis extension - for (String8Node *node = cmd->value_strings.first; node != 0; node = node->next) { - String8 ext = str8_skip_last_dot(node->string); - if (!str8_match(ext, str8_lit("natvis"), StringMatchFlag_CaseInsensitive)) { - lnk_error_cmd_switch(LNK_Warning_InvalidNatvisFileExt, cmd_switch, "Visual Studio expects .natvis extension: \"%S\"", node->string); - } - } - - String8List natvis_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->natvis_list, &natvis_list); - } break; - - case LNK_CmdSwitch_NoDefaultLib: { - if (cmd->value_strings.node_count == 0) { - config->no_default_libs = 1; - } else { - String8List no_default_lib_list = str8_list_copy(arena, &cmd->value_strings); - str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list); - } - } break; - - case LNK_CmdSwitch_NoExp: { - config->build_exp = 0; - } break; - - case LNK_CmdSwitch_NoImpLib: { - config->build_imp_lib = 0; - } break; - - case LNK_CmdSwitch_NoLogo: { - // we don't print logo - } break; - - case LNK_CmdSwitch_NxCompat: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->dll_characteristics, PE_DllCharacteristic_NX_COMPAT); - } break; - - case LNK_CmdSwitch_Opt: { - for (String8Node *n = cmd->value_strings.first; n != 0; n = n->next) { - String8 param = n->string; - if (str8_match(param, str8_lit("ref"), StringMatchFlag_CaseInsensitive)) { - config->opt_ref = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("noref"), StringMatchFlag_CaseInsensitive)) { - config->opt_ref = LNK_SwitchState_No; - } else if (str8_match(param, str8_lit("icf"), StringMatchFlag_CaseInsensitive) || - str8_match(param, str8_lit("icf="), StringMatchFlag_CaseInsensitive | StringMatchFlag_RightSideSloppy)) { - String8List vals = str8_split_by_string_chars(scratch.arena, param, str8_lit("="), 0); - if (vals.node_count > 2) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "too many parameters for iteration"); - continue; - } - if (vals.node_count == 2) { - B32 is_parsed = try_u64_from_str8_c_rules(vals.last->string, &config->opt_iter_count); - if (!is_parsed) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse iterations \"%S\"", vals.last->string); - continue; - } - } - config->opt_icf = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("noicf"), StringMatchFlag_CaseInsensitive)) { - config->opt_icf = LNK_SwitchState_No; - } else if (str8_match(param, str8_lit("lbr"), StringMatchFlag_CaseInsensitive)) { - config->opt_lbr = LNK_SwitchState_Yes; - } else if (str8_match(param, str8_lit("nolibr"), StringMatchFlag_CaseInsensitive)) { - config->opt_lbr = LNK_SwitchState_No; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown option \"%S\"", param); - } - } - } break; - - case LNK_CmdSwitch_Out: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->image_name); - } break; - - case LNK_CmdSwitch_Pdb: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_name); - } break; - - case LNK_CmdSwitch_PdbAltPath: { - // see :PdbAltPath - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_alt_path); - } break; - - case LNK_CmdSwitch_PdbPageSize: { - U64 page_size; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &page_size, LNK_ParseU64Flag_CheckPow2)) { - if (page_size >= MSF_MIN_PAGE_SIZE) { - if (page_size < MSF_MAX_PAGE_SIZE) { - config->pdb_page_size = page_size; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "page size must be <= %u bytes", MSF_MAX_PAGE_SIZE); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "page size must be >= %u bytes", MSF_MIN_PAGE_SIZE); - } - } - } break; - - case LNK_CmdSwitch_Release: { - if (cmd->value_strings.node_count == 0) { - config->flags |= LNK_ConfigFlag_WriteImageChecksum; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Stack: { - Rng1U64 reserve_commit; - reserve_commit.v[0] = config->stack_reserve; - reserve_commit.v[1] = config->stack_commit; - if (lnk_cmd_switch_parse_tuple(cmd->value_strings, cmd_switch, &reserve_commit)) { - if (reserve_commit.v[0] >= reserve_commit.v[1]) { - U64 reserve_aligned = AlignPow2(reserve_commit.v[0], 4); - U64 commit_aligned = AlignPow2(reserve_commit.v[1], 4); -#if 0 - if (reserve_aligned != reserve_commit.v[0]) { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "reserve is not power of two, aligned to %u", reserve_aligned); - } - if (commit_aligned != reserve_commit.v[1]) { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "commit is not power of two, aligned to %u", commit_aligned); - } -#endif - config->stack_reserve = reserve_aligned; - config->stack_commit = commit_aligned; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "commit(%llu) is greater than reserve(%llu)", reserve_commit.v[1], reserve_commit.v[0]); - } - } - } break; - - case LNK_CmdSwitch_SubSystem: { - if (cmd->value_strings.node_count <= 2 && cmd->value_strings.node_count > 0) { - // set subsystem type - PE_WindowsSubsystem subsystem = pe_subsystem_from_string(cmd->value_strings.first->string); - if (subsystem != PE_WindowsSubsystem_UNKNOWN) { - config->subsystem = subsystem; - - // parse version (optional) - if (cmd->value_strings.node_count == 2) { - String8List value_strings = cmd->value_strings; - str8_list_pop_front(&value_strings); // pop subsystem parameter - lnk_cmd_switch_parse_version(value_strings, cmd_switch, &config->subsystem_ver); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid subsystem \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Time: { - } break; - - case LNK_CmdSwitch_TsAware: { - lnk_cmd_switch_set_flag_inv_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_NoTsAware); - } break; - - case LNK_CmdSwitch_Version: { - lnk_cmd_switch_parse_version(cmd->value_strings, cmd_switch, &config->image_ver); - } break; - - case LNK_CmdSwitch_Rad_Age: { - lnk_cmd_switch_parse_u32(cmd->value_strings, cmd_switch, &config->age, 0); - } break; - - case LNK_CmdSwitch_Rad_BuildInfo: { - lnk_print_build_info(); - os_abort(0); - } break; - - case LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll); - } break; - - case LNK_CmdSwitch_Rad_Debug: { - lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->rad_debug); - } break; - case LNK_CmdSwitch_Rad_DebugName: { - // :Rad_DebugAltPath - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_name); - } break; - - case LNK_CmdSwitch_Rad_DebugAltPath: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_alt_path); - } break; - - case LNK_CmdSwitch_Rad_DelayBind: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_DelayBind); - } break; - - case LNK_CmdSwitch_Rad_DoMerge: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Merge); - } break; - - case LNK_CmdSwitch_Rad_EnvLib: { - lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_EnvLib); - } break; - - case LNK_CmdSwitch_Rad_Exe: { - lnk_cmd_switch_set_flag_16(cmd->value_strings, cmd_switch, &config->file_characteristics, PE_ImageFileCharacteristic_EXE); - } break; - - case LNK_CmdSwitch_Rad_Guid: { - if (cmd->value_strings.node_count == 1) { - if (str8_match(cmd->value_strings.first->string, str8_lit("imageblake3"), StringMatchFlag_CaseInsensitive)) { - config->guid_type = Lnk_DebugInfoGuid_ImageBlake3; - } else if (str8_match(cmd->value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) { - config->guid = os_make_guid(); - } else { - Guid guid; - if (try_guid_from_string(cmd->value_strings.first->string, &guid)) { - config->guid = guid; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse \"%S\"", cmd->value_strings.first->string); - } - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters, expected GUID formatted as following: \"0000000-0000-0000-0000-000000000000\""); - } - } break; - - case LNK_CmdSwitch_Rad_IdleWorkers: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->idle_worker_count, 0); - } break; - - case LNK_CmdSwitch_Rad_LargePages: { - if (cmd->value_strings.node_count == 0) { - OS_ProcessInfo *process_info = os_get_process_info(); - if (process_info->large_pages_allowed) { - arena_default_flags |= ArenaFlag_LargePages; - } else { - lnk_error_cmd_switch(LNK_Warning_LargePages, cmd_switch, "Large pages aren't enabled on this system."); -#if OS_WINDOWS - lnk_supplement_error("To enable large pages:"); - lnk_supplement_error("\t- Press Win+R and open \"gpedit.msc\""); - lnk_supplement_error("\t- Navigate to Local Computer Policy > Computer Configuration > Windows Settings > Security Settings > Local Policies > User Rights And Assignments"); - lnk_supplement_error("\t- Double-click on \"Lock pages in memory\""); - lnk_supplement_error("\t- Click \"Add User or Group...\""); - lnk_supplement_error("\t- Type in your user name"); - lnk_supplement_error("\t- Click Oks and reboot the machine"); -#endif - } - } else if (cmd->value_strings.node_count == 1) { - if (str8_match(cmd->value_strings.first->string, str8_lit("quiet"), StringMatchFlag_CaseInsensitive)) { - OS_ProcessInfo *process_info = os_get_process_info(); - if (process_info->large_pages_allowed) { - arena_default_flags |= ArenaFlag_LargePages; - } - } else if (str8_match(cmd->value_strings.first->string, str8_lit("no"), StringMatchFlag_CaseInsensitive)) { - arena_default_flags &= ~ArenaFlag_LargePages; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid parameter: \"%S\", expected NO or QUIET", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Rad_LinkVer: { - lnk_cmd_switch_parse_version(cmd->value_strings, cmd_switch, &config->link_ver); - } break; - - case LNK_CmdSwitch_Rad_Log: { - if (cmd->value_strings.node_count == 1) { - if (str8_match(cmd->value_strings.first->string, str8_lit("all"), StringMatchFlag_CaseInsensitive)) { - for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) { - lnk_set_log_status((LNK_LogType)ilog, 1); - } - } else if (str8_match(cmd->value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) { - lnk_set_log_status(LNK_Log_IO_Read, 1); - lnk_set_log_status(LNK_Log_IO_Write, 1); - } else { - LNK_LogType log_type = lnk_log_type_from_string(cmd->value_strings.first->string); - if (log_type == LNK_Log_Null) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter \"%S\"", cmd->value_strings.first->string); - } else { - lnk_set_log_status(log_type, 1); - } - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters, expected 1"); - } - } break; - - case LNK_CmdSwitch_Rad_MtPath: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->mt_path); - } break; - - case LNK_CmdSwitch_Rad_OsVer: { - lnk_cmd_switch_parse_version(cmd->value_strings, cmd_switch, &config->os_ver); - } break; - - case LNK_CmdSwitch_Rad_PageSize: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->page_size, 0); - } break; - - case LNK_CmdSwitch_Rad_PathStyle: { - if (cmd->value_strings.node_count == 1) { - PathStyle path_style = path_style_from_string(str8_list_first(&cmd->value_strings)); - if (path_style != PathStyle_Null) { - config->path_style = path_style; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse parameter \"%S\"", cmd->value_strings.first->string); - } - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid number of parameters"); - } - } break; - - case LNK_CmdSwitch_Rad_PdbHashTypeNames: { - String8 mode_string = str8_list_first(&cmd->value_strings); - - LNK_TypeNameHashMode mode; - if (mode_string.size == 0) { - config->pdb_hash_type_names = LNK_TypeNameHashMode_Lenient; - } else { - mode = lnk_type_name_hash_mode_from_string(mode_string); - if (mode == LNK_TypeNameHashMode_Null) { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter: \"%S\"", mode_string); - } else { - config->pdb_hash_type_names = mode; - } - } - } break; - - case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: { - lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_map); - } break; - - case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_length, 0); - } break; - - case LNK_CmdSwitch_Rad_SectVirtOff: { - U64 sect_virt_off; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, §_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) { - if (sect_virt_off >= 0x1000) { - config->section_virt_off = sect_virt_off; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "section virtual offset must be >= 0x1000"); - } - } - } break; - - case LNK_CmdSwitch_Rad_SuppressError: { - U64List error_code_list = {0}; - if (lnk_cmd_switch_parse_u64_list(scratch.arena, cmd->value_strings, cmd_switch, &error_code_list, 0)) { - for (U64Node *error_code_n = error_code_list.first; error_code_n != 0; error_code_n = error_code_n->next) { - if (error_code_n->data < LNK_Error_Count) { - lnk_suppress_error(error_code_n->data); - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "unknown error code %llu", error_code_n->data); - } - } - } - } break; - - case LNK_CmdSwitch_Rad_SymbolTableCapDefined: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_defined, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapInternal: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_internal, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapWeak: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_weak, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapLib: { - lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->symbol_table_cap_lib, 0); - } break; - - case LNK_CmdSwitch_Rad_TargetOs: { - if (cmd->value_strings.node_count == 1) { - String8 os_string = str8_list_first(&cmd->value_strings); - OperatingSystem target_os = operating_system_from_string(os_string); - if (target_os != OperatingSystem_Null) { - config->target_os = target_os; - } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown operating system type %S", os_string); - } - } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "expected 1 parameter"); - } - } break; - - case LNK_CmdSwitch_Rad_TimeStamp: { - lnk_cmd_switch_parse_u32(cmd->value_strings, cmd_switch, &config->time_stamp, 0); - } break; - - case LNK_CmdSwitch_Rad_Version: { - fprintf(stdout, "%s\n", BUILD_TITLE_STRING_LITERAL); - os_abort(0); - } break; - - case LNK_CmdSwitch_Rad_Workers: { - U64 worker_count; - if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &worker_count, 0)) { - config->worker_count = worker_count; - } - } break; - - case LNK_CmdSwitch_Help: { - lnk_print_help(); - os_abort(0); - } break; - } + lnk_apply_cmd_option_to_config(arena, config, cmd->string, cmd->value_strings, str8_zero(), str8_zero()); } // apply idle workers switch @@ -1733,7 +1758,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) U64 final_worker_count = config->worker_count - config->idle_worker_count; config->worker_count = final_worker_count; } else { - lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count); + lnk_error_cmd_switch(LNK_Warning_Cmdl, str8_zero(), str8_zero(), LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count); } } @@ -1748,7 +1773,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) } } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); + lnk_error_cmd_switch(LNK_Error_Cmdl, str8_zero(), str8_zero(), LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED"); } } diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 01518cbe..54783f7b 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -40,6 +40,7 @@ typedef enum LNK_CmdSwitch_ManifestFile, LNK_CmdSwitch_ManifestInput, LNK_CmdSwitch_ManifestUac, + LNK_CmdSwitch_Merge, LNK_CmdSwitch_Natvis, LNK_CmdSwitch_NoDefaultLib, LNK_CmdSwitch_NoExp, @@ -73,18 +74,23 @@ typedef enum LNK_CmdSwitch_DependentLoadFlag, LNK_CmdSwitch_Driver, LNK_CmdSwitch_DisallowLib, + LNK_CmdSwitch_EditAndContinue, LNK_CmdSwitch_EmitVolatileMetadata, LNK_CmdSwitch_ErrorReport, LNK_CmdSwitch_Export, LNK_CmdSwitch_ExportAdmin, LNK_CmdSwitch_FastGenProfile, + LNK_CmdSwitch_FailIfMismatch, LNK_CmdSwitch_Force, LNK_CmdSwitch_Guard, + LNK_CmdSwitch_GuardSym, LNK_CmdSwitch_GenProfile, LNK_CmdSwitch_IdlOut, LNK_CmdSwitch_IgnoreIdl, LNK_CmdSwitch_Ilk, LNK_CmdSwitch_IntegrityCheck, + LNK_CmdSwitch_InferAsanLibs, + LNK_CmdSwitch_InferAsanLibsNo, LNK_CmdSwitch_Kernel, LNK_CmdSwitch_KeyContainer, LNK_CmdSwitch_KeyFile, @@ -94,7 +100,6 @@ typedef enum LNK_CmdSwitch_LtcgOut, LNK_CmdSwitch_Map, LNK_CmdSwitch_MapInfo, - LNK_CmdSwitch_Merge, LNK_CmdSwitch_Midl, LNK_CmdSwitch_NoAssembly, LNK_CmdSwitch_NoEntry, @@ -108,6 +113,7 @@ typedef enum LNK_CmdSwitch_Stub, LNK_CmdSwitch_SwapRun, LNK_CmdSwitch_TlbId, + LNK_CmdSwitch_ThrowingNew, LNK_CmdSwitch_UserProfile, LNK_CmdSwitch_Verbose, LNK_CmdSwitch_Version, @@ -281,7 +287,6 @@ typedef struct LNK_Config Version subsystem_ver; PE_ImageFileCharacteristics file_characteristics; PE_DllCharacteristics dll_characteristics; - String8 user_entry_point_name; String8 entry_point_name; String8List lib_dir_list; PathStyle path_style; @@ -471,9 +476,9 @@ internal B32 lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSw //////////////////////////////// // Errors -internal void lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt, ...); -internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch); -internal void lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, String8 param); +internal void lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...); +internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch); +internal void lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param); //////////////////////////////// // Getters @@ -488,24 +493,26 @@ internal B32 lnk_do_debug_info(LNK_Config *config); //////////////////////////////// // Specialized Parsers -internal B32 lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_switch, Version *ver_out); -internal B32 lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_switch, Rng1U64 *tuple_out); -internal B32 lnk_cmd_switch_parse_u64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *value_out, LNK_ParseU64Flags flags); -internal B32 lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *value_out, LNK_ParseU64Flags flags); -internal B32 lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switch, LNK_SwitchState *value_out); -internal void lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits); -internal void lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits); -internal void lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits); -internal void lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *flags, U32 bits); -internal void lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits); -internal B32 lnk_cmd_switch_parse_string(String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out); -internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out); +internal B32 lnk_cmd_switch_parse_version(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out); +internal B32 lnk_cmd_switch_parse_tuple(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out); +internal B32 lnk_cmd_switch_parse_u64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags); +internal B32 lnk_cmd_switch_parse_u32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags); +internal B32 lnk_cmd_switch_parse_flag(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out); +internal void lnk_cmd_switch_set_flag_inv_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); +internal void lnk_cmd_switch_set_flag_inv_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); +internal void lnk_cmd_switch_set_flag_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits); +internal void lnk_cmd_switch_set_flag_32(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits); +internal void lnk_cmd_switch_set_flag_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits); +internal B32 lnk_cmd_switch_parse_string(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); +internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out); internal B32 lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out); internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out); //////////////////////////////// +internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, String8 obj_path, String8 lib_path); + internal LNK_Config * lnk_config_from_raw_cmd_line(Arena *arena, String8List raw_cmd_line); internal LNK_Config * lnk_build_config(Arena *arena, int argc, char **argv); diff --git a/src/linker/lnk_directive.c b/src/linker/lnk_directive.c index c0d7e408..c3107942 100644 --- a/src/linker/lnk_directive.c +++ b/src/linker/lnk_directive.c @@ -23,69 +23,76 @@ lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_Me //////////////////////////////// +internal B32 +lnk_is_directive_legal(LNK_CmdSwitchType type) +{ + static B32 init_table = 1; + static B8 is_legal[LNK_CmdSwitch_Count]; + if (init_table) { + init_table = 0; + is_legal[LNK_CmdSwitch_AlternateName] = 1; + is_legal[LNK_CmdSwitch_DefaultLib] = 1; + is_legal[LNK_CmdSwitch_DisallowLib] = 1; + is_legal[LNK_CmdSwitch_EditAndContinue] = 1; + is_legal[LNK_CmdSwitch_Entry] = 1; + is_legal[LNK_CmdSwitch_Export] = 1; + is_legal[LNK_CmdSwitch_FailIfMismatch] = 1; + is_legal[LNK_CmdSwitch_GuardSym] = 1; + is_legal[LNK_CmdSwitch_Include] = 1; + is_legal[LNK_CmdSwitch_InferAsanLibs] = 1; + is_legal[LNK_CmdSwitch_InferAsanLibsNo] = 1; + is_legal[LNK_CmdSwitch_ManifestDependency] = 1; + is_legal[LNK_CmdSwitch_Merge] = 1; + is_legal[LNK_CmdSwitch_NoDefaultLib] = 1; + is_legal[LNK_CmdSwitch_Release] = 1; + is_legal[LNK_CmdSwitch_Section] = 1; + is_legal[LNK_CmdSwitch_Stack] = 1; + is_legal[LNK_CmdSwitch_SubSystem] = 1; + is_legal[LNK_CmdSwitch_ThrowingNew] = 1; + } + return is_legal[type]; +} + internal void lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 buffer, String8 obj_path) { Temp scratch = scratch_begin(&arena, 1); - String8 unparsed_directives = buffer; + String8 to_parse; { - static const U8 BOM_SIG[] = { 0xEF, 0xBB, 0xBF }; - B32 is_bom = MemoryMatch(buffer.str, &BOM_SIG[0], sizeof(BOM_SIG)); - if (is_bom) { - unparsed_directives = str8_zero(); + local_persist const U8 bom_sig[] = { 0xEF, 0xBB, 0xBF }; + local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 }; + if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) { + to_parse = str8_zero(); lnk_not_implemented("TODO: support for BOM encoding"); - } - static const U8 ASCII_SIG[] = { 0x20, 0x20, 0x20 }; - B32 is_ascii = MemoryMatch(buffer.str, &ASCII_SIG[0], sizeof(ASCII_SIG)); - if (is_ascii) { - unparsed_directives = str8_skip(buffer, sizeof(ASCII_SIG)); + } else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) { + to_parse = str8_skip(buffer, sizeof(ascii_sig)); + } else { + to_parse = buffer; } } - String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, unparsed_directives); + String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, to_parse); LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, arg_list); for (LNK_CmdOption *opt = cmd_line.first_option; opt != 0; opt = opt->next) { - static struct { - LNK_DirectiveKind kind; - String8 name; - } directive_table[LNK_Directive_Count] = { - { LNK_Directive_Null, str8_lit_comp("") }, - { LNK_Directive_DefaultLib, str8_lit_comp("defaultlib") }, - { LNK_Directive_Export, str8_lit_comp("export" ) }, - { LNK_Directive_Include, str8_lit_comp("include") }, - { LNK_Directive_ManifestDependency, str8_lit_comp("manifestdependency") }, - { LNK_Directive_Merge, str8_lit_comp("merge") }, - { LNK_Directive_Section, str8_lit_comp("section") }, - { LNK_Directive_AlternateName, str8_lit_comp("alternatename") }, - { LNK_Directive_GuardSym, str8_lit_comp("guardsym") }, - { LNK_Directive_DisallowLib, str8_lit_comp("disallowlib") }, - { LNK_Directive_FailIfMismatch, str8_lit_comp("failifmismatch") }, - { LNK_Directive_EditAndContinue, str8_lit_comp("editandcontinue") }, - { LNK_Directive_ThrowingNew, str8_lit_comp("throwingnew") }, - }; + LNK_CmdSwitchType type = lnk_cmd_switch_type_from_string(opt->string); - LNK_DirectiveKind kind = LNK_Directive_Null; - for (U64 i = 0; i < ArrayCount(directive_table); ++i) { - if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) { - kind = directive_table[i].kind; - if (kind == LNK_Directive_Merge) { - String8 v = str8_list_join(scratch.arena, &opt->value_strings, &(StringJoin){ .sep = str8_lit_comp(" ")}); - } - break; - } - } - if (kind == LNK_Directive_Null) { + if (type == LNK_CmdSwitch_Null) { lnk_error(LNK_Warning_UnknownDirective, "%S: unknown directive \"%S\"", obj_path, opt->string); + continue; } - + if (!lnk_is_directive_legal(type)) { + lnk_error(LNK_Warning_IllegalDirective, "%S: illegal directive \"%S\"", obj_path, opt->string); + continue; + } + LNK_Directive *directive = push_array_no_zero(arena, LNK_Directive, 1); directive->next = 0; directive->id = push_str8_copy(arena, opt->string); directive->value_list = str8_list_copy(arena, &opt->value_strings); - - LNK_DirectiveList *directive_list = &directive_info->v[kind]; + + LNK_DirectiveList *directive_list = &directive_info->v[type]; SLLQueuePush(directive_list->first, directive_list->last, directive); ++directive_list->count; } @@ -110,7 +117,6 @@ lnk_parse_default_lib_directive(Arena *arena, LNK_DirectiveList *dir_list) } else { lib_path = push_str8_copy(arena, lib_path); } - str8_list_push(arena, &default_libs, lib_path); } diff --git a/src/linker/lnk_directive.h b/src/linker/lnk_directive.h index c6228738..64f9e0d2 100644 --- a/src/linker/lnk_directive.h +++ b/src/linker/lnk_directive.h @@ -51,27 +51,9 @@ typedef struct LNK_MergeDirectiveList LNK_MergeDirectiveNode *last; } LNK_MergeDirectiveList; -typedef enum -{ - LNK_Directive_Null, - LNK_Directive_DefaultLib, - LNK_Directive_Export, - LNK_Directive_Include, - LNK_Directive_ManifestDependency, - LNK_Directive_Merge, - LNK_Directive_Section, - LNK_Directive_AlternateName, - LNK_Directive_GuardSym, - LNK_Directive_DisallowLib, - LNK_Directive_FailIfMismatch, - LNK_Directive_EditAndContinue, - LNK_Directive_ThrowingNew, - LNK_Directive_Count -} LNK_DirectiveKind; - typedef struct LNK_DirectiveInfo { - LNK_DirectiveList v[LNK_Directive_Count]; + LNK_DirectiveList v[LNK_CmdSwitch_Count]; } LNK_DirectiveInfo; //////////////////////////////// diff --git a/src/linker/lnk_error.c b/src/linker/lnk_error.c index 1aeb04f0..b907de88 100644 --- a/src/linker/lnk_error.c +++ b/src/linker/lnk_error.c @@ -67,6 +67,31 @@ lnk_error(LNK_ErrorCode code, char *fmt, ...) va_end(args); } +internal void +lnk_error_with_loc_fv(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, va_list args) +{ + Temp scratch = scratch_begin(0, 0); + String8 text = push_str8fv(scratch.arena, fmt, args); + if (obj_path.size) { + if (lib_path.size) { + lnk_error(code, "%S(%S): %S", lib_path, obj_path, text); + } else { + lnk_error(code, "%S: %S", obj_path, text); + } + } else { + lnk_error(code, "%S", text); + } + scratch_end(scratch); +} + +internal void +lnk_error_with_loc(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, ...) +{ + va_list args; va_start(args, fmt); + lnk_error_with_loc_fv(code, obj_path, lib_path, fmt, args); + va_end(args); +} + internal void lnk_supplement_error(char *fmt, ...) { diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 555a23ce..65cdf96b 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -74,6 +74,7 @@ typedef enum LNK_Warning_SectionFlagsConflict, LNK_Warning_Subsystem, LNK_Warning_UnknownDirective, + LNK_Warning_IllegalDirective, LNK_Warning_UnresolvedComdat, LNK_Warning_UnusedDelayLoadDll, LNK_Warning_LongSectionName, @@ -110,6 +111,7 @@ typedef enum internal void lnk_init_error_handler(void); internal void lnk_errorfv(LNK_ErrorCode code, char *fmt, va_list args); internal void lnk_error(LNK_ErrorCode code, char *fmt, ...); +internal void lnk_error_with_loc(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, ...); internal void lnk_supplement_error(char *fmt, ...); internal void lnk_supplement_error_list(String8List list); internal void lnk_suppress_error(LNK_ErrorCode code); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index b6c9c487..2fb22216 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -6,19 +6,9 @@ internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...) { - Temp scratch = scratch_begin(0, 0); - va_list args; - va_start(args, fmt); - String8 text = push_str8fv(scratch.arena, fmt, args); - - if (obj->lib_path.size) { - lnk_error(code, "%S(%S): %S", obj->lib_path, obj->path, text); - } else { - lnk_error(code, "%S: %S", obj->path, text); - } - + va_list args; va_start(args, fmt); + lnk_error_with_loc_fv(code, obj->path, obj->lib_path, fmt, args); va_end(args); - scratch_end(scratch); } //////////////////////////////// @@ -230,7 +220,7 @@ THREAD_POOL_TASK_FUNC(lnk_default_lib_collector) String8List *result = &task->out_arr[task_id]; for (U64 obj_idx = range.min; obj_idx < range.max; obj_idx += 1) { LNK_Obj *obj = &task->in_arr.v[obj_idx].data; - String8List list = lnk_parse_default_lib_directive(arena, &obj->directive_info.v[LNK_Directive_DefaultLib]); + String8List list = lnk_parse_default_lib_directive(arena, &obj->directive_info.v[LNK_CmdSwitch_DefaultLib]); str8_list_concat_in_place(result, &list); } } @@ -264,7 +254,7 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector) for (; obj_ptr < obj_opl; obj_ptr += 1) { LNK_Obj *obj = &obj_ptr->data; - LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency]; + LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_CmdSwitch_ManifestDependency]; for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) { String8List dep = str8_list_copy(arena, &dir->value_list); str8_list_concat_in_place(list, &dep); @@ -450,7 +440,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // parse exports LNK_ExportParseList export_parse = {0}; - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Export].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) { lnk_parse_export_direcive(arena, &obj->export_parse, dir->value_list, obj); } @@ -461,12 +451,12 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // push /include symbols - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Include].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Include].first; dir != 0; dir = dir->next) { str8_list_concat_in_place(&obj->include_symbol_list, &dir->value_list); } // parse /alternatename - for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_AlternateName].first; dir != 0; dir = dir->next) { + for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) { String8 *invalid_string = lnk_parse_alt_name_directive_list(arena, dir->value_list, &obj->alt_name_list); if (invalid_string != 0) { lnk_error_obj(LNK_Error_Cmdl, obj, "invalid syntax \"%S\", expected format \"FROM=TO\"", *invalid_string);