move image, import lib, and debug info builders outside of the state machine

This commit is contained in:
Nikita Smith
2025-06-02 00:11:02 -07:00
committed by Ryan Fleury
parent e971db7fdd
commit 1c08db2705
4 changed files with 273 additions and 253 deletions
+249 -243
View File
@@ -2143,18 +2143,19 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config
return result;
}
internal String8
lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs)
internal LNK_ImageContext
lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs)
{
ProfBegin("Image");
lnk_timer_begin(LNK_Timer_Image);
Temp scratch = scratch_begin(arena->v, arena->count);
//
// init section table
//
LNK_SectionTable *sectab = lnk_section_table_alloc();
lnk_section_table_push(sectab, str8_lit(".text"), PE_TEXT_SECTION_FLAGS);
lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS);
lnk_section_table_push(sectab, str8_lit(".rdata"), PE_RDATA_SECTION_FLAGS);
lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS);
{
ProfBegin("Remove Associative Sections");
@@ -3244,8 +3245,14 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
ProfEnd();
}
LNK_ImageContext image_ctx = {0};
image_ctx.image_data = image_data;
image_ctx.sectab = sectab;
lnk_timer_end(LNK_Timer_Image);
ProfEnd(); // :EndImage
scratch_end(scratch);
return image_data;
return image_ctx;
}
////////////////////////////////
@@ -3403,7 +3410,7 @@ lnk_run_symbol_finder(TP_Context *tp,
////////////////////////////////
internal String8List
lnk_build_rad_chunk_map(Arena *arena, String8 image_data, U64 thread_count, LNK_ObjList objs, LNK_LibList lib_index[LNK_InputSource_Count], LNK_SectionTable *sectab)
lnk_build_rad_map(Arena *arena, String8 image_data, U64 thread_count, U64 objs_count, LNK_Obj **objs, LNK_LibList lib_index[LNK_InputSource_Count], LNK_SectionTable *sectab)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
@@ -3486,8 +3493,8 @@ lnk_build_rad_chunk_map(Arena *arena, String8 image_data, U64 thread_count, LNK_
ProfBegin("SYMBOLS");
str8_list_pushf(arena, &map, "# SYMBOLS\n");
str8_list_pushf(arena, &map, "%-8s %s\n", "Sect:Idx", "Symbol");
for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) {
LNK_Obj *obj = &obj_n->data;
for (U64 obj_idx = 0; obj_idx < objs_count; obj_idx += 1) {
LNK_Obj *obj = objs[obj_idx];
COFF_ParsedSymbol symbol;
for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
@@ -3534,50 +3541,8 @@ lnk_build_rad_chunk_map(Arena *arena, String8 image_data, U64 thread_count, LNK_
////////////////////////////////
internal void
lnk_log_timers(void)
{
Temp scratch = scratch_begin(0, 0);
U64 total_build_time_micro = 0;
for (U64 i = 0; i < LNK_Timer_Count; ++i) {
total_build_time_micro += g_timers[i].end - g_timers[i].begin;
}
String8List output_list = {0};
str8_list_pushf(scratch.arena, &output_list, "------ Link Times --------------------------------------------------------------");
for (U64 i = 0; i < LNK_Timer_Count; ++i) {
U64 build_time_micro = g_timers[i].end - g_timers[i].begin;
if (build_time_micro != 0) {
String8 timer_name = lnk_string_from_timer_type(i);
DateTime time = date_time_from_micro_seconds(build_time_micro);
String8 time_str = string_from_elapsed_time(scratch.arena, time);
str8_list_pushf(scratch.arena, &output_list, " %-5S Time: %S", timer_name, time_str);
}
}
DateTime total_time = date_time_from_micro_seconds(total_build_time_micro);
String8 total_time_str = string_from_elapsed_time(scratch.arena, total_time);
str8_list_pushf(scratch.arena, &output_list, " Total Time: %S", total_time_str);
StringJoin new_line_join = { str8_lit_comp(""), str8_lit_comp("\n"), str8_lit_comp("") };
String8 output = str8_list_join(scratch.arena, &output_list, &new_line_join);
lnk_log(LNK_Log_Timers, "%S\n", output);
scratch_end(scratch);
}
internal void
lnk_write_thread(void *raw_ctx)
{
ProfBeginFunction();
LNK_WriteThreadContext *ctx = raw_ctx;
lnk_write_data_to_file_path(ctx->path, ctx->temp_path, ctx->data);
ProfEnd();
}
internal void
lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
internal LNK_LinkContext
lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
{
enum State {
State_Null,
@@ -3593,10 +3558,6 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
State_LookupWeak,
State_LookupEntryPoint,
State_ReportUnresolvedSymbols,
State_BuildImage,
State_BuildImpLib,
State_BuildRadChunkMap,
State_BuildDebugInfo,
};
struct StateNode {
struct StateNode *next;
@@ -3621,15 +3582,15 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
Temp scratch = scratch_begin(tp_arena->v, tp_arena->count);
// inputs
String8List include_symbol_list = config->include_symbol_list;
String8List input_disallow_lib_list = config->disallow_lib_list;
String8List input_manifest_path_list = str8_list_copy(scratch.arena, &config->input_list[LNK_Input_Manifest]);
String8List manifest_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list);
PE_ExportParseList export_symbol_list = {0};
HashTable *export_ht = hash_table_init(scratch.arena, max_U16/2);
LNK_InputObjList input_obj_list = {0};
LNK_InputImportList input_import_list = {0};
LNK_SymbolList input_weak_list = {0};
String8List include_symbol_list = config->include_symbol_list;
String8List input_disallow_lib_list = config->disallow_lib_list;
String8List input_manifest_path_list = str8_list_copy(scratch.arena, &config->input_list[LNK_Input_Manifest]);
String8List manifest_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list);
PE_ExportParseList export_symbol_list = {0};
HashTable *export_ht = hash_table_init(scratch.arena, max_U16/2);
LNK_InputObjList input_obj_list = {0};
LNK_InputImportList input_import_list = {0};
LNK_SymbolList input_weak_list = {0};
LNK_InputLibList input_libs[LNK_InputSource_Count] = {
config->input_list[LNK_Input_Lib], // command line libs
config->input_default_lib_list // default libs
@@ -3663,12 +3624,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
U64 entry_point_lookup_attempts = 0;
B32 report_unresolved_symbols = 1;
B32 input_linker_objs = 1;
B32 build_imp_lib = config->build_imp_lib;
B32 build_rad_chunk_map = (config->rad_chunk_map == LNK_SwitchState_Yes);
B32 build_debug_info = lnk_do_debug_info(config);
String8 image_data = str8_zero();
OS_Handle image_write_thread = {0};
//
// Init state machine
//
@@ -3692,7 +3648,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
// Push config exports
//
for (PE_ExportParseNode *exp_n = config->export_symbol_list.first; exp_n != 0; exp_n = exp_n->next) {
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, exp_n->data);
lnk_push_export(tp_arena->v[0], export_ht, &export_symbol_list, &include_symbol_list, exp_n->data);
}
//
@@ -3702,9 +3658,6 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
lnk_symbol_table_push_alt_name(symtab, 0, alt_n->data.from, alt_n->data.to);
}
ProfBegin("Image"); // :EndImage
lnk_timer_begin(LNK_Timer_Image);
// run states
for (;;) {
while (state_list.count) {
@@ -3904,7 +3857,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) {
PE_ExportParse export_parse = {0};
lnk_parse_export_directive_ex(scratch.arena, dir->value_list, obj->path, obj->lib_path, &export_parse);
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, export_parse);
lnk_push_export(tp_arena->v[0], export_ht, &export_symbol_list, &include_symbol_list, export_parse);
}
}
@@ -3918,7 +3871,9 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
for (String8Node *value_n = dir->value_list.first; value_n != 0; value_n = value_n->next) {
LNK_MergeDirective merge_dir;
if (lnk_parse_merge_directive(value_n->string, &merge_dir)) {
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, merge_dir);
merge_dir.src = push_str8_copy(tp_arena->v[0], merge_dir.src);
merge_dir.dst = push_str8_copy(tp_arena->v[0], merge_dir.dst);
lnk_merge_directive_list_push(tp_arena->v[0], &config->merge_list, merge_dir);
} else {
lnk_error_obj(LNK_Warning_IllData, obj, "can't parse merge directive \"%S\"", value_n->string);
}
@@ -3946,6 +3901,8 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
for (String8Node *string_n = dir->value_list.first; string_n != 0; string_n = string_n->next) {
LNK_AltName alt_name;
if (lnk_parse_alt_name_directive(string_n->string, &alt_name)) {
alt_name.from = push_str8_copy(tp_arena->v[0], alt_name.from);
alt_name.to = push_str8_copy(tp_arena->v[0], alt_name.to);
lnk_symbol_table_push_alt_name(symtab, obj, alt_name.from, alt_name.to);
} else {
lnk_error_obj(LNK_Error_Cmdl, obj, "syntax error in \"%S\", expected format \"FROM=TO\"", string_n->string);
@@ -4270,7 +4227,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->path = str8_lit("* Linker Symbols *");
input->dedup_id = input->path;
input->data = lnk_make_linker_obj(scratch.arena, config);
input->data = lnk_make_linker_obj(tp_arena->v[0], config);
ProfEnd();
}
@@ -4297,23 +4254,22 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]);
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->input_idx = input_obj_list.count;
input->data = pe_make_import_dll_obj_delayed(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat);
input->data = pe_make_import_dll_obj_delayed(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat);
input->path = dll_names[dll_idx];
input->dedup_id = input->path;
//os_write_data_to_file_path(str8_lit("delay_imp.obj"), input->data);
}
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(tp_arena->v[0], config->machine);
{
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->input_idx = input_obj_list.count;
input->data = pe_make_null_import_descriptor_delayed(scratch.arena, time_stamp, config->machine, linker_debug_symbols);
input->data = pe_make_null_import_descriptor_delayed(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols);
input->path = str8_lit("* Delayed Null Import Descriptor *");
input->dedup_id = input->path;
}
{
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->input_idx = input_obj_list.count;
input->data = pe_make_null_thunk_data_obj_delayed(scratch.arena, lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols);
input->data = pe_make_null_thunk_data_obj_delayed(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols);
input->path = str8_lit("* Delayed Null Thunk Data *");
input->dedup_id = input->path;
}
@@ -4332,7 +4288,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]);
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->input_idx = input_obj_list.count;
input->data = pe_make_import_dll_obj_static(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]);
input->data = pe_make_import_dll_obj_static(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]);
input->path = dll_names[dll_idx];
input->dedup_id = dll_names[dll_idx];
}
@@ -4340,14 +4296,14 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
{
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->input_idx = input_obj_list.count;
input->data = pe_make_null_import_descriptor_obj(scratch.arena, time_stamp, config->machine, linker_debug_symbols);
input->data = pe_make_null_import_descriptor_obj(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols);
input->path = str8_lit("* Null Import Descriptor *");
input->dedup_id = input->path;
}
{
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->input_idx = input_obj_list.count;
input->data = pe_make_null_thunk_data_obj(scratch.arena, lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols);
input->data = pe_make_null_thunk_data_obj(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols);
input->path = str8_lit("* Null Thunk Data *");
input->dedup_id = input->path;
}
@@ -4385,7 +4341,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
}
PE_FinalizedExports finalized_exports = pe_finalize_export_list(scratch.arena, resolved_exports);
String8 edata_obj = pe_make_edata_obj(scratch.arena, str8_skip_last_slash(config->image_name), COFF_TimeStamp_Max, config->machine, finalized_exports);
String8 edata_obj = pe_make_edata_obj(tp_arena->v[0], str8_skip_last_slash(config->image_name), COFF_TimeStamp_Max, config->machine, finalized_exports);
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->path = str8_lit("* Exports *");
@@ -4454,7 +4410,7 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
ProfBegin("Build * Resources *");
String8 obj_name = str8_lit("* Resources *");
String8 obj_data = lnk_make_res_obj(scratch.arena,
String8 obj_data = lnk_make_res_obj(tp_arena->v[0],
res_data_list,
res_path_list,
config->machine,
@@ -4472,13 +4428,13 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
}
}
if (build_debug_info) {
if (lnk_do_debug_info(config)) {
{
ProfBegin("Build * Linker * Obj");
String8 obj_name = str8_lit("* Linker *");
String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") });
String8 obj_data = lnk_make_linker_coff_obj(scratch.arena, config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name);
String8 obj_data = lnk_make_linker_coff_obj(tp_arena->v[0], config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name);
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->dedup_id = obj_name;
@@ -4493,131 +4449,18 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->path = str8_lit("* Debug Directory PDB *");
input->dedup_id = input->path;
input->data = pe_make_debug_directory_pdb_obj(scratch.arena, config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path);
input->data = pe_make_debug_directory_pdb_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path);
}
if (config->rad_debug == LNK_SwitchState_Yes) {
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->path = str8_lit("* Debug Directory RDI *");
input->dedup_id = input->path;
input->data = pe_make_debug_directory_rdi_obj(scratch.arena, config->machine, config->guid, config->age, config->time_stamp, config->rad_debug_alt_path);
input->data = pe_make_debug_directory_rdi_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->rad_debug_alt_path);
}
ProfEnd();
}
}
} break;
case State_BuildImage: {
// obj list -> array
U64 objs_count = obj_list.count;
LNK_Obj **objs = lnk_array_from_obj_list(scratch.arena, obj_list);
// build image
image_data = lnk_build_win32_image(tp_arena, tp, config, symtab, objs_count, objs);
// write image to disk in a background thread
{
LNK_WriteThreadContext *ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1);
ctx->path = config->image_name;
ctx->temp_path = config->temp_image_name;
ctx->data = image_data;
image_write_thread = os_thread_launch(lnk_write_thread, ctx, 0);
}
// log
{
if (lnk_get_log_status(LNK_Log_InputObj)) {
U64 total_input_size = 0;
for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { total_input_size += obj_n->data.data.size; }
lnk_log(LNK_Log_InputObj, "[Total Obj Input Size %M]", total_input_size);
}
if (lnk_get_log_status(LNK_Log_InputLib)) {
U64 total_input_size = 0;
for (U64 i = 0; i < ArrayCount(lib_index); ++i) {
LNK_LibList list = lib_index[i];
for (LNK_LibNode *lib_n = list.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; }
}
lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size);
}
}
lnk_timer_end(LNK_Timer_Image);
ProfEnd(); // :EndImage
} break;
case State_BuildImpLib: {
ProfBegin("Build Imp Lib");
lnk_timer_begin(LNK_Timer_Lib);
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
String8List lib_list = pe_make_import_lib(tp_arena->v[0], config->machine, config->time_stamp, str8_skip_last_slash(config->image_name), linker_debug_symbols, export_symbol_list);
lnk_write_data_list_to_file_path(config->imp_lib_name, str8_zero(), lib_list);
lnk_timer_end(LNK_Timer_Lib);
ProfEnd();
} break;
case State_BuildRadChunkMap: {
ProfBegin("RAD Chunk Map");
String8List map = lnk_build_rad_chunk_map(scratch.arena, image_data, config->worker_count, obj_list, lib_index, sectab);
lnk_write_data_list_to_file_path(config->rad_chunk_map_name, config->temp_rad_chunk_map_name, map);
ProfEnd();
} break;
case State_BuildDebugInfo: {
ProfBegin("Debug Info");
lnk_timer_begin(LNK_Timer_Debug);
LNK_CodeViewInput input = lnk_make_code_view_input(tp, tp_arena, config->lib_dir_list, obj_list);
CV_DebugT *types = lnk_import_types(tp, tp_arena, &input);
if (config->rad_debug == LNK_SwitchState_Yes) {
lnk_timer_begin(LNK_Timer_Rdi);
RDI_Arch arch = rdi_arch_from_coff_machine(config->machine);
LNK_SectionArray image_sects = lnk_section_table_get_output_sections(scratch.arena, sectab);
String8List rdi_data = lnk_build_rad_debug_info(tp,
tp_arena,
config->target_os,
arch,
config->image_name,
image_data,
image_sects,
input.count,
input.obj_arr,
input.debug_s_arr,
input.total_symbol_input_count,
input.symbol_inputs,
input.parsed_symbols,
types);
lnk_write_data_list_to_file_path(config->rad_debug_name, config->temp_rad_debug_name, rdi_data);
lnk_timer_end(LNK_Timer_Rdi);
}
// TODO: Parallel debug info builds are currently blocked by the patch
// strings in $$FILE_CHECKSUM step in `lnk_process_c13_data_task`.
if (config->debug_mode == LNK_DebugMode_Full) {
lnk_timer_begin(LNK_Timer_Pdb);
if (config->pdb_hash_type_names != LNK_TypeNameHashMode_Null && config->pdb_hash_type_names != LNK_TypeNameHashMode_None) {
lnk_replace_type_names_with_hashes(tp, tp_arena, types[CV_TypeIndexSource_TPI], config->pdb_hash_type_names, config->pdb_hash_type_name_length, config->pdb_hash_type_name_map);
}
String8List pdb_data = lnk_build_pdb(tp,
tp_arena,
image_data,
config,
symtab,
input.count,
input.obj_arr,
input.debug_s_arr,
input.total_symbol_input_count,
input.symbol_inputs,
input.parsed_symbols,
types);
lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb_data);
lnk_timer_end(LNK_Timer_Pdb);
}
lnk_timer_end(LNK_Timer_Debug);
ProfEnd();
} break;
}
}
@@ -4681,53 +4524,216 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
continue;
}
}
if (image_data.size == 0) {
state_list_push(scratch.arena, state_list, State_BuildImage);
continue;
}
if (build_imp_lib) {
build_imp_lib = 0;
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
state_list_push(scratch.arena, state_list, State_BuildImpLib);
continue;
}
}
if (build_rad_chunk_map) {
build_rad_chunk_map = 0;
state_list_push(scratch.arena, state_list, State_BuildRadChunkMap);
continue;
}
if (build_debug_info) {
build_debug_info = 0;
state_list_push(scratch.arena, state_list, State_BuildDebugInfo);
continue;
}
// wait for the thread to finish writing image to disk
os_thread_join(image_write_thread, -1);
break;
}
// log
{
if (lnk_get_log_status(LNK_Log_InputObj)) {
U64 total_input_size = 0;
for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { total_input_size += obj_n->data.data.size; }
lnk_log(LNK_Log_InputObj, "[Total Obj Input Size %M]", total_input_size);
}
if (lnk_get_log_status(LNK_Log_InputLib)) {
U64 total_input_size = 0;
for (U64 i = 0; i < ArrayCount(lib_index); ++i) {
LNK_LibList list = lib_index[i];
for (LNK_LibNode *lib_n = list.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; }
}
lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size);
}
}
exit:;
LNK_LinkContext link_ctx = {0};
link_ctx.symtab = symtab;
link_ctx.objs_count = obj_list.count;
link_ctx.objs = lnk_array_from_obj_list(tp_arena->v[0], obj_list);
link_ctx.export_symbol_list = export_symbol_list;
MemoryCopyTyped(&link_ctx.lib_index[0], &lib_index[0], ArrayCount(lib_index));
scratch_end(scratch);
return link_ctx;
#undef state_list_push
#undef state_list_pop
}
internal void
lnk_write_thread(void *raw_ctx)
{
ProfBeginFunction();
LNK_WriteThreadContext *ctx = raw_ctx;
lnk_write_data_to_file_path(ctx->path, ctx->temp_path, ctx->data);
ProfEnd();
}
internal void
lnk_log_timers(void)
{
Temp scratch = scratch_begin(0, 0);
U64 total_build_time_micro = 0;
for (U64 i = 0; i < LNK_Timer_Count; ++i) {
total_build_time_micro += g_timers[i].end - g_timers[i].begin;
}
String8List output_list = {0};
str8_list_pushf(scratch.arena, &output_list, "------ Link Times --------------------------------------------------------------");
for (U64 i = 0; i < LNK_Timer_Count; ++i) {
U64 build_time_micro = g_timers[i].end - g_timers[i].begin;
if (build_time_micro != 0) {
String8 timer_name = lnk_string_from_timer_type(i);
DateTime time = date_time_from_micro_seconds(build_time_micro);
String8 time_str = string_from_elapsed_time(scratch.arena, time);
str8_list_pushf(scratch.arena, &output_list, " %-5S Time: %S", timer_name, time_str);
}
}
DateTime total_time = date_time_from_micro_seconds(total_build_time_micro);
String8 total_time_str = string_from_elapsed_time(scratch.arena, total_time);
str8_list_pushf(scratch.arena, &output_list, " Total Time: %S", total_time_str);
StringJoin new_line_join = { str8_lit_comp(""), str8_lit_comp("\n"), str8_lit_comp("") };
String8 output = str8_list_join(scratch.arena, &output_list, &new_line_join);
lnk_log(LNK_Log_Timers, "%S\n", output);
scratch_end(scratch);
}
internal void
lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
{
ProfBeginFunction();
Temp scratch = scratch_begin(tp_arena->v, tp_arena->count);
//
// Link Inputs
//
LNK_LinkContext link_ctx = lnk_build_link_context(tp, tp_arena, config);
//
// Image
//
LNK_ImageContext image_ctx = lnk_build_image(tp_arena, tp, config, link_ctx.symtab, link_ctx.objs_count, link_ctx.objs);
// Write image in the background
LNK_WriteThreadContext *image_write_ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1);
image_write_ctx->path = config->image_name;
image_write_ctx->temp_path = config->temp_image_name;
image_write_ctx->data = image_ctx.image_data;
OS_Handle image_write_thread = os_thread_launch(lnk_write_thread, image_write_ctx, 0);
//
// RAD Map
//
if (config->rad_chunk_map == LNK_SwitchState_Yes) {
String8List rad_map = lnk_build_rad_map(scratch.arena, image_ctx.image_data, config->worker_count, link_ctx.objs_count, link_ctx.objs, link_ctx.lib_index, image_ctx.sectab);
lnk_write_data_list_to_file_path(config->rad_chunk_map_name, config->temp_rad_chunk_map_name, rad_map);
}
//
// Import Library
//
if (config->build_imp_lib && (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL)) {
ProfBegin("Build Import Library");
lnk_timer_begin(LNK_Timer_Lib);
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
String8List lib_list = pe_make_import_lib(tp_arena->v[0], config->machine, config->time_stamp, str8_skip_last_slash(config->image_name), linker_debug_symbols, link_ctx.export_symbol_list);
lnk_write_data_list_to_file_path(config->imp_lib_name, str8_zero(), lib_list);
lnk_timer_end(LNK_Timer_Lib);
ProfEnd();
}
//
// Debug Info
//
if (lnk_do_debug_info(config)) {
ProfBegin("Debug Info");
lnk_timer_begin(LNK_Timer_Debug);
//
// CodeView
//
LNK_CodeViewInput input = lnk_make_code_view_input(tp, tp_arena, config->lib_dir_list, link_ctx.objs_count, link_ctx.objs);
CV_DebugT *types = lnk_import_types(tp, tp_arena, &input);
//
// RDI
//
if (config->rad_debug == LNK_SwitchState_Yes) {
lnk_timer_begin(LNK_Timer_Rdi);
RDI_Arch arch = rdi_arch_from_coff_machine(config->machine);
LNK_SectionArray image_sects = lnk_section_table_get_output_sections(scratch.arena, image_ctx.sectab);
String8List rdi_data = lnk_build_rad_debug_info(tp,
tp_arena,
config->target_os,
arch,
config->image_name,
image_ctx.image_data,
image_sects,
input.count,
input.obj_arr,
input.debug_s_arr,
input.total_symbol_input_count,
input.symbol_inputs,
input.parsed_symbols,
types);
lnk_write_data_list_to_file_path(config->rad_debug_name, config->temp_rad_debug_name, rdi_data);
lnk_timer_end(LNK_Timer_Rdi);
}
//
// PDB
//
// TODO: Parallel debug info builds are currently blocked by the patch
// strings in $$FILE_CHECKSUM step in `lnk_process_c13_data_task`.
if (config->debug_mode == LNK_DebugMode_Full) {
lnk_timer_begin(LNK_Timer_Pdb);
if (config->pdb_hash_type_names != LNK_TypeNameHashMode_Null && config->pdb_hash_type_names != LNK_TypeNameHashMode_None) {
lnk_replace_type_names_with_hashes(tp, tp_arena, types[CV_TypeIndexSource_TPI], config->pdb_hash_type_names, config->pdb_hash_type_name_length, config->pdb_hash_type_name_map);
}
String8List pdb_data = lnk_build_pdb(tp,
tp_arena,
image_ctx.image_data,
config,
link_ctx.symtab,
input.count,
input.obj_arr,
input.debug_s_arr,
input.total_symbol_input_count,
input.symbol_inputs,
input.parsed_symbols,
types);
lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb_data);
lnk_timer_end(LNK_Timer_Pdb);
}
lnk_timer_end(LNK_Timer_Debug);
ProfEnd();
}
// wait for the thread to finish writing image to disk
os_thread_join(image_write_thread, -1);
//
// Timers
//
if (lnk_get_log_status(LNK_Log_Timers)) {
lnk_log_timers();
}
exit:;
// linker is done, punt memory release to OS
//arena_release(ht_arena);
//lnk_section_table_release(&sectab);
//lnk_export_table_release(&export_table);
//lnk_import_table_release(&imptab_static);
//lnk_import_table_release(&imptab_delayed);
//tp_arena_release(&tp_arena);
scratch_end(scratch);
ProfEnd();
#undef state_list_push
#undef state_list_pop
}
internal void
+22 -4
View File
@@ -3,6 +3,23 @@
#pragma once
// --- Link --------------------------------------------------------------------
typedef struct LNK_LinkContext
{
LNK_SymbolTable *symtab;
U64 objs_count;
LNK_Obj **objs;
PE_ExportParseList export_symbol_list;
LNK_LibList lib_index[LNK_InputSource_Count];
} LNK_LinkContext;
typedef struct LNK_ImageContext
{
String8 image_data;
LNK_SectionTable *sectab;
} LNK_ImageContext;
// --- Base Reloc --------------------------------------------------------------
typedef struct LNK_BaseRelocPage
@@ -141,10 +158,11 @@ internal void lnk_queue_lib_member_input(Arena *arena, PathStyle pat
// --- Win32 Image -------------------------------------------------------------
internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
internal String8List lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_temp, LNK_Config *config, U64 objs_count, LNK_Obj **objs);
internal String8List lnk_build_win32_image_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sect_arr, U64 expected_image_header_size);
internal String8 lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, LNK_Obj **objs);
internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config);
internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
internal String8List lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_temp, LNK_Config *config, U64 objs_count, LNK_Obj **objs);
internal String8List lnk_build_win32_image_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sect_arr, U64 expected_image_header_size);
internal LNK_ImageContext lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, LNK_Obj **objs);
// --- Logger ------------------------------------------------------------------
+1 -5
View File
@@ -360,14 +360,10 @@ 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, LNK_ObjList obj_list)
lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir_list, U64 obj_count, LNK_Obj **obj_arr)
{
ProfBegin("Extract CodeView");
Temp scratch = scratch_begin(0,0);
// obj list -> array
U64 obj_count = obj_list.count;
LNK_Obj **obj_arr = lnk_array_from_obj_list(tp_arena->v[0], obj_list);
// gather debug info sections from objs
ProfBegin("Collect CodeView");
+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, LNK_ObjList obj_list);
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_LeafRef lnk_leaf_ref(U32 idx, U32 leaf_idx);
internal LNK_LeafRef lnk_obj_leaf_ref(U32 obj_idx, U32 leaf_idx);