on read memory map files

This commit is contained in:
Nikita Smith
2025-06-19 15:12:18 -07:00
committed by Ryan Fleury
parent 16e72fd573
commit 46663688e2
8 changed files with 405 additions and 377 deletions
+9 -7
View File
@@ -203,6 +203,7 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv)
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%%");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MemoryMapFiles, "");
#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");
@@ -435,6 +436,7 @@ lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest
internal String8
lnk_manifest_from_inputs(Arena *arena,
LNK_IO_Flags io_flags,
String8 mt_path,
String8 manifest_name,
B32 manifest_uac,
@@ -468,7 +470,7 @@ lnk_manifest_from_inputs(Arena *arena,
lnk_merge_manifest_files(mt_path, merged_manifest_path, unique_input_manifest_paths);
// read mt.exe output from disk
manifest_data = lnk_read_data_from_file_path(arena, merged_manifest_path);
manifest_data = lnk_read_data_from_file_path(arena, io_flags, merged_manifest_path);
if (manifest_data.size == 0) {
lnk_error(LNK_Error_Mt, "unable to find mt.exe output manifest on disk, expected path \"%S\"", merged_manifest_path);
}
@@ -1455,7 +1457,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
U64 thin_inputs_count = 0;
LNK_InputObj **thin_inputs = lnk_thin_array_from_input_obj_list(scratch.arena, unique_obj_input_list, &thin_inputs_count);
String8Array thin_input_paths = lnk_path_array_from_input_obj_array(scratch.arena, thin_inputs, thin_inputs_count);
String8Array thin_input_datas = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], thin_input_paths);
String8Array thin_input_datas = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], config->io_flags, thin_input_paths);
for (U64 thin_input_idx = 0; thin_input_idx < thin_inputs_count; thin_input_idx += 1) {
thin_inputs[thin_input_idx]->has_disk_read_failed = thin_input_datas.v[thin_input_idx].size == 0;
thin_inputs[thin_input_idx]->data = thin_input_datas.v[thin_input_idx];
@@ -1696,7 +1698,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
ProfBegin("Disk Read Libs");
String8Array paths = str8_array_from_list(temp.arena, &unique_input_lib_list);
String8Array datas = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], paths);
String8Array datas = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], config->io_flags, paths);
ProfEnd();
ProfBegin("Lib Init");
@@ -2047,7 +2049,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
ProfBegin("Embed Manifest");
// TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest
// resource to the tree directly
String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list);
String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->io_flags, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list);
String8 manifest_res = pe_make_manifest_resource(scratch.arena, *config->manifest_resource_id, manifest_data);
str8_list_push(scratch.arena, &res_data_list, manifest_res);
str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *"));
@@ -2056,7 +2058,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
case LNK_ManifestOpt_WriteToFile: {
ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name));
Temp temp = temp_begin(scratch.arena);
String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list);
String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->io_flags, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list);
lnk_write_data_to_file_path(config->manifest_name, str8_zero(), manifest_data);
temp_end(temp);
ProfEnd();
@@ -2072,7 +2074,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
ProfBegin("Load .res files from disk");
for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) {
String8 res_data = lnk_read_data_from_file_path(scratch.arena, node->string);
String8 res_data = lnk_read_data_from_file_path(scratch.arena, config->io_flags, node->string);
if (res_data.size > 0) {
if (pe_is_res(res_data)) {
str8_list_push(scratch.arena, &res_data_list, res_data);
@@ -5066,7 +5068,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
//
// CodeView
//
LNK_CodeViewInput input = lnk_make_code_view_input(tp, tp_arena, config->lib_dir_list, link_ctx.objs_count, link_ctx.objs);
LNK_CodeViewInput input = lnk_make_code_view_input(tp, tp_arena, config->io_flags, config->lib_dir_list, link_ctx.objs_count, link_ctx.objs);
CV_DebugT *types = lnk_import_types(tp, tp_arena, &input);
//
+1 -1
View File
@@ -188,7 +188,7 @@ internal U128 lnk_blake3_hash_parallel(TP_Context *tp, U64 chunk_count, String8
internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list);
internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list);
internal String8 lnk_manifest_from_inputs(Arena *arena, String8 mt_path, String8 manifest_name, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List input_manifest_path_list, String8List deps_list);
internal String8 lnk_manifest_from_inputs(Arena *arena, LNK_IO_Flags io_flags, String8 mt_path, String8 manifest_name, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List input_manifest_path_list, String8List deps_list);
// --- Internal Objs -----------------------------------------------------------
+267 -265
View File
@@ -1,10 +1,8 @@
// Copyright (c) 2025 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// Enum <-> String
global read_only LNK_CmdSwitch g_cmd_switch_map[] = {
global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{
{ LNK_CmdSwitch_Null, 0, "", "", "" },
{ LNK_CmdSwitch_NotImplemented, 0, "NOT_IMPLEMENTED", "", "" },
{ LNK_CmdSwitch_Align, 0, "ALIGN", ":#", "" },
@@ -123,40 +121,42 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = {
{ LNK_CmdSwitch_NotImplemented, 0, "WX", "", "" },
//- internal switches
{ LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
{ LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." },
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." },
{ LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
{ LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", "", "" },
{ LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
{ LNK_CmdSwitch_Rad_DelayBind, 0, "RAD_DELAY_BIND", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_DoMerge, 0, "RAD_DO_MERGE", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_EnvLib, 0, "RAD_ENV_LIB", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Exe, 0, "RAD_EXE", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Guid, 0, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
{ LNK_CmdSwitch_Rad_LargePages, 0, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
{ LNK_CmdSwitch_Rad_LinkVer, 0, "RAD_LINK_VER", ":##,##", "" },
{ LNK_CmdSwitch_Rad_Log, 0, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
{ LNK_CmdSwitch_Rad_MtPath, 0, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME },
{ LNK_CmdSwitch_Rad_OsVer, 0, "RAD_OS_VER", ":##,##", "" },
{ LNK_CmdSwitch_Rad_PageSize, 0, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
{ LNK_CmdSwitch_Rad_PathStyle, 0, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
{ LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
{ LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." },
{ LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" },
{ LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." },
{ LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" },
{ LNK_CmdSwitch_Rad_SymbolTableCapDefined, 0, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapInternal, 0, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapLib, 0, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapWeak, 0, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." },
{ LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
{ LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
{ LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." },
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." },
{ LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:NO]", "When enabled, files are memory-mapped instead of being read entirely on request." },
{ LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
{ LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", "", "" },
{ LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
{ LNK_CmdSwitch_Rad_DelayBind, 0, "RAD_DELAY_BIND", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_DoMerge, 0, "RAD_DO_MERGE", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_EnvLib, 0, "RAD_ENV_LIB", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Exe, 0, "RAD_EXE", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_Guid, 0, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
{ LNK_CmdSwitch_Rad_LargePages, 0, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
{ LNK_CmdSwitch_Rad_LinkVer, 0, "RAD_LINK_VER", ":##,##", "" },
{ LNK_CmdSwitch_Rad_Log, 0, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
{ LNK_CmdSwitch_Rad_MtPath, 0, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME },
{ LNK_CmdSwitch_Rad_OsVer, 0, "RAD_OS_VER", ":##,##", "" },
{ LNK_CmdSwitch_Rad_PageSize, 0, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
{ LNK_CmdSwitch_Rad_PathStyle, 0, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
{ LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
{ LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." },
{ LNK_CmdSwitch_Rad_SectVirtOff, 0, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." },
{ LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" },
{ LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." },
{ LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" },
{ LNK_CmdSwitch_Rad_SymbolTableCapDefined, 0, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapInternal, 0, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapLib, 0, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapWeak, 0, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." },
{ LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
{ LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." },
{ LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
{ LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." },
{ LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
{ LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." },
{ LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." },
{ LNK_CmdSwitch_Help, 0, "HELP", "", "" },
@@ -270,8 +270,6 @@ lnk_type_name_hash_mode_from_string(String8 name)
return LNK_TypeNameHashMode_Null;
}
////////////////////////////////
internal LNK_CmdOption *
lnk_cmd_line_push_option_if_not_presentf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...)
{
@@ -307,8 +305,6 @@ lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch)
return lnk_cmd_line_has_option_string(cmd_line, cmd_switch_name);
}
////////////////////////////////
internal void
lnk_error_cmd_switch(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...)
{
@@ -362,185 +358,6 @@ lnk_error_invalid_uac_ui_access_param(LNK_ErrorCode error_code, String8 obj_path
lnk_error_cmd_switch(error_code, obj_path, lib_path, cmd_switch, "invalid param format, expected \"uiAccess={'true'|'false'}\" but got \"%S\"", input);
}
////////////////////////////////
internal String8
lnk_get_image_name(LNK_Config *config)
{
String8 image_name = config->image_name;
image_name = str8_skip_last_slash(image_name);
image_name = str8_chop_last_dot(image_name);
return image_name;
}
internal U64
lnk_get_default_function_pad_min(COFF_MachineType machine)
{
U64 function_pad_min = 0;
switch (machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X86: {
function_pad_min = 5;
} break;
case COFF_MachineType_X64: {
function_pad_min = 6;
} 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));
} break;
}
return function_pad_min;
}
internal U64
lnk_get_base_addr(LNK_Config *config)
{
U64 base_addr = config->user_base_addr;
if (base_addr == 0) {
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
base_addr = coff_default_dll_base_from_machine(config->machine);
} else if (config->file_characteristics & PE_ImageFileCharacteristic_EXE) {
if ((~config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE) && config->machine == COFF_MachineType_X64) {
base_addr = coff_default_exe_base_from_machine(COFF_MachineType_X86);
} else {
base_addr = coff_default_exe_base_from_machine(config->machine);
}
} else {
lnk_error(LNK_Error_Cmdl, "image type is not specified.");
}
}
return base_addr;
}
internal Version
lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine)
{
Version ver = make_version(0,0);
switch (subsystem) {
case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: ver = make_version(1,0); break;
case PE_WindowsSubsystem_WINDOWS_CUI: {
switch (machine) {
case COFF_MachineType_X64:
case COFF_MachineType_X86: ver = make_version(6,0); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_WINDOWS_GUI: {
switch (machine) {
case COFF_MachineType_X64:
case COFF_MachineType_X86: ver = make_version(6,0); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_POSIX_CUI: ver = make_version(19,90); break;
case PE_WindowsSubsystem_EFI_APPLICATION:
case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER:
case PE_WindowsSubsystem_EFI_ROM:
case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: ver = make_version(1,0); break;
case PE_WindowsSubsystem_NATIVE_WINDOWS:
case PE_WindowsSubsystem_NATIVE: lnk_not_implemented("detect -drive=WDM switch"); break;
default: lnk_not_implemented("unknown subsystem kind %u", subsystem); break;
}
return ver;
}
internal Version
lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine)
{
Version ver = make_version(0,0);
switch (subsystem) {
case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: ver = make_version(1,0); break;
case PE_WindowsSubsystem_WINDOWS_CUI: {
switch (machine) {
case COFF_MachineType_X86: ver = make_version(5,1); break;
case COFF_MachineType_X64: ver = make_version(5,2); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_WINDOWS_GUI: {
switch (machine) {
case COFF_MachineType_X86: ver = make_version(5,1); break;
case COFF_MachineType_X64: ver = make_version(5,2); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_POSIX_CUI: ver = make_version(1,0); break;
case PE_WindowsSubsystem_EFI_APPLICATION:
case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER:
case PE_WindowsSubsystem_EFI_ROM:
case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: ver = make_version(1,0); break;
case PE_WindowsSubsystem_NATIVE_WINDOWS:
case PE_WindowsSubsystem_NATIVE: lnk_not_implemented("detect -drive=WDM switch"); break;
default: lnk_not_implemented("unknown subsystem kind %u", subsystem);
}
return ver;
}
internal B32
lnk_do_debug_info(LNK_Config *config)
{
B32 do_debug_info = config->rad_debug == LNK_SwitchState_Yes ||
(config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null);
return do_debug_info;
}
internal B32
lnk_is_thread_pool_shared(LNK_Config *config)
{
return config->shared_thread_pool_name.size > 0;
}
internal B32
lnk_is_section_removed(LNK_Config *config, String8 section_name)
{
B32 is_removed = 0;
for (String8Node *name_n = config->remove_sections.first; name_n != 0 && !is_removed; name_n = name_n->next) {
is_removed = str8_match(section_name, name_n->string, 0);
}
return is_removed;
}
////////////////////////////////
internal B32
lnk_cmd_switch_parse_version(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out)
{
@@ -784,8 +601,6 @@ lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_pat
}
}
////////////////////////////////
internal B32
lnk_parse_alt_name_directive(String8 input, LNK_AltName *alt_out)
{
@@ -947,7 +762,180 @@ lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out)
return is_parse_ok;
}
////////////////////////////////
internal String8
lnk_get_image_name(LNK_Config *config)
{
String8 image_name = config->image_name;
image_name = str8_skip_last_slash(image_name);
image_name = str8_chop_last_dot(image_name);
return image_name;
}
internal U64
lnk_get_default_function_pad_min(COFF_MachineType machine)
{
U64 function_pad_min = 0;
switch (machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X86: {
function_pad_min = 5;
} break;
case COFF_MachineType_X64: {
function_pad_min = 6;
} 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));
} break;
}
return function_pad_min;
}
internal U64
lnk_get_base_addr(LNK_Config *config)
{
U64 base_addr = config->user_base_addr;
if (base_addr == 0) {
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
base_addr = coff_default_dll_base_from_machine(config->machine);
} else if (config->file_characteristics & PE_ImageFileCharacteristic_EXE) {
if ((~config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE) && config->machine == COFF_MachineType_X64) {
base_addr = coff_default_exe_base_from_machine(COFF_MachineType_X86);
} else {
base_addr = coff_default_exe_base_from_machine(config->machine);
}
} else {
lnk_error(LNK_Error_Cmdl, "image type is not specified.");
}
}
return base_addr;
}
internal Version
lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine)
{
Version ver = make_version(0,0);
switch (subsystem) {
case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: ver = make_version(1,0); break;
case PE_WindowsSubsystem_WINDOWS_CUI: {
switch (machine) {
case COFF_MachineType_X64:
case COFF_MachineType_X86: ver = make_version(6,0); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_WINDOWS_GUI: {
switch (machine) {
case COFF_MachineType_X64:
case COFF_MachineType_X86: ver = make_version(6,0); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_POSIX_CUI: ver = make_version(19,90); break;
case PE_WindowsSubsystem_EFI_APPLICATION:
case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER:
case PE_WindowsSubsystem_EFI_ROM:
case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: ver = make_version(1,0); break;
case PE_WindowsSubsystem_NATIVE_WINDOWS:
case PE_WindowsSubsystem_NATIVE: lnk_not_implemented("detect -drive=WDM switch"); break;
default: lnk_not_implemented("unknown subsystem kind %u", subsystem); break;
}
return ver;
}
internal Version
lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine)
{
Version ver = make_version(0,0);
switch (subsystem) {
case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: ver = make_version(1,0); break;
case PE_WindowsSubsystem_WINDOWS_CUI: {
switch (machine) {
case COFF_MachineType_X86: ver = make_version(5,1); break;
case COFF_MachineType_X64: ver = make_version(5,2); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_WINDOWS_GUI: {
switch (machine) {
case COFF_MachineType_X86: ver = make_version(5,1); break;
case COFF_MachineType_X64: ver = make_version(5,2); break;
case COFF_MachineType_ArmNt:
case COFF_MachineType_Arm64:
case COFF_MachineType_Arm: ver = make_version(6,2); break;
default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break;
}
} break;
case PE_WindowsSubsystem_POSIX_CUI: ver = make_version(1,0); break;
case PE_WindowsSubsystem_EFI_APPLICATION:
case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER:
case PE_WindowsSubsystem_EFI_ROM:
case PE_WindowsSubsystem_EFI_RUNTIME_DRIVER: ver = make_version(1,0); break;
case PE_WindowsSubsystem_NATIVE_WINDOWS:
case PE_WindowsSubsystem_NATIVE: lnk_not_implemented("detect -drive=WDM switch"); break;
default: lnk_not_implemented("unknown subsystem kind %u", subsystem);
}
return ver;
}
internal B32
lnk_do_debug_info(LNK_Config *config)
{
B32 do_debug_info = config->rad_debug == LNK_SwitchState_Yes ||
(config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null);
return do_debug_info;
}
internal B32
lnk_is_thread_pool_shared(LNK_Config *config)
{
return config->shared_thread_pool_name.size > 0;
}
internal B32
lnk_is_section_removed(LNK_Config *config, String8 section_name)
{
B32 is_removed = 0;
for (String8Node *name_n = config->remove_sections.first; name_n != 0 && !is_removed; name_n = name_n->next) {
is_removed = str8_match(section_name, name_n->string, 0);
}
return is_removed;
}
internal void
lnk_print_build_info()
@@ -999,8 +987,6 @@ lnk_print_help(void)
scratch_end(scratch);
}
////////////////////////////////
internal String8
lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
{
@@ -1034,6 +1020,46 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
return result;
}
internal String8List
lnk_unwrap_rsp(Arena *arena, String8List arg_list)
{
Temp scratch = scratch_begin(&arena, 1);
String8List result = {0};
for (String8Node *curr = arg_list.first; curr != 0; curr = curr->next) {
B32 is_rsp = str8_match_lit("@", curr->string, StringMatchFlag_RightSideSloppy);
if (is_rsp) {
// remove "@"
String8 name = str8_skip(curr->string, 1);
if (os_file_path_exists(name)) {
// read rsp from disk
String8 file = lnk_read_data_from_file_path(scratch.arena, 0, name);
// parse rsp
String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file);
// handle case where rsp references another rsp
String8List list = lnk_unwrap_rsp(arena, rsp_args);
// push arguments from rsp
list = str8_list_copy(arena, &list);
str8_list_concat_in_place(&result, &list);
} else {
lnk_error(LNK_Error_Cmdl, "unable to find rsp: %S", name);
}
} else {
// push regular argument
String8 str = push_str8_copy(arena, curr->string);
str8_list_push(arena, &result, str);
}
}
scratch_end(scratch);
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)
{
@@ -1634,9 +1660,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
config->rad_chunk_map = LNK_SwitchState_Yes;
} break;
case LNK_CmdSwitch_Rad_MemoryMapFiles: {
lnk_cmd_switch_set_flag_32(obj_path, lib_path, cmd_switch, value_strings, &config->io_flags, LNK_IO_Flags_MemoryMapFiles);
} 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);
@@ -1797,6 +1828,17 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
}
} break;
case LNK_CmdSwitch_Rad_SectVirtOff: {
U64 sect_virt_off;
if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &sect_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_SharedThreadPool: {
if (value_strings.node_count == 0) {
config->shared_thread_pool_name = str8_lit(LNK_DEFAULT_THREAD_POOL_NAME);
@@ -1892,46 +1934,6 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
scratch_end(scratch);
}
internal String8List
lnk_unwrap_rsp(Arena *arena, String8List arg_list)
{
Temp scratch = scratch_begin(&arena, 1);
String8List result = {0};
for (String8Node *curr = arg_list.first; curr != 0; curr = curr->next) {
B32 is_rsp = str8_match_lit("@", curr->string, StringMatchFlag_RightSideSloppy);
if (is_rsp) {
// remove "@"
String8 name = str8_skip(curr->string, 1);
if (os_file_path_exists(name)) {
// read rsp from disk
String8 file = lnk_read_data_from_file_path(scratch.arena, name);
// parse rsp
String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file);
// handle case where rsp references another rsp
String8List list = lnk_unwrap_rsp(arena, rsp_args);
// push arguments from rsp
list = str8_list_copy(arena, &list);
str8_list_concat_in_place(&result, &list);
} else {
lnk_error(LNK_Error_Cmdl, "unable to find rsp: %S", name);
}
} else {
// push regular argument
String8 str = push_str8_copy(arena, curr->string);
str8_list_push(arena, &result, str);
}
}
scratch_end(scratch);
return result;
}
internal LNK_Config *
lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd_line)
{
+49 -53
View File
@@ -3,6 +3,29 @@
#pragma once
#if OS_WINDOWS
# define LNK_MANIFEST_MERGE_TOOL_NAME "mt.exe"
#elif OS_LINUX || OS_MAC
# define LNK_MANIFEST_MERGE_TOOL_NAME "llvm-mt"
#else
# error
#endif
#define LNK_DEFAULT_THREAD_POOL_NAME "RADLINK_THREAD_POOL"
typedef enum
{
LNK_ParseU64Flag_CheckUnder32bit = (1 << 0),
LNK_ParseU64Flag_CheckPow2 = (1 << 1),
} LNK_ParseU64Flags;
typedef enum
{
LNK_SwitchState_Null,
LNK_SwitchState_No,
LNK_SwitchState_Yes
} LNK_SwitchState;
typedef enum
{
LNK_CmdSwitch_Null,
@@ -128,7 +151,6 @@ typedef enum
LNK_CmdSwitch_Rad_Age,
LNK_CmdSwitch_Rad_BuildInfo,
LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll,
LNK_CmdSwitch_Rad_Map,
LNK_CmdSwitch_Rad_Debug,
LNK_CmdSwitch_Rad_DebugAltPath,
LNK_CmdSwitch_Rad_DebugName,
@@ -141,6 +163,8 @@ typedef enum
LNK_CmdSwitch_Rad_LinkVer,
LNK_CmdSwitch_Rad_Log,
LNK_CmdSwitch_Rad_Logo,
LNK_CmdSwitch_Rad_Map,
LNK_CmdSwitch_Rad_MemoryMapFiles,
LNK_CmdSwitch_Rad_MtPath,
LNK_CmdSwitch_Rad_OsVer,
LNK_CmdSwitch_Rad_PageSize,
@@ -177,13 +201,6 @@ typedef struct LNK_CmdSwitch
char *desc;
} LNK_CmdSwitch;
typedef enum
{
LNK_SwitchState_Null,
LNK_SwitchState_No,
LNK_SwitchState_Yes
} LNK_SwitchState;
typedef enum
{
LNK_Input_Null,
@@ -285,16 +302,6 @@ typedef enum
LNK_TypeNameHashMode_Full,
} LNK_TypeNameHashMode;
#if OS_WINDOWS
# define LNK_MANIFEST_MERGE_TOOL_NAME "mt.exe"
#elif OS_LINUX || OS_MAC
# define LNK_MANIFEST_MERGE_TOOL_NAME "llvm-mt"
#else
# error
#endif
#define LNK_DEFAULT_THREAD_POOL_NAME "RADLINK_THREAD_POOL"
typedef struct LNK_Config
{
LNK_ConfigFlags flags;
@@ -383,15 +390,10 @@ typedef struct LNK_Config
String8 temp_rad_debug_name;
String8 temp_rad_chunk_map_name;
String8List remove_sections;
LNK_IO_Flags io_flags;
} LNK_Config;
typedef enum
{
LNK_ParseU64Flag_CheckUnder32bit = (1 << 0),
LNK_ParseU64Flag_CheckPow2 = (1 << 1),
} LNK_ParseU64Flags;
////////////////////////////////
// --- MSVC Error Codes --------------------------------------------------------
typedef enum
{
@@ -518,8 +520,7 @@ typedef enum
LNK_MsWarningCode_Lnk4286 = 4286,
} LNK_MsErrorCode;
////////////////////////////////
// Enum <-> String
// --- Enum <-> String ---------------------------------------------------------
internal String8 lnk_string_cmd_switch_type(LNK_CmdSwitchType type);
internal LNK_CmdSwitchType lnk_cmd_switch_type_from_string(String8 string);
@@ -528,36 +529,20 @@ internal LNK_InputType lnk_input_type_from_string(String8 string);
internal LNK_DebugMode lnk_debug_mode_from_string(String8 string);
internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string);
////////////////////////////////
// Command Line Helpers
// --- Command Line Helpers ----------------------------------------------------
internal LNK_CmdOption * lnk_cmd_line_push_option_if_not_presentf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal LNK_CmdOption * lnk_cmd_line_push_optionf (Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal B32 lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type);
////////////////////////////////
// Errors
internal B32 lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type);
// --- Errors ------------------------------------------------------------------
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
internal String8 lnk_get_image_name(LNK_Config *config);
internal U64 lnk_get_default_function_pad_min(COFF_MachineType machine);
internal U64 lnk_get_base_addr(LNK_Config *config);
internal Version lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal B32 lnk_do_debug_info (LNK_Config *config);
internal B32 lnk_is_thread_pool_shared(LNK_Config *config);
internal B32 lnk_is_section_removed(LNK_Config *config, String8 section_name);
////////////////////////////////
// Specialized Parsers
// --- Specialized Parsers ------------------------------------------------------
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);
@@ -572,17 +557,28 @@ internal void lnk_cmd_switch_set_flag_64 (String8 obj_path, String8 lib_path,
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(String8 input, LNK_AltName *alt_out);
internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out);
internal B32 lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, PE_ExportParse *export_out);
internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data);
internal B32 lnk_parse_merge_directive(String8 string, LNK_MergeDirective *parse_out);
////////////////////////////////
// --- Getters -----------------------------------------------------------------
internal String8 lnk_get_image_name(LNK_Config *config);
internal U64 lnk_get_default_function_pad_min(COFF_MachineType machine);
internal U64 lnk_get_base_addr(LNK_Config *config);
internal Version lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal B32 lnk_do_debug_info (LNK_Config *config);
internal B32 lnk_is_thread_pool_shared(LNK_Config *config);
internal B32 lnk_is_section_removed(LNK_Config *config, String8 section_name);
// --- Config ------------------------------------------------------------------
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_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd_line);
+3 -3
View File
@@ -360,7 +360,7 @@ lnk_merge_debug_t_and_debug_p(Arena *arena, U64 obj_count, CV_DebugT *debug_t_ar
}
internal LNK_CodeViewInput
lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir_list, U64 obj_count, LNK_Obj **obj_arr)
lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, U64 obj_count, LNK_Obj **obj_arr)
{
ProfBegin("Extract CodeView");
Temp scratch = scratch_begin(0,0);
@@ -675,7 +675,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
// read type servers from disk in parallel
{
ProfBegin("Read External Type Servers");
String8Array msf_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, ts_path_arr);
String8Array msf_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, 0, ts_path_arr);
ProfEnd();
MSF_Parsed **msf_parse_arr = lnk_msf_parsed_from_data_parallel(tp_arena, tp, msf_data_arr);
@@ -3315,7 +3315,7 @@ lnk_build_pdb(TP_Context *tp,
ProfBegin("Build NatVis");
{
String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &config->natvis_list);
String8Array natvis_file_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, natvis_file_path_arr);
String8Array natvis_file_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, config->io_flags, natvis_file_path_arr);
for (U64 i = 0; i < natvis_file_data_arr.count; ++i) {
String8 natvis_file_path = natvis_file_path_arr.v[i];
+1 -1
View File
@@ -500,7 +500,7 @@ internal CV_DebugT * lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *
internal CV_SymbolList * lnk_cv_symbol_list_arr_from_debug_s_arr(TP_Context *tp, TP_Arena *arena, U64 obj_count, CV_DebugS *debug_s_arr);
internal LNK_PchInfo * lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj *obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols);
internal LNK_CodeViewInput lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir_list, U64 objs_count, LNK_Obj **objs);
internal LNK_CodeViewInput lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, U64 objs_count, LNK_Obj **objs);
internal LNK_LeafRef lnk_leaf_ref(U32 idx, U32 leaf_idx);
internal LNK_LeafRef lnk_obj_leaf_ref(U32 obj_idx, U32 leaf_idx);
+64 -44
View File
@@ -172,31 +172,13 @@ lnk_log_read(String8 path, U64 size)
}
internal String8
lnk_read_data_from_file_path(Arena *arena, String8 path)
lnk_read_data_from_file_path(Arena *arena, LNK_IO_Flags io_flags, String8 path)
{
String8 data = str8_zero();
OS_Handle handle = {0};
int is_open = lnk_open_file_read((char*)path.str, path.size, &handle, sizeof(handle));
if (is_open) {
U64 buffer_size = lnk_size_from_file(&handle);
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
U64 read_size = lnk_read_file(&handle, buffer, buffer_size);
data = str8(buffer, read_size);
lnk_close_file(&handle);
if (read_size != buffer_size) {
lnk_error(LNK_Warning_IllData, "incomplete file read occurred, read %u bytes, expected %u bytes, file %S", path);
}
if (lnk_get_log_status(LNK_Log_IO_Read)) {
lnk_log_read(path, data.size);
}
} else {
lnk_error(LNK_Error_FileNotFound, "unable to open file %S", path);
}
return data;
Temp scratch = scratch_begin(&arena, 1);
TP_Context *single_thread_ctx = tp_alloc(scratch.arena, 1, 1, str8_zero());
String8Array data_arr = lnk_read_data_from_file_path_parallel(single_thread_ctx, arena, io_flags, (String8Array){ .count = 1, .v = &path });
scratch_end(scratch);
return data_arr.v[0];
}
internal
@@ -232,33 +214,72 @@ THREAD_POOL_TASK_FUNC(lnk_data_from_file_path_task)
task->data_arr.v[task_id] = str8(buffer, read_size);
}
internal String8Array
lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr)
internal
THREAD_POOL_TASK_FUNC(lnk_memory_map_file_task)
{
Temp scratch = scratch_begin(&arena,1);
LNK_DiskReader *task = raw_task;
#if _WIN32
Temp scratch = scratch_begin(&arena, 1);
String16 path16 = str16_from_8(scratch.arena, task->path_arr.v[task_id]);
HANDLE file_handle = CreateFileW(path16.str, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (file_handle != INVALID_HANDLE_VALUE) {
HANDLE mapping_handle = CreateFileMappingA(file_handle, 0, PAGE_WRITECOPY, 0, 0, 0);
if (mapping_handle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER file_size = {0};
GetFileSizeEx(file_handle, &file_size);
void *file_data = MapViewOfFile(mapping_handle, FILE_MAP_COPY, 0, 0, file_size.QuadPart);
if (file_data) {
task->data_arr.v[task_id] = str8(file_data, file_size.QuadPart);
}
CloseHandle(mapping_handle);
}
CloseHandle(file_handle);
}
scratch_end(scratch);
#else
# error "memory mapping files is not supported on this platform"
#endif
}
internal String8Array
lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, LNK_IO_Flags io_flags, String8Array path_arr)
{
LNK_DiskReader reader = {0};
reader.path_arr = path_arr;
reader.handle_arr = push_array_no_zero(scratch.arena, OS_Handle, path_arr.count);
reader.size_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
// open handles and get sizes
tp_for_parallel(tp, 0, path_arr.count, lnk_data_size_from_file_path_task, &reader);
if (io_flags & LNK_IO_Flags_MemoryMapFiles) {
reader.io_flags = io_flags;
reader.path_arr = path_arr;
reader.data_arr.count = path_arr.count;
reader.data_arr.v = push_array(arena, String8, path_arr.count);
tp_for_parallel(tp, 0, path_arr.count, lnk_memory_map_file_task, &reader);
} else {
Temp scratch = scratch_begin(&arena,1);
// compute file buffer size
U64 total_data_size = sum_array_u64(path_arr.count, reader.size_arr);
reader.path_arr = path_arr;
reader.handle_arr = push_array_no_zero(scratch.arena, OS_Handle, path_arr.count);
reader.size_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
// assign offsets into file buffer
U64 *off_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
MemoryCopyTyped(off_arr, reader.size_arr, path_arr.count);
counts_to_offsets_array_u64(path_arr.count, off_arr);
// open handles and get sizes
tp_for_parallel(tp, 0, path_arr.count, lnk_data_size_from_file_path_task, &reader);
reader.data_arr = str8_array_reserve(arena, path_arr.count);
reader.off_arr = off_arr;
reader.buffer = push_array_no_zero(arena, U8, total_data_size);
// compute file buffer size
U64 total_data_size = sum_array_u64(path_arr.count, reader.size_arr);
// read files and close handles
tp_for_parallel(tp, 0, path_arr.count, lnk_data_from_file_path_task, &reader);
// assign offsets into file buffer
U64 *off_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
MemoryCopyTyped(off_arr, reader.size_arr, path_arr.count);
counts_to_offsets_array_u64(path_arr.count, off_arr);
reader.io_flags = io_flags;
reader.data_arr = str8_array_reserve(arena, path_arr.count);
reader.off_arr = off_arr;
reader.buffer = push_array_no_zero(arena, U8, total_data_size);
// read files and close handles
tp_for_parallel(tp, 0, path_arr.count, lnk_data_from_file_path_task, &reader);
scratch_end(scratch);
}
String8Array result = {0};
result.count = path_arr.count;
@@ -270,7 +291,6 @@ lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array
}
}
scratch_end(scratch);
return result;
}
+11 -3
View File
@@ -2,8 +2,17 @@
////////////////////////////////
typedef U32 LNK_IO_Flags;
enum
{
LNK_IO_Flags_MemoryMapFiles = (1 << 0),
};
////////////////////////////////
typedef struct
{
LNK_IO_Flags io_flags;
String8Array path_arr;
String8Array data_arr;
OS_Handle *handle_arr;
@@ -30,10 +39,9 @@ internal OS_Handle lnk_file_open_with_rename_permissions(String8 path);
internal B32 lnk_file_set_delete_on_close(OS_Handle handle, B32 delete_file);
internal B32 lnk_file_rename(OS_Handle handle, String8 new_name);
internal String8 lnk_read_data_from_file_path(Arena *arena, String8 path);
internal String8Array lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr);
internal String8 lnk_read_data_from_file_path(Arena *arena, LNK_IO_Flags io_flags, String8 path);
internal String8Array lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, LNK_IO_Flags io_flags, String8Array path_arr);
internal void lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List list);
internal void lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data);