mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
linker checkpoint
This commit is contained in:
committed by
Ryan Fleury
parent
a60216fa9f
commit
7c071e7238
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32Array
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "../third_party_ext/blake3/blake3_portable.c"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_BLAKE3_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U16
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "base_core.c"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal MD5Hash
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8Node *
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
+2467
-2219
File diff suppressed because it is too large
Load Diff
+58
-174
@@ -1,67 +1,11 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LNK_NULL_SYMBOL_NAME "NULL"
|
||||
#define LNK_TEXT_SYMBOL_NAME "TEXT"
|
||||
#define LNK_DATA_SYMBOL_NAME "DATA"
|
||||
#define LNK_RDATA_SYMBOL_NAME "RDATA"
|
||||
#define LNK_BSS_SYMBOL_NAME "BSS"
|
||||
#define LNK_XDATA_SYMBOL_NAME "XDATA"
|
||||
#define LNK_PDATA_SYMBOL_NAME "PDATA"
|
||||
#define LNK_BASE_RELOC_SYMBOL_NAME "BASE_RELOC"
|
||||
#define LNK_EDATA_SYMBOL_NAME "EDATA"
|
||||
#define LNK_DEBUG_DIR_SYMBOL_NAME "DEDIR"
|
||||
#define LNK_DEBUG_DATA_SYMBOL_NAME "DEDAT"
|
||||
#define LNK_CV_DIR_SYMBOL_NAME "CV_DIR"
|
||||
#define LNK_CV_HEADER_PDB70_SYMBOL_NAME "CV_HEADER_PDB70"
|
||||
#define LNK_CV_HEADER_RDI_SYMBOL_NAME "CV_HEADER_RDI"
|
||||
#define LNK_CV_HEADER_GUID_SYMBOL_NAME "CV_HEADER_GUID"
|
||||
#define LNK_RSRC_SYMBOL_NAME "RSRC"
|
||||
#define LNK_DEBUG_SYMBOL_NAME "DEBUG"
|
||||
#define LNK_GFIDS_SYMBOL_NAME "GFIDS"
|
||||
#define LNK_GIATS_SYMBOL_NAME "GIATS"
|
||||
#define LNK_GLJMP_SYMBOL_NAME "GLJMP"
|
||||
#define LNK_GEHCONT_SYMBOL_NAME "GEHCONT"
|
||||
#define LNK_IMPORT_NAME_TABLE_SYMBOL_NAME "IMPORT_STR"
|
||||
#define LNK_IMPORT_DLL_TABLE_SYMBOL_NAME "IDATA"
|
||||
#define LNK_IMPORT_ILT_SYMBOL_NAME "ILT"
|
||||
#define LNK_IMPORT_IAT_SYMBOL_NAME "IAT"
|
||||
#define LNK_IMPORT_JMP_SYMBOL_NAME "IMPORT_THUNKS"
|
||||
#define LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME "DELAYED_IMPORT_DLL_TABLE"
|
||||
#define LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME "DELAYED_IMPORT_HANDLE_TABLE"
|
||||
#define LNK_DELAYED_IMPORT_INT_SYMBOL_NAME "DELAYED_IMPORT_INT"
|
||||
#define LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME "DELAYED_IMPORT_IAT"
|
||||
#define LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME "DELAYED_IMPORT_ILT"
|
||||
#define LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME "DELAYED_IMPORT_BIAT"
|
||||
#define LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME "DELAYED_IMPORT_UIAT"
|
||||
#define LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME "DELAYED_IMPORT_CODE"
|
||||
// --- CRT Symbols -------------------------------------------------------------
|
||||
|
||||
#define LNK_WIN32_HEADER_SYMBOL_NAME "WIN32_HEADER"
|
||||
#define LNK_DOS_SYMBOL_NAME "DOS"
|
||||
#define LNK_NT_HEADERS_SYMBOL_NAME "NT_HEADERS"
|
||||
#define LNK_PE_MAGIC_CONTAINER_SYMBOL_NAME "PE_MAGIC_CONTAINER"
|
||||
#define LNK_COFF_FILE_HEADER_CONTAINER_SYMBOL_NAME "COFF_FILE_HEADER_CONTAINER"
|
||||
#define LNK_PE_OPT_HEADER_CONTAINER_SYMBOL_NAME "PE_OPTIONAL_HEADER_CONTAINER"
|
||||
#define LNK_COFF_SECTION_HEADER_CONTAINER_SYMBOL_NAME "COFF_SECTION_HEADER_CONTAINER"
|
||||
|
||||
#define LNK_DOS_HEADER_SYMBOL_NAME "DOS_HEADER"
|
||||
#define LNK_DOS_PROGRAM_SYMBOL_NAME "DOS_PROGRAM"
|
||||
#define LNK_PE_MAGIC_SYMBOL_NAME "PE_MAGIC"
|
||||
#define LNK_COFF_FILE_HEADER_SYMBOL_NAME "COFF_FILE_HEADER"
|
||||
#define LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME "PE_DIRECTORY_ARRAY"
|
||||
#define LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME "PE_DIRECTORY_COUNT"
|
||||
#define LNK_PE_OPT_HEADER_SYMBOL_NAME "PE_OPTIONAL_HEADER"
|
||||
#define LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME "COFF_SECT_HEADER_ARRAY"
|
||||
#define LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME "COFF_SECT_HEADER_COUNT"
|
||||
#define LNK_PE_CHECKSUM_SYMBOL_NAME "PE_CHECKSUM"
|
||||
|
||||
// _tls_used is a special section in CRT which has format of
|
||||
// PE_TLSHeader32 or PE_TLSHeader64, according to machine type.
|
||||
#define LNK_TLS_SYMBOL_NAME "_tls_used"
|
||||
|
||||
// _load_config_used points to SYMS_PeLoadConfig32/SYMS_PeLoadConfig64
|
||||
// _load_config_used points to PE_LoadConfig32/PE_LoadConfig64
|
||||
// and symbols below are used to patch patricual fields of the struct.
|
||||
#define LNK_LOAD_CONFIG_SYMBOL_NAME "_load_config_used"
|
||||
#define LNK_ENCLAVE_CONFIG_SYMBOL_NAME "__enclave_config"
|
||||
@@ -74,6 +18,7 @@
|
||||
#define LNK_GUARD_LONGJMP_COUNT_SYMBOL_NAME "__guard_longjmp_count"
|
||||
#define LNK_GUARD_EHCONT_TABLE_SYMBOL_NAME "__guard_eh_cont_table"
|
||||
#define LNK_GUARD_EHCONT_COUNT_SYMBOL_NAME "__guard_eh_cont_count"
|
||||
|
||||
// x86 load config fields
|
||||
#define LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME "__safe_se_handler_table"
|
||||
#define LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME "__safe_se_handler_count"
|
||||
@@ -82,6 +27,12 @@
|
||||
#define LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME "__delayLoadHelper2"
|
||||
#define LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME "___delayLoadHelper2@8"
|
||||
|
||||
// _tls_used is a special section in CRT which has format of
|
||||
// PE_TLSHeader32 or PE_TLSHeader64, according to machine type.
|
||||
#define LNK_TLS_SYMBOL_NAME "_tls_used"
|
||||
|
||||
// --- Default Section Flags --------------------------------------------------
|
||||
|
||||
#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CntCode|COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead)
|
||||
#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
|
||||
#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead)
|
||||
@@ -101,38 +52,7 @@
|
||||
#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
|
||||
#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define LNK_COFF_RELOC_FILE_OFFSET32 0x1000
|
||||
#define LNK_COFF_RELOC_SECT_SIZE32 0x1001
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_InputSource_CmdLine, // specified on command line
|
||||
LNK_InputSource_Default, // specified through defaultlib switch
|
||||
LNK_InputSource_Obj, // refrenced from objects
|
||||
LNK_InputSource_Count
|
||||
} LNK_InputSourceType;
|
||||
|
||||
typedef String8Node LNK_InputLib;
|
||||
typedef String8List LNK_InputLibList;
|
||||
|
||||
typedef struct LNK_InputImport
|
||||
{
|
||||
COFF_ParsedArchiveImportHeader import_header;
|
||||
struct LNK_InputImport *next;
|
||||
} LNK_InputImport;
|
||||
|
||||
typedef struct LNK_InputImportList
|
||||
{
|
||||
U64 count;
|
||||
LNK_InputImport *first;
|
||||
LNK_InputImport *last;
|
||||
} LNK_InputImportList;
|
||||
|
||||
////////////////////////////////
|
||||
// --- Base Reloc --------------------------------------------------------------
|
||||
|
||||
typedef struct LNK_BaseRelocPage
|
||||
{
|
||||
@@ -160,11 +80,11 @@ typedef struct LNK_BaseRelocPageArray
|
||||
LNK_BaseRelocPage *v;
|
||||
} LNK_BaseRelocPageArray;
|
||||
|
||||
// --- Workers Contexts --------------------------------------------------------
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 page_size;
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_Reloc **reloc_arr;
|
||||
Rng1U64 *range_arr;
|
||||
LNK_BaseRelocPageList *list_arr;
|
||||
HashTable **page_ht_arr;
|
||||
@@ -175,7 +95,6 @@ typedef struct
|
||||
{
|
||||
Rng1U64 *ranges;
|
||||
U64 page_size;
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_BaseRelocPageList *list_arr;
|
||||
LNK_Obj **obj_arr;
|
||||
HashTable **page_ht_arr;
|
||||
@@ -200,32 +119,10 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
union {
|
||||
LNK_ObjNodeArray objs;
|
||||
LNK_LibNodeArray libs;
|
||||
} u;
|
||||
} LNK_SymbolPusher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 image_data;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SectionTable *sectab;
|
||||
LNK_Section **sect_id_map;
|
||||
U64 base_addr;
|
||||
LNK_Section **sect_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_SectionRelocPatcher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 image_data;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SectionTable *sectab;
|
||||
LNK_Section **sect_id_map;
|
||||
U64 base_addr;
|
||||
LNK_Obj **obj_arr;
|
||||
String8 image_data;
|
||||
LNK_Obj **objs;
|
||||
U64 base_addr;
|
||||
COFF_SectionHeader **image_section_table;
|
||||
} LNK_ObjRelocPatcher;
|
||||
|
||||
typedef struct
|
||||
@@ -242,17 +139,42 @@ typedef struct
|
||||
U128 *hashes;
|
||||
} LNK_Blake3Hasher;
|
||||
|
||||
////////////////////////////////
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
union {
|
||||
LNK_ObjNodeArray objs;
|
||||
LNK_LibNodeArray libs;
|
||||
} u;
|
||||
} LNK_SymbolPusher;
|
||||
|
||||
internal LNK_InputImport * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list);
|
||||
internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat);
|
||||
internal LNK_InputImport ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list);
|
||||
internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count);
|
||||
// --- Entry Point -------------------------------------------------------------
|
||||
|
||||
////////////////////////////////
|
||||
// Helpers
|
||||
internal void lnk_run(int argc, char **argv);
|
||||
|
||||
internal String8 lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, String8 path);
|
||||
// --- Path --------------------------------------------------------------------
|
||||
|
||||
internal String8 lnk_make_full_path(Arena *arena, PathStyle system_path_style, String8 work_dir, String8 path);
|
||||
|
||||
// --- Hasher ------------------------------------------------------------------
|
||||
|
||||
internal U128 lnk_blake3_hash_parallel(TP_Context *tp, U64 chunk_count, String8 data);
|
||||
|
||||
// --- Manifest ----------------------------------------------------------------
|
||||
|
||||
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 Objs -----------------------------------------------------------
|
||||
|
||||
internal String8 lnk_make_res_obj(Arena *arena, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name);
|
||||
internal String8 lnk_make_linker_coff_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 cwd_path, String8 exe_path, String8 pdb_path, String8 cmd_line, String8 obj_name);
|
||||
internal String8 lnk_make_debug_directory_obj(Arena *arena, LNK_Config *config);
|
||||
internal String8 lnk_make_debug_directory_pdb_obj(Arena *arena, LNK_Config *config);
|
||||
internal String8 lnk_make_debug_directory_rdi_obj(Arena *arena, LNK_Config *config);
|
||||
|
||||
// --- Symbol Resolver ---------------------------------------------------------
|
||||
|
||||
internal String8 lnk_get_lib_name(String8 path);
|
||||
internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path);
|
||||
@@ -260,56 +182,18 @@ internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path);
|
||||
internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path);
|
||||
internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
// Manifest
|
||||
internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config);
|
||||
internal void lnk_queue_lib_member_input(Arena *arena, PathStyle path_style, LNK_SymbolLib *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list);
|
||||
|
||||
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);
|
||||
// --- Win32 Image -------------------------------------------------------------
|
||||
|
||||
////////////////////////////////
|
||||
// Resources
|
||||
internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, 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, LNK_ExportTable *exptab, LNK_ObjList obj_list);
|
||||
|
||||
internal void lnk_serialize_pe_resource_tree(COFF_ObjWriter *obj_writer, PE_ResourceDir *root_dir);
|
||||
internal void lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array);
|
||||
internal String8 lnk_make_res_obj(Arena *arena, PE_ResourceDir *root_dir, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 path, String8 cwd_path, String8 exe_path, String8List res_file_list, MD5Hash *res_hash_array);
|
||||
internal String8 lnk_obj_from_res_file_list(Arena *arena, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name);
|
||||
// --- Logger ------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////
|
||||
// Debug
|
||||
|
||||
internal String8 lnk_make_linker_coff_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 cwd_path, String8 exe_path, String8 pdb_path, String8 cmd_line, String8 obj_name);
|
||||
|
||||
////////////////////////////////
|
||||
// Win32 Image Helpers
|
||||
|
||||
internal void lnk_build_debug_pdb(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, U32 age, String8 pdb_path);
|
||||
internal void lnk_build_debug_rdi(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, String8 rdi_path);
|
||||
internal void lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
|
||||
internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, PE_ImageFileCharacteristics file_chars, LNK_ObjList obj_list);
|
||||
internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk);
|
||||
internal LNK_Chunk * lnk_build_pe_magic(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent);
|
||||
internal LNK_Chunk * lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, COFF_TimeStamp time_stamp, PE_ImageFileCharacteristics file_characteristics);
|
||||
internal LNK_Chunk * lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, U64 base_addr, U64 sect_align, U64 file_align, Version linker_ver, Version os_ver, Version image_ver, Version subsystem_ver, PE_WindowsSubsystem subsystem, PE_DllCharacteristics dll_characteristics, U64 stack_reserve, U64 stack_commit, U64 heap_reserve, U64 heap_commit, String8 entry_point_name, LNK_SectionArray sect_arr);
|
||||
internal LNK_Chunk * lnk_build_pe_directories(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent);
|
||||
internal LNK_Chunk * lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk, LNK_SectionArray sect_arr);
|
||||
internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk, LNK_Config *config, LNK_SectionArray sect_arr);
|
||||
|
||||
////////////////////////////////
|
||||
// Relocs
|
||||
|
||||
internal void lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *sectab, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
|
||||
internal void lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *sectab, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
|
||||
|
||||
internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_log_size_breakdown(LNK_SectionTable *sectab, LNK_SymbolTable *symtab);
|
||||
internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *sectab);
|
||||
internal void lnk_log_timers(void);
|
||||
|
||||
////////////////////////////////
|
||||
// Enum <-> String
|
||||
|
||||
internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source);
|
||||
|
||||
|
||||
@@ -1,804 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal LNK_ChunkRef
|
||||
lnk_chunk_ref(U64 sect_id, U64 chunk_id)
|
||||
{
|
||||
LNK_ChunkRef ref = {0};
|
||||
ref.sect_id = sect_id;
|
||||
ref.chunk_id = chunk_id;
|
||||
return ref;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b)
|
||||
{
|
||||
B32 is_equal = a.sect_id == b.sect_id && a.chunk_id == b.chunk_id;
|
||||
return is_equal;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_chunk_list_push(Arena *arena, LNK_ChunkList *list, LNK_Chunk *chunk)
|
||||
{
|
||||
LNK_ChunkNode *node = push_array_no_zero(arena, LNK_ChunkNode, 1);
|
||||
node->next = 0;
|
||||
node->data = chunk;
|
||||
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_list_concat_in_place(LNK_ChunkList *list, LNK_ChunkList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_list_concat_in_place_arr(LNK_ChunkList *list, LNK_ChunkList *arr, U64 count)
|
||||
{
|
||||
SLLConcatInPlaceArray(list, arr, count);
|
||||
}
|
||||
|
||||
internal LNK_ChunkList **
|
||||
lnk_make_chunk_list_arr_arr(Arena *arena, U64 slot_count, U64 per_count)
|
||||
{
|
||||
LNK_ChunkList **arr_arr = push_array_no_zero(arena, LNK_ChunkList *, slot_count);
|
||||
for (U64 i = 0; i < slot_count; i += 1) {
|
||||
arr_arr[i] = push_array(arena, LNK_ChunkList, per_count);
|
||||
}
|
||||
return arr_arr;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_chunk_sort_index_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
// Grouped Sections (PE Format)
|
||||
// "All contributions with the same object-section name are allocated contiguously in the image,
|
||||
// and the blocks of contributions are sorted in lexical order by object-section name."
|
||||
LNK_ChunkPtr *a = raw_a;
|
||||
LNK_ChunkPtr *b = raw_b;
|
||||
|
||||
// sort on section postfix
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->sort_idx, &(*b)->sort_idx);
|
||||
|
||||
// sort on obj position on command line
|
||||
if (cmp == 0) {
|
||||
cmp = u64_compar(&(*a)->input_idx, &(*b)->input_idx);
|
||||
}
|
||||
|
||||
int is_before = cmp < 0;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_array_sort(LNK_ChunkArray arr)
|
||||
{
|
||||
radsort(arr.v, arr.count, lnk_chunk_sort_index_is_before);
|
||||
}
|
||||
|
||||
internal LNK_ChunkManager *
|
||||
lnk_chunk_manager_alloc(Arena *arena, U64 id, U64 align)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkList temp_list = {0};
|
||||
|
||||
LNK_Chunk temp_chunk = {0};
|
||||
temp_chunk.ref = lnk_chunk_ref(id, 0);
|
||||
temp_chunk.align = align;
|
||||
temp_chunk.type = LNK_Chunk_List;
|
||||
temp_chunk.u.list = &temp_list;
|
||||
|
||||
LNK_ChunkManager *cman = push_array_no_zero(arena, LNK_ChunkManager, 1);
|
||||
cman->total_chunk_count = 1; // null chunk
|
||||
cman->root = 0;
|
||||
cman->root = lnk_chunk_push_list(arena, cman, &temp_chunk, str8(0,0));
|
||||
cman->root->align = align;
|
||||
|
||||
ProfEnd();
|
||||
return cman;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push_(Arena *arena, LNK_Chunk *parent, U64 chunk_id, String8 sort_index)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
Assert(parent->type == LNK_Chunk_List);
|
||||
LNK_ChunkList *list = parent->u.list;
|
||||
|
||||
LNK_Chunk *chunk = push_array_no_zero(arena, LNK_Chunk, 1);
|
||||
chunk->ref = lnk_chunk_ref(parent->ref.sect_id, chunk_id);
|
||||
chunk->align = 1;
|
||||
chunk->is_discarded = 0;
|
||||
chunk->sort_chunk = 1;
|
||||
chunk->type = LNK_Chunk_Null;
|
||||
chunk->sort_idx = push_str8_copy(arena, sort_index);
|
||||
chunk->input_idx = list->count;
|
||||
chunk->flags = 0;
|
||||
chunk->associate = 0;
|
||||
|
||||
lnk_chunk_list_push(arena, list, chunk);
|
||||
|
||||
ProfEnd();
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index)
|
||||
{
|
||||
U64 chunk_id = cman->total_chunk_count;
|
||||
++cman->total_chunk_count;
|
||||
LNK_Chunk *chunk = lnk_chunk_push_(arena, parent, chunk_id, sort_index);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index, void *raw_ptr, U64 raw_size)
|
||||
{
|
||||
LNK_Chunk *chunk = lnk_chunk_push(arena, cman, parent, sort_index);
|
||||
chunk->type = LNK_Chunk_Leaf;
|
||||
chunk->u.leaf = str8((U8 *)raw_ptr, raw_size);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index)
|
||||
{
|
||||
LNK_Chunk *chunk = lnk_chunk_push(arena, cman, parent, sort_index);
|
||||
chunk->type = LNK_Chunk_List;
|
||||
chunk->u.list = push_array(arena, LNK_ChunkList, 1);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_ChunkNode *dst_root_node = push_array_no_zero(arena, LNK_ChunkNode, 1);
|
||||
LNK_ChunkNode *src_root_node = push_array_no_zero(scratch.arena, LNK_ChunkNode, 1);
|
||||
src_root_node->next = 0;
|
||||
src_root_node->data = chunk;
|
||||
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkNode *src_node;
|
||||
LNK_ChunkNode *dst_node;
|
||||
};
|
||||
struct Stack *stack = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
stack->next = 0;
|
||||
stack->src_node = src_root_node;
|
||||
stack->dst_node = dst_root_node;
|
||||
|
||||
while (stack) {
|
||||
while (stack->src_node) {
|
||||
LNK_Chunk *src = stack->src_node->data;
|
||||
LNK_Chunk *dst = stack->dst_node->data;
|
||||
|
||||
stack->src_node = stack->src_node->next;
|
||||
stack->dst_node = stack->dst_node->next;
|
||||
|
||||
dst->ref = src->ref;
|
||||
dst->type = src->type;
|
||||
dst->align = src->align;
|
||||
dst->is_discarded = src->is_discarded;
|
||||
dst->sort_chunk = src->sort_chunk;
|
||||
dst->sort_idx = push_str8_copy(arena, src->sort_idx);
|
||||
dst->input_idx = src->input_idx;
|
||||
dst->flags = src->flags;
|
||||
//dst->associate = src->associate;
|
||||
Assert(src->associate == 0);
|
||||
lnk_chunk_set_debugf(arena, dst, "%S", src->debug);
|
||||
|
||||
switch (src->type) {
|
||||
case LNK_Chunk_Null: break;
|
||||
case LNK_Chunk_Leaf: {
|
||||
B32 is_bss = src->u.leaf.str == 0;
|
||||
if (is_bss) {
|
||||
dst->u.leaf = src->u.leaf;
|
||||
} else {
|
||||
dst->u.leaf = push_str8_copy(arena, src->u.leaf);
|
||||
}
|
||||
} break;
|
||||
case LNK_Chunk_List: {
|
||||
LNK_ChunkNode *chain = 0;
|
||||
LNK_ChunkNode *curr = 0;
|
||||
if (src->u.list->count > 0) {
|
||||
chain = push_array(arena, LNK_ChunkNode, src->u.list->count);
|
||||
curr = chain;
|
||||
for (U64 i = 1; i < src->u.list->count; ++i) {
|
||||
curr->next = &chain[i];
|
||||
curr = curr->next;
|
||||
}
|
||||
curr->next = 0;
|
||||
}
|
||||
|
||||
dst->u.list = push_array_no_zero(arena, LNK_ChunkList, 1);
|
||||
dst->u.list->count = src->u.list->count;
|
||||
dst->u.list->first = chain;
|
||||
dst->u.list->last = curr;
|
||||
|
||||
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
frame->next = 0;
|
||||
frame->src_node = src->u.list->first;
|
||||
frame->dst_node = dst->u.list->first;
|
||||
SLLStackPush(stack, frame);
|
||||
} break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
}
|
||||
|
||||
SLLStackPop(stack);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return dst_root_node;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 0);
|
||||
|
||||
Assert(src->ref.sect_id != dst->ref.sect_id);
|
||||
Assert(dst->type == LNK_Chunk_List);
|
||||
Assert(src->type != LNK_Chunk_Null);
|
||||
|
||||
LNK_ChunkNode *src_node = push_array(arena, LNK_ChunkNode, 1);
|
||||
src_node->data = src;
|
||||
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkNode *node;
|
||||
};
|
||||
struct Stack *stack = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
stack->next = 0;
|
||||
stack->node = src_node;
|
||||
|
||||
while (stack) {
|
||||
while (stack->node) {
|
||||
LNK_Chunk *chunk = stack->node->data;
|
||||
|
||||
// advance node
|
||||
stack->node = stack->node->next;
|
||||
|
||||
// allocate id
|
||||
U64 new_id = dst_cman->total_chunk_count++;
|
||||
|
||||
// write id map
|
||||
Assert(chunk->ref.chunk_id < id_map_max);
|
||||
id_map_out[chunk->ref.chunk_id] = new_id;
|
||||
|
||||
// update id
|
||||
chunk->ref = lnk_chunk_ref(dst->ref.sect_id, new_id);
|
||||
|
||||
// recurse down on lists
|
||||
if (chunk->type == LNK_Chunk_List) {
|
||||
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
frame->next = 0;
|
||||
frame->node = chunk->u.list->first;
|
||||
SLLStackPush(stack, frame);
|
||||
}
|
||||
}
|
||||
|
||||
// reached end of chunk list, pop frame
|
||||
SLLStackPop(stack);
|
||||
}
|
||||
|
||||
// move source root copy to destination section
|
||||
LNK_ChunkList *list = dst->u.list;
|
||||
++list->count;
|
||||
SLLQueuePush(list->first, list->last, src_node);
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return src_node;
|
||||
}
|
||||
|
||||
internal
|
||||
LNK_CHUNK_VISITOR_SIG(lnk_set_associate_on_chunks)
|
||||
{
|
||||
chunk->associate = (LNK_Chunk *)ud;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *chunk)
|
||||
{
|
||||
// for simplicity we don't support multiple associations,
|
||||
// but it's possible to craft symbol table with multiple associations
|
||||
AssertAlways(!chunk->associate);
|
||||
lnk_visit_chunks(0, chunk, lnk_set_associate_on_chunks, head);
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_chunk_is_discarded(LNK_Chunk *chunk)
|
||||
{
|
||||
B32 is_discarded = chunk->is_discarded;
|
||||
LNK_Chunk *curr = chunk->associate;
|
||||
while (!is_discarded && curr) {
|
||||
is_discarded = curr->is_discarded;
|
||||
curr = curr->associate;
|
||||
}
|
||||
return is_discarded;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_chunk_get_size(LNK_Chunk *chunk)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Null: break;
|
||||
case LNK_Chunk_Leaf: {
|
||||
result = chunk->u.leaf.size;
|
||||
} break;
|
||||
case LNK_Chunk_LeafArray:
|
||||
case LNK_Chunk_List: {
|
||||
Assert(!"TODO: list size");
|
||||
} break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_chunk_list_get_node_count(LNK_Chunk *chunk)
|
||||
{
|
||||
Assert(chunk->type == LNK_Chunk_List);
|
||||
return chunk->u.list->count;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_pad_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkPadArrayList *list, U64 cap, U64 align_off, U64 align_size)
|
||||
{
|
||||
if (align_size > 0) {
|
||||
if (list->last == 0 || list->last->data.count >= list->last->cap) {
|
||||
LNK_ChunkPadArrayNode *node = push_array(scratch, LNK_ChunkPadArrayNode, 1);
|
||||
node->cap = cap;
|
||||
node->data.v = push_array_no_zero(arena, LNK_ChunkPad, cap);
|
||||
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
}
|
||||
|
||||
LNK_ChunkPadArray *last_array = &list->last->data;
|
||||
LNK_ChunkPad *align = &last_array->v[last_array->count++];
|
||||
align->off = align_off;
|
||||
align->size = align_size;
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
LNK_CHUNK_VISITOR_SIG(lnk_offset_chunks)
|
||||
{
|
||||
LNK_OffsetChunks *offset_chunks = ud;
|
||||
U64 offset = offset_chunks->offset;
|
||||
LNK_ChunkLayout *layout = offset_chunks->layout;
|
||||
|
||||
layout->chunk_off_array[chunk->ref.chunk_id] += offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal LNK_ChunkLayout
|
||||
lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count)
|
||||
{
|
||||
ProfBeginV("lnk_layout_from_chunk [total_chunk_count = %llu]", total_chunk_count);
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_ChunkLayout layout = {0};
|
||||
layout.total_count = total_chunk_count;
|
||||
layout.chunk_ptr_array = push_array_no_zero(arena, LNK_ChunkPtr, total_chunk_count);
|
||||
layout.chunk_off_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
layout.chunk_file_size_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
layout.chunk_virt_size_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
|
||||
ProfBegin("Init Arrays");
|
||||
for (U64 i = 0; i < total_chunk_count; ++i) {
|
||||
layout.chunk_ptr_array[i] = &g_null_chunk;
|
||||
}
|
||||
#if BUILD_DEBUG
|
||||
MemorySet(layout.chunk_off_array, 0xff, total_chunk_count * sizeof(layout.chunk_off_array));
|
||||
MemorySet(layout.chunk_file_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_file_size_array));
|
||||
MemorySet(layout.chunk_virt_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_virt_size_array));
|
||||
#endif
|
||||
ProfEnd();
|
||||
|
||||
// handle null chunk
|
||||
layout.chunk_off_array[0] = 0;
|
||||
layout.chunk_file_size_array[0] = 0;
|
||||
layout.chunk_virt_size_array[0] = 0;
|
||||
|
||||
// setup stack
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkArray chunk_array;
|
||||
U64 ichunk;
|
||||
};
|
||||
struct Stack *stack = push_array(scratch.arena, struct Stack, 1);
|
||||
stack->chunk_array.count = 1;
|
||||
stack->chunk_array.v = &root;
|
||||
|
||||
U64 pad_cap = 4096;
|
||||
LNK_ChunkPadArrayList pad_list = {0};
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
ProfBegin("Traverse chunks from root");
|
||||
for (; stack != 0; ) {
|
||||
for (; stack->ichunk < stack->chunk_array.count; ) {
|
||||
LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++];
|
||||
|
||||
// skip discarded chunk
|
||||
if (lnk_chunk_is_discarded(chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Leaf: {
|
||||
// push pad
|
||||
if (chunk->u.leaf.size < chunk->min_size) {
|
||||
U64 pad_size = chunk->min_size - chunk->u.leaf.size;
|
||||
lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, pad_size);
|
||||
cursor += pad_size;
|
||||
}
|
||||
|
||||
// push align
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, align_size);
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> chunk
|
||||
Assert(chunk->ref.chunk_id < total_chunk_count);
|
||||
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
|
||||
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
|
||||
|
||||
// store id -> offset
|
||||
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
|
||||
|
||||
// store id -> file size
|
||||
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
|
||||
|
||||
// store id -> virt size
|
||||
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
|
||||
|
||||
// advance
|
||||
cursor += chunk->u.leaf.size;
|
||||
} break;
|
||||
|
||||
case LNK_Chunk_LeafArray: {
|
||||
// push align
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, align_size);
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> chunk
|
||||
Assert(chunk->ref.chunk_id < total_chunk_count);
|
||||
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
|
||||
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
|
||||
|
||||
// store id -> offset
|
||||
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
|
||||
|
||||
// apply sort
|
||||
if (chunk->sort_chunk) {
|
||||
lnk_chunk_array_sort(*chunk->u.arr);
|
||||
}
|
||||
|
||||
// recurse into sub chunks
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_array = *chunk->u.arr;
|
||||
SLLStackPush(stack, frame);
|
||||
} goto _continue;
|
||||
|
||||
case LNK_Chunk_List: {
|
||||
// push align
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, align_size);
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> chunk
|
||||
Assert(chunk->ref.chunk_id < total_chunk_count);
|
||||
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
|
||||
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
|
||||
|
||||
// store id -> offset
|
||||
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
|
||||
|
||||
// list -> array
|
||||
LNK_ChunkArray chunk_array = {0};
|
||||
chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count);
|
||||
for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) {
|
||||
chunk_array.v[chunk_array.count++] = cptr->data;
|
||||
}
|
||||
|
||||
// apply sort
|
||||
if (chunk->sort_chunk) {
|
||||
lnk_chunk_array_sort(chunk_array);
|
||||
}
|
||||
|
||||
// recurse into sub chunks
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_array = chunk_array;
|
||||
SLLStackPush(stack, frame);
|
||||
} goto _continue;
|
||||
|
||||
case LNK_Chunk_Null: break;
|
||||
}
|
||||
}
|
||||
|
||||
// terminate series
|
||||
if (stack->next) {
|
||||
// pop node chunk from stack
|
||||
struct Stack *prev = stack->next;
|
||||
|
||||
Assert(prev->ichunk > 0);
|
||||
LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1];
|
||||
|
||||
U64 chunk_data_off = layout.chunk_off_array[chunk->ref.chunk_id];
|
||||
Assert(chunk_data_off != max_U64);
|
||||
Assert(chunk_data_off <= cursor);
|
||||
|
||||
U64 chunk_data_size = cursor - chunk_data_off;
|
||||
|
||||
// store id -> virt size (no pad and align)
|
||||
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk_data_size;
|
||||
|
||||
// push pad
|
||||
if (chunk_data_size < chunk->min_size) {
|
||||
U64 pad_size = chunk->min_size - chunk->u.leaf.size;
|
||||
lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, chunk_data_off, pad_size);
|
||||
|
||||
LNK_OffsetChunks ud = {0};
|
||||
ud.offset = pad_size;
|
||||
ud.layout = &layout;
|
||||
lnk_visit_chunks(0, chunk, lnk_offset_chunks, &ud);
|
||||
}
|
||||
|
||||
// align chunk end
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_pad_array_list_push(arena, scratch.arena, &pad_list, pad_cap, cursor, align_size);
|
||||
cursor += align_size;
|
||||
|
||||
chunk_data_size = cursor - chunk_data_off;
|
||||
|
||||
// store id -> file size (pad + align)
|
||||
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk_data_size;
|
||||
}
|
||||
|
||||
// move to next frame
|
||||
SLLStackPop(stack);
|
||||
|
||||
_continue:;
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Build Pad Array");
|
||||
layout.pad_array_count = 0;
|
||||
layout.pad_array = push_array(arena, LNK_ChunkPadArray, pad_list.count);
|
||||
for (LNK_ChunkPadArrayNode *node = pad_list.first; node != 0; node = node->next) {
|
||||
layout.pad_array[layout.pad_array_count++] = node->data;
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal LNK_ChunkLayout
|
||||
lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
LNK_ChunkLayout layout = lnk_layout_from_chunk(arena, cman->root, cman->total_chunk_count);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkLayoutSerializer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
LNK_ChunkLayout layout = task->layout;
|
||||
String8 buffer = task->buffer;
|
||||
|
||||
for (U64 chunk_idx = range.min; chunk_idx < range.max; ++chunk_idx) {
|
||||
LNK_Chunk *chunk = layout.chunk_ptr_array[chunk_idx];
|
||||
|
||||
if (lnk_chunk_is_discarded(chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunk->type == LNK_Chunk_Leaf) {
|
||||
U64 off = layout.chunk_off_array[chunk->ref.chunk_id];
|
||||
Assert(off + chunk->u.leaf.size <= buffer.size);
|
||||
U8 *buffer_ptr = buffer.str + off;
|
||||
|
||||
if (chunk->u.leaf.str == 0) {
|
||||
// zero out chunk bytes
|
||||
MemorySet(buffer_ptr, 0, chunk->u.leaf.size);
|
||||
} else {
|
||||
// copy chunk bytes
|
||||
MemoryCopy(buffer_ptr, chunk->u.leaf.str, chunk->u.leaf.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_fill_pads_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkLayoutSerializer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
LNK_ChunkLayout layout = task->layout;
|
||||
String8 buffer = task->buffer;
|
||||
U8 fill_byte = task->fill_byte;
|
||||
|
||||
for (U64 pad_array_idx = range.min; pad_array_idx < range.max; ++pad_array_idx) {
|
||||
LNK_ChunkPadArray pad_array = layout.pad_array[pad_array_idx];
|
||||
for (U64 pad_idx = 0; pad_idx < pad_array.count; ++pad_idx) {
|
||||
LNK_ChunkPad pad = pad_array.v[pad_idx];
|
||||
Assert(pad.off + pad.size <= buffer.size);
|
||||
MemorySet(buffer.str + pad.off, fill_byte, pad.size);
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_serialize_chunk_layout(TP_Context *tp, LNK_ChunkLayout layout, String8 buffer, U8 fill_byte)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
LNK_ChunkLayoutSerializer task;
|
||||
task.layout = layout;
|
||||
task.buffer = buffer;
|
||||
task.fill_byte = fill_byte;
|
||||
|
||||
ProfBeginV("Fill Chunks [Chunk Count %llu]", layout.total_count);
|
||||
task.ranges = tp_divide_work(scratch.arena, layout.total_count, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_chunks_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
ProfBeginV("Fill Pads [Array Count %llu]", layout.pad_array_count);
|
||||
task.ranges = tp_divide_work(scratch.arena, layout.pad_array_count, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_pads_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_visit_chunks_(U64 sect_id, LNK_Chunk *chunk, LNK_ChunkVisitorSig *cb, void *ud)
|
||||
{
|
||||
// visit chunk
|
||||
B32 is_done = cb(sect_id, chunk, ud);
|
||||
if (is_done) {
|
||||
return is_done;
|
||||
}
|
||||
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Null:
|
||||
case LNK_Chunk_Leaf: {
|
||||
// reached leaf
|
||||
} break;
|
||||
case LNK_Chunk_LeafArray: {
|
||||
for (U64 idx = 0; idx < chunk->u.arr->count; idx += 1) {
|
||||
is_done = lnk_visit_chunks_(sect_id, chunk->u.arr->v[idx], cb, ud);
|
||||
if (is_done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case LNK_Chunk_List: {
|
||||
for (LNK_ChunkNode *i = chunk->u.list->first; i != 0; i = i->next) {
|
||||
is_done = lnk_visit_chunks_(sect_id, i->data, cb, ud);
|
||||
if (is_done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return is_done;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_visit_chunks(U64 sect_id, LNK_Chunk *chunk, LNK_ChunkVisitorSig *cb, void *ud)
|
||||
{
|
||||
lnk_visit_chunks_(sect_id, chunk, cb, ud);
|
||||
}
|
||||
|
||||
LNK_CHUNK_VISITOR_SIG(lnk_save_chunk_ptr)
|
||||
{
|
||||
LNK_Chunk **id_map = (LNK_Chunk **)ud;
|
||||
if (!chunk->is_discarded) {
|
||||
id_map[chunk->ref.chunk_id] = chunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal LNK_ChunkPtr *
|
||||
lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman)
|
||||
{
|
||||
LNK_ChunkPtr *map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count);
|
||||
lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, map);
|
||||
map[0] = &g_null_chunk;
|
||||
return map;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_chunk_ptr_list_reserve(Arena *arena, LNK_ChunkList *list, U64 count)
|
||||
{
|
||||
LNK_ChunkNode *arr = 0;
|
||||
if (count) {
|
||||
arr = push_array(arena, LNK_ChunkNode, count);
|
||||
LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, count);
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
arr[i].data = &chunk_arr[i];
|
||||
SLLQueuePush(list->first, list->last, &arr[i]);
|
||||
}
|
||||
list->count += count;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal String8Array
|
||||
lnk_data_arr_from_chunk_ptr_list(Arena *arena, LNK_ChunkList list)
|
||||
{
|
||||
String8Array arr = {0};
|
||||
arr.v = push_array(arena, String8, list.count);
|
||||
for (LNK_ChunkNode *n = list.first; n != 0; n = n->next) {
|
||||
LNK_ChunkPtr c = n->data;
|
||||
Assert(c->type == LNK_Chunk_Leaf);
|
||||
arr.v[arr.count] = c->u.leaf;
|
||||
arr.count += 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal String8Array *
|
||||
lnk_data_arr_from_chunk_ptr_list_arr(Arena *arena, LNK_ChunkList *list_arr, U64 count)
|
||||
{
|
||||
String8Array *result = push_array(arena, String8Array, count);
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
result[i] = lnk_data_arr_from_chunk_ptr_list(arena, list_arr[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_string_from_chunk_type(LNK_ChunkType type)
|
||||
{
|
||||
switch (type) {
|
||||
case LNK_Chunk_Null: return str8_lit("Null");
|
||||
case LNK_Chunk_Leaf: return str8_lit("Leaf");
|
||||
case LNK_Chunk_LeafArray: return str8_lit("LeafArray");
|
||||
case LNK_Chunk_List: return str8_lit("List");
|
||||
default: InvalidPath;
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define LNK_DEBUG_CHUNKS 1
|
||||
|
||||
#if LNK_DEBUG_CHUNKS
|
||||
# define lnk_chunk_set_debugf(a, c, f, ...) do { (c)->debug = push_str8f((a), f, __VA_ARGS__); } while(0)
|
||||
#else
|
||||
# define lnk_chunk_set_debugf(a, c, f, ...) (void)(c)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct LNK_ChunkRef
|
||||
{
|
||||
U64 sect_id;
|
||||
U64 chunk_id;
|
||||
} LNK_ChunkRef;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_Chunk_Null,
|
||||
LNK_Chunk_Leaf,
|
||||
LNK_Chunk_LeafArray,
|
||||
LNK_Chunk_List,
|
||||
} LNK_ChunkType;
|
||||
|
||||
typedef struct LNK_Chunk
|
||||
{
|
||||
LNK_ChunkRef ref;
|
||||
LNK_ChunkType type;
|
||||
U64 align;
|
||||
U64 min_size;
|
||||
B32 is_discarded;
|
||||
B32 sort_chunk;
|
||||
String8 sort_idx;
|
||||
U64 input_idx;
|
||||
COFF_SectionFlags flags;
|
||||
struct LNK_Chunk *associate;
|
||||
union {
|
||||
String8 leaf;
|
||||
struct LNK_ChunkList *list;
|
||||
struct LNK_ChunkArray *arr;
|
||||
} u;
|
||||
struct LNK_Obj *obj;
|
||||
#if LNK_DEBUG_CHUNKS
|
||||
String8 debug;
|
||||
#endif
|
||||
} LNK_Chunk, * LNK_ChunkPtr;
|
||||
|
||||
typedef struct LNK_ChunkNode
|
||||
{
|
||||
struct LNK_ChunkNode *next;
|
||||
LNK_ChunkPtr data;
|
||||
} LNK_ChunkNode;
|
||||
|
||||
typedef struct LNK_ChunkArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkPtr *v;
|
||||
} LNK_ChunkArray;
|
||||
|
||||
typedef struct LNK_ChunkList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkNode *first;
|
||||
LNK_ChunkNode *last;
|
||||
} LNK_ChunkList;
|
||||
|
||||
typedef enum LNK_ChunkOpType
|
||||
{
|
||||
LNK_ChunkOp_Null,
|
||||
LNK_ChunkOp_WriteString,
|
||||
LNK_ChunkOp_Align,
|
||||
LNK_ChunkOp_Begin,
|
||||
LNK_ChunkOp_End,
|
||||
LNK_ChunkOp_EndVirt,
|
||||
} LNK_ChunkOpType;
|
||||
|
||||
typedef struct LNK_ChunkOp
|
||||
{
|
||||
struct LNK_ChunkOp *next;
|
||||
LNK_ChunkOpType type;
|
||||
union {
|
||||
String8 string;
|
||||
LNK_Chunk *chunk;
|
||||
struct {
|
||||
U64 val;
|
||||
U64 x;
|
||||
} align;
|
||||
LNK_Chunk *leaf;
|
||||
} u;
|
||||
} LNK_ChunkOp;
|
||||
|
||||
typedef struct LNK_ChunkOpList
|
||||
{
|
||||
U64 total_chunk_count;
|
||||
LNK_ChunkOp *first;
|
||||
LNK_ChunkOp *last;
|
||||
} LNK_ChunkOpList;
|
||||
|
||||
typedef struct LNK_ChunkPad
|
||||
{
|
||||
U64 off;
|
||||
U64 size;
|
||||
} LNK_ChunkPad;
|
||||
|
||||
typedef struct LNK_ChunkPadArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkPad *v;
|
||||
} LNK_ChunkPadArray;
|
||||
typedef struct LNK_ChunkPadArrayNode
|
||||
{
|
||||
struct LNK_ChunkPadArrayNode *next;
|
||||
U64 cap;
|
||||
LNK_ChunkPadArray data;
|
||||
} LNK_ChunkPadArrayNode;
|
||||
typedef struct LNK_ChunkPadArrayList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkPadArrayNode *first;
|
||||
LNK_ChunkPadArrayNode *last;
|
||||
} LNK_ChunkPadArrayList;
|
||||
|
||||
typedef struct LNK_ChunkLayout
|
||||
{
|
||||
U64 total_count;
|
||||
LNK_Chunk **chunk_ptr_array; // discarded chunks point to g_null_chunk
|
||||
U64 *chunk_off_array; // discarded chunks have offset set to max_U64
|
||||
U64 *chunk_file_size_array; // discarded chunks have offset set to max_U64
|
||||
U64 *chunk_virt_size_array; // discarded chunks have offset set to max_U64
|
||||
U64 pad_array_count;
|
||||
LNK_ChunkPadArray *pad_array;
|
||||
} LNK_ChunkLayout;
|
||||
|
||||
typedef struct LNK_ChunkManager
|
||||
{
|
||||
LNK_Chunk *root;
|
||||
U64 total_chunk_count;
|
||||
} LNK_ChunkManager;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 offset;
|
||||
LNK_ChunkLayout *layout;
|
||||
} LNK_OffsetChunks;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_ChunkLayout layout;
|
||||
String8 buffer;
|
||||
U8 fill_byte;
|
||||
Rng1U64 *ranges;
|
||||
} LNK_ChunkLayoutSerializer;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
read_only global LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
|
||||
read_only global LNK_Chunk *g_null_chunk_ptr = &g_null_chunk;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_ChunkRef lnk_chunk_ref(U64 sect_id, U64 chunk_id);
|
||||
internal B32 lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b);
|
||||
|
||||
internal LNK_ChunkNode * lnk_chunk_list_push(Arena *arena, LNK_ChunkList *list, LNK_Chunk *chunk);
|
||||
internal void lnk_chunk_list_concat_in_place(LNK_ChunkList *list, LNK_ChunkList *to_concat);
|
||||
internal void lnk_chunk_list_concat_in_place_arr(LNK_ChunkList *list, LNK_ChunkList *arr, U64 count);
|
||||
internal LNK_ChunkList ** lnk_make_chunk_list_arr_arr(Arena *arena, U64 slot_count, U64 per_count);
|
||||
internal void lnk_chunk_array_sort(LNK_ChunkArray arr);
|
||||
|
||||
internal LNK_ChunkManager * lnk_chunk_manager_alloc(Arena *arena, U64 id, U64 align);
|
||||
internal LNK_Chunk * lnk_chunk_push(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index, void *raw_ptr, U64 raw_size);
|
||||
internal LNK_Chunk * lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index);
|
||||
internal LNK_ChunkNode * lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk);
|
||||
internal LNK_ChunkNode * lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max);
|
||||
internal void lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *associate);
|
||||
internal B32 lnk_chunk_is_discarded(LNK_Chunk *chunk);
|
||||
internal U64 lnk_chunk_get_size(LNK_Chunk *chunk);
|
||||
internal U64 lnk_chunk_list_get_node_count(LNK_Chunk *chunk);
|
||||
|
||||
internal void lnk_chunk_op_list_push_node(LNK_ChunkOpList *list, LNK_ChunkOp *op);
|
||||
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_begin(Arena *arena, U64 chunk_id);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_end_virt(Arena *arena);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_end_file(Arena *arena);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string);
|
||||
|
||||
internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count);
|
||||
internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman);
|
||||
|
||||
#define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud)
|
||||
typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig);
|
||||
internal void lnk_visit_chunks(U64 sect_id, LNK_Chunk *root, LNK_ChunkVisitorSig *cb, void *ud);
|
||||
|
||||
internal LNK_ChunkNode * lnk_chunk_ptr_list_reserve(Arena *arena, LNK_ChunkList *list, U64 count);
|
||||
internal String8Array lnk_data_arr_from_chunk_ptr_list(Arena *arena, LNK_ChunkList list);
|
||||
internal String8Array * lnk_data_arr_from_chunk_ptr_list_arr(Arena *arena, LNK_ChunkList *list_arr, U64 count);
|
||||
|
||||
internal String8 lnk_string_from_chunk_type(LNK_ChunkType type);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8List
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
+11
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
@@ -396,7 +396,11 @@ lnk_get_base_addr(LNK_Config *config)
|
||||
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) {
|
||||
base_addr = coff_default_exe_base_from_machine(config->machine);
|
||||
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.");
|
||||
}
|
||||
@@ -2002,6 +2006,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
config->opt_lbr = LNK_SwitchState_Yes;
|
||||
}
|
||||
}
|
||||
|
||||
// warn about unused large address aware flag
|
||||
if ((~config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE) && (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL)) {
|
||||
lnk_error(LNK_Warning_NoLargeAddressAwarenessForDll, "/LARGEADDRESSAWARE:NO has no effect when specified together with /DLL");
|
||||
}
|
||||
|
||||
// error check base address flags
|
||||
if (config->flags & LNK_ConfigFlag_Fixed) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
lnk_make_linker_compile3(Arena *arena, COFF_MachineType machine)
|
||||
{
|
||||
String8 comp3_data = cv_make_comp3(arena,
|
||||
0,
|
||||
CV_Language_LINK,
|
||||
cv_arch_from_coff_machine(machine),
|
||||
/* ver_fe_major */ 0,
|
||||
/* ver_fe_minor */ 0,
|
||||
/* ver_fe_build */ 0,
|
||||
/* ver_feqfe */ 0,
|
||||
/* ver_major */ 14,
|
||||
/* ver_minor */ 36,
|
||||
/* ver_build */ 32537,
|
||||
/* ver_qfe */ 0,
|
||||
str8_lit(BUILD_TITLE));
|
||||
return comp3_data;
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_make_debug_s(Arena *arena, CV_SymbolList symbol_list)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
CV_DebugS debug_s = {0};
|
||||
String8List *symbol_list_ptr = cv_sub_section_ptr_from_debug_s(&debug_s, CV_C13SubSectionKind_Symbols);
|
||||
*symbol_list_ptr = cv_data_from_symbol_list(scratch.arena, symbol_list, CV_SymbolAlign);
|
||||
|
||||
String8List debug_s_data_list = cv_data_c13_from_debug_s(scratch.arena, &debug_s, 1);
|
||||
String8 debug_s_data = str8_list_join(arena, &debug_s_data_list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return debug_s_data;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
internal String8 lnk_make_linker_compile3(Arena *arena, COFF_MachineType machine);
|
||||
internal String8 lnk_make_debug_s(Arena *arena, CV_SymbolList symbol_list);
|
||||
|
||||
+105
-143
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
@@ -9,16 +9,13 @@ THREAD_POOL_TASK_FUNC(lnk_parse_debug_s_task)
|
||||
U64 obj_idx = task_id;
|
||||
LNK_ParseDebugSTaskData *task = raw_task;
|
||||
|
||||
LNK_Obj *obj = task->obj_arr[obj_idx];
|
||||
LNK_ChunkList sect_list = task->sect_list_arr[obj_idx];
|
||||
CV_DebugS *debug_s = &task->debug_s_arr[obj_idx];
|
||||
|
||||
for (LNK_ChunkNode *node = sect_list.first; node != 0; node = node->next) {
|
||||
LNK_ChunkPtr chunk = node->data;
|
||||
Assert(chunk->type == LNK_Chunk_Leaf);
|
||||
LNK_Obj *obj = task->obj_arr[obj_idx];
|
||||
String8List sect_list = task->sect_list_arr[obj_idx];
|
||||
CV_DebugS *debug_s = &task->debug_s_arr[obj_idx];
|
||||
|
||||
for (String8Node *node = sect_list.first; node != 0; node = node->next) {
|
||||
// parse & merge sub sections
|
||||
CV_DebugS ds = cv_parse_debug_s(arena, chunk->u.leaf);
|
||||
CV_DebugS ds = cv_parse_debug_s(arena, node->string);
|
||||
cv_debug_s_concat_in_place(debug_s, &ds);
|
||||
|
||||
// make sure there is one string table
|
||||
@@ -38,7 +35,7 @@ THREAD_POOL_TASK_FUNC(lnk_parse_debug_s_task)
|
||||
}
|
||||
|
||||
internal CV_DebugS *
|
||||
lnk_parse_debug_s_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, LNK_ChunkList *sect_list_arr)
|
||||
lnk_parse_debug_s_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *sect_list_arr)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
@@ -113,12 +110,12 @@ THREAD_POOL_TASK_FUNC(lnk_parse_debug_t_task)
|
||||
}
|
||||
|
||||
internal CV_DebugT *
|
||||
lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, LNK_ChunkList *debug_t_list_arr)
|
||||
lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *debug_t_list_arr)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
// list -> array
|
||||
String8Array *data_arr_arr = lnk_data_arr_from_chunk_ptr_list_arr(arena->v[0], debug_t_list_arr, obj_count);
|
||||
String8Array *data_arr_arr = str8_array_from_list_arr(arena->v[0], debug_t_list_arr, obj_count);
|
||||
|
||||
// validate signatures
|
||||
LNK_CheckDebugTSigTaskData check_sig;
|
||||
@@ -376,26 +373,26 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
ProfBegin("Collect CodeView");
|
||||
// TODO: fix memory leak, we need a Temp wrapper for pool arena
|
||||
B32 collect_discarded_flag = 0;
|
||||
LNK_ChunkList *debug_s_list_arr = lnk_collect_obj_chunks(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug"), str8_lit("S"), collect_discarded_flag);
|
||||
LNK_ChunkList *debug_p_list_arr = lnk_collect_obj_chunks(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug"), str8_lit("P"), collect_discarded_flag);
|
||||
LNK_ChunkList *debug_t_list_arr = lnk_collect_obj_chunks(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug"), str8_lit("T"), collect_discarded_flag);
|
||||
String8List *debug_s_list_arr = lnk_collect_obj_chunks_parallel(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug"), str8_lit("S"), collect_discarded_flag);
|
||||
String8List *debug_p_list_arr = lnk_collect_obj_chunks_parallel(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug"), str8_lit("P"), collect_discarded_flag);
|
||||
String8List *debug_t_list_arr = lnk_collect_obj_chunks_parallel(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug"), str8_lit("T"), collect_discarded_flag);
|
||||
ProfEnd();
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_Debug) || PROFILE_TELEMETRY) {
|
||||
U64 total_debug_s_size = 0, total_debug_t_size = 0, total_debug_p_size = 0;
|
||||
for (U64 obj_idx = 0; obj_idx < obj_count; ++obj_idx) {
|
||||
for (LNK_ChunkNode *chunk = debug_s_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_s_size += chunk->data->u.leaf.size;
|
||||
for (String8Node *chunk = debug_s_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_s_size += chunk->string.size;
|
||||
}
|
||||
for (LNK_ChunkNode *chunk = debug_t_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_t_size += chunk->data->u.leaf.size;
|
||||
for (String8Node *chunk = debug_t_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_t_size += chunk->string.size;
|
||||
}
|
||||
for (LNK_ChunkNode *chunk = debug_p_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_p_size += chunk->data->u.leaf.size;
|
||||
for (String8Node *chunk = debug_p_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_p_size += chunk->string.size;
|
||||
}
|
||||
}
|
||||
|
||||
ProfNoteV("Total .debug$S Input Size: %M", total_debug_s_size);
|
||||
ProfNoteV("Total .debug$S Input Size: %M", total_debug_s_size);
|
||||
ProfNoteV("Total .debug$T Input Size: %M", total_debug_t_size);
|
||||
ProfNoteV("Total .debug$P Input Size: %M", total_debug_p_size);
|
||||
|
||||
@@ -416,10 +413,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
str8_serial_push_string(scratch.arena, &srl, raw_null_leaf);
|
||||
String8 null_debug_data = str8_serial_end(tp_arena->v[0], &srl);
|
||||
|
||||
LNK_Chunk *null_chunk = push_array(tp_arena->v[0], LNK_Chunk, 1);
|
||||
null_chunk->type = LNK_Chunk_Leaf;
|
||||
null_chunk->u.leaf = null_debug_data;
|
||||
lnk_chunk_list_push(tp_arena->v[0], &debug_t_list_arr[0], null_chunk);
|
||||
str8_list_push(tp_arena->v[0], &debug_t_list_arr[0], null_debug_data);
|
||||
}
|
||||
|
||||
ProfBegin("Parse CodeView");
|
||||
@@ -2971,55 +2965,43 @@ lnk_hash_cv_symbol_ptr_arr(TP_Context *tp, Arena *arena, CV_SymbolPtrArray arr)
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
|
||||
{
|
||||
U64 obj_idx = task_id;
|
||||
LNK_PushDbiSecContribTaskData *task = raw_task;
|
||||
LNK_Section **sect_id_map = task->sect_id_map;
|
||||
PDB_DbiModule *mod = task->mod_arr[obj_idx];
|
||||
LNK_Obj *obj = &task->obj_arr[obj_idx];
|
||||
PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx];
|
||||
String8 image_data = task->image_data;
|
||||
|
||||
// TODO: use chunked lists for SC
|
||||
// TODO: put back unused sc nodes
|
||||
// TODO: compute CRC for relocations
|
||||
|
||||
// TODO: put back unused nodes
|
||||
PDB_DbiSectionContribNode *sc_arr = push_array_no_zero(arena, PDB_DbiSectionContribNode, obj->sect_count);
|
||||
U64 sc_count = 0;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_PushDbiSecContribTaskData *task = raw_task;
|
||||
PDB_DbiModule *mod = task->mod_arr[obj_idx];
|
||||
LNK_Obj *obj = &task->obj_arr[obj_idx];
|
||||
|
||||
COFF_SectionHeader *obj_section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
|
||||
PDB_DbiSectionContribNode *sc_arr = push_array_no_zero(arena, PDB_DbiSectionContribNode, obj->header.section_count_no_null);
|
||||
U64 sc_count = 0;
|
||||
|
||||
for (U64 chunk_idx = 0; chunk_idx < obj->sect_count; ++chunk_idx) {
|
||||
LNK_Chunk *chunk = obj->chunk_arr[chunk_idx];
|
||||
|
||||
if (!chunk || lnk_chunk_is_discarded(chunk)) {
|
||||
for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) {
|
||||
COFF_SectionHeader *obj_sect_header = &obj_section_table[sect_idx];
|
||||
|
||||
if (obj_sect_header->flags & COFF_SectionFlag_LnkRemove) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LNK_Section *sect = lnk_sect_from_chunk_ref(task->sect_id_map, chunk->ref);
|
||||
if (!sect->has_layout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// query chunk info
|
||||
ISectOff chunk_sc = lnk_sc_from_chunk_ref (sect_id_map, chunk->ref);
|
||||
String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, image_data, chunk->ref);
|
||||
LNK_Section *chunk_sect = lnk_sect_from_chunk_ref (sect_id_map, chunk->ref);
|
||||
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref);
|
||||
|
||||
// compute chunk CRC
|
||||
U32 data_crc = update_crc32(0, chunk_data.str, chunk_data.size);
|
||||
U32 reloc_crc = 0; // TODO: compute CRC for relocations block
|
||||
U64 sect_number = rng_1u64_array_bsearch(task->image_section_file_ranges, obj_sect_header->foff);
|
||||
String8 sect_data = str8_substr(task->image_data, rng_1u64(obj_sect_header->foff, obj_sect_header->foff + obj_sect_header->fsize));
|
||||
U32 sect_off = obj_sect_header->foff - task->image_section_file_ranges.v[sect_number].min;
|
||||
|
||||
// fill out SC
|
||||
PDB_DbiSectionContribNode *sc = sc_arr + sc_count++;
|
||||
sc->data.base.sec = safe_cast_u16(chunk_sc.isect);
|
||||
sc->data.base.sec = (U16)sect_number;
|
||||
sc->data.base.pad0 = 0;
|
||||
sc->data.base.sec_off = chunk_sc.off;
|
||||
sc->data.base.size = safe_cast_u32(chunk_size);
|
||||
sc->data.base.flags = chunk_sect->flags;
|
||||
sc->data.base.sec_off = sect_off;
|
||||
sc->data.base.size = obj_sect_header->foff;
|
||||
sc->data.base.flags = obj_sect_header->flags;
|
||||
sc->data.base.mod = mod->imod;
|
||||
sc->data.base.pad1 = 0;
|
||||
sc->data.data_crc = data_crc;
|
||||
sc->data.reloc_crc = reloc_crc;
|
||||
sc->data.data_crc = update_crc32(0, sect_data.str, sect_data.size);
|
||||
sc->data.reloc_crc = 0;
|
||||
|
||||
dbi_sec_contrib_list_push_node(dst_list, sc);
|
||||
dbi_sec_contrib_list_push_node(&task->sc_list[obj_idx], sc);
|
||||
}
|
||||
|
||||
// Mod1::fUpdateSecContrib
|
||||
@@ -3040,36 +3022,33 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_BuildPublicSymbolsTask *task = raw_task;
|
||||
LNK_Section **sect_id_map = task->sect_id_map;
|
||||
CV_SymbolList *pub_list = &task->pub_list_arr[task_id];
|
||||
LNK_SymbolHashTrieChunkList chunk_list = task->chunk_lists[task_id];
|
||||
LNK_BuildPublicSymbolsTask *task = raw_task;
|
||||
CV_SymbolList *pub_list = &task->pub_list_arr[task_id];
|
||||
LNK_SymbolHashTrieChunkList chunk_list = task->chunk_lists[task_id];
|
||||
|
||||
for (LNK_SymbolHashTrieChunk *chunk = chunk_list.first; chunk != 0; chunk = chunk->next) {
|
||||
CV_SymbolNode *nodes = push_array_no_zero(arena, CV_SymbolNode, chunk->count);
|
||||
|
||||
for (U64 i = 0, node_idx = 0; i < chunk->count; ++i) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
Assert(symbol->type == LNK_Symbol_Defined);
|
||||
|
||||
Assert(LNK_Symbol_IsDefined(symbol->type));
|
||||
|
||||
LNK_DefinedSymbol *defined_symbol = &symbol->u.defined;
|
||||
if (defined_symbol->value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Regular) {
|
||||
CV_Pub32Flags flags = 0;
|
||||
if (defined_symbol->flags & LNK_DefinedSymbolFlag_IsFunc || defined_symbol->flags & LNK_DefinedSymbolFlag_IsThunk) {
|
||||
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
|
||||
flags |= CV_Pub32Flag_Function;
|
||||
}
|
||||
|
||||
U64 symbol_off = lnk_sect_off_from_symbol(sect_id_map, symbol);
|
||||
U64 symbol_isect = lnk_isect_from_symbol(sect_id_map, symbol);
|
||||
|
||||
U32 symbol_off32 = safe_cast_u32(symbol_off);
|
||||
U16 symbol_isect16 = safe_cast_u16(symbol_isect);
|
||||
ISectOff sc = lnk_sc_from_symbol(symbol);
|
||||
U16 symbol_isect16 = safe_cast_u16(sc.isect);
|
||||
U32 symbol_off32 = safe_cast_u32(sc.off);
|
||||
|
||||
nodes[node_idx].data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name);
|
||||
cv_symbol_list_push_node(pub_list, &nodes[node_idx]);
|
||||
|
||||
++node_idx;
|
||||
node_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3098,7 +3077,6 @@ internal void
|
||||
lnk_build_pdb_public_symbols(TP_Context *tp,
|
||||
TP_Arena *arena,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_Section **sect_id_map,
|
||||
PDB_PsiContext *psi)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
@@ -3106,9 +3084,8 @@ lnk_build_pdb_public_symbols(TP_Context *tp,
|
||||
|
||||
ProfBegin("Defined");
|
||||
LNK_BuildPublicSymbolsTask task = {0};
|
||||
task.sect_id_map = sect_id_map;
|
||||
task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count);
|
||||
task.chunk_lists = symtab->chunk_lists[LNK_SymbolScopeIndex_Defined];
|
||||
task.chunk_lists = symtab->chunk_lists[LNK_SymbolScope_Defined];
|
||||
tp_for_parallel(tp, arena, tp->worker_count, lnk_build_pdb_public_symbols_defined_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
@@ -3126,16 +3103,8 @@ internal String8List
|
||||
lnk_build_pdb(TP_Context *tp,
|
||||
TP_Arena *tp_arena,
|
||||
String8 image_data,
|
||||
Guid guid,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U32 age,
|
||||
U64 page_size,
|
||||
String8 pdb_name,
|
||||
String8List lib_dir_list,
|
||||
String8List natvis_list,
|
||||
LNK_Config *config,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_Section **sect_id_map,
|
||||
U64 obj_count,
|
||||
LNK_Obj *obj_arr,
|
||||
CV_DebugS *debug_s_arr,
|
||||
@@ -3147,8 +3116,12 @@ lnk_build_pdb(TP_Context *tp,
|
||||
ProfBegin("PDB");
|
||||
Temp scratch = scratch_begin(tp_arena->v, tp_arena->count);
|
||||
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, image_data);
|
||||
COFF_SectionHeader **image_section_table = coff_section_table_from_data(scratch.arena, image_data, pe.section_table_range);
|
||||
U64 image_section_table_count = pe.section_count+1;
|
||||
|
||||
ProfBegin("Setup PDB Context");
|
||||
PDB_Context *pdb = pdb_alloc(page_size, machine, time_stamp, age, guid);
|
||||
PDB_Context *pdb = pdb_alloc(config->page_size, config->machine, config->time_stamp, config->age, config->guid);
|
||||
ProfEnd();
|
||||
|
||||
// move patched type data
|
||||
@@ -3284,27 +3257,29 @@ lnk_build_pdb(TP_Context *tp,
|
||||
|
||||
ProfBegin("Build DBI Section Headers");
|
||||
{
|
||||
LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME);
|
||||
LNK_Chunk *coff_sect_chunk = lnk_chunk_from_symbol(coff_sect_array_symbol);
|
||||
String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, coff_sect_chunk->ref);
|
||||
U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader);
|
||||
COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str;
|
||||
for (COFF_SectionHeader *hdr_ptr = &coff_sect_ptr[0], *opl = hdr_ptr + coff_sect_count;
|
||||
hdr_ptr < opl;
|
||||
++hdr_ptr) {
|
||||
dbi_push_section(pdb->dbi, hdr_ptr);
|
||||
for (U64 sect_idx = 1; sect_idx < image_section_table_count; sect_idx += 1) {
|
||||
dbi_push_section(pdb->dbi, image_section_table[sect_idx]);
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Build Section Contrib Map");
|
||||
{
|
||||
|
||||
Rng1U64Array image_section_file_ranges = {0};
|
||||
image_section_file_ranges.count = image_section_table_count;
|
||||
image_section_file_ranges.v = push_array(scratch.arena, Rng1U64, image_section_table_count);
|
||||
for (U64 i = 0; i < image_section_table_count; i += 1) {
|
||||
COFF_SectionHeader *sect_header = image_section_table[i];
|
||||
image_section_file_ranges.v[i] = rng_1u64(sect_header->foff, sect_header->foff + sect_header->fsize);
|
||||
}
|
||||
|
||||
LNK_PushDbiSecContribTaskData task = {0};
|
||||
task.obj_arr = obj_arr;
|
||||
task.sect_id_map = sect_id_map;
|
||||
task.mod_arr = mod_arr;
|
||||
task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, obj_count);
|
||||
task.image_data = image_data;
|
||||
task.image_section_file_ranges = image_section_file_ranges;
|
||||
tp_for_parallel(tp, tp_arena, obj_count, lnk_push_dbi_sec_contrib_task, &task);
|
||||
|
||||
dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list);
|
||||
@@ -3313,7 +3288,7 @@ lnk_build_pdb(TP_Context *tp,
|
||||
|
||||
ProfBegin("Build NatVis");
|
||||
{
|
||||
String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &natvis_list);
|
||||
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);
|
||||
|
||||
for (U64 i = 0; i < natvis_file_data_arr.count; ++i) {
|
||||
@@ -3341,7 +3316,7 @@ lnk_build_pdb(TP_Context *tp,
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi);
|
||||
lnk_build_pdb_public_symbols(tp, tp_arena, symtab, pdb->psi);
|
||||
|
||||
pdb_build(tp, tp_arena, pdb, string_ht);
|
||||
|
||||
@@ -4439,16 +4414,16 @@ lnk_type_from_itype(CV_TypeIndex itype, Rng1U64 tpi_itype_range, RDIB_Type **tpi
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_virt_off_from_sect_off(U64 sect_idx, U64 sect_off, LNK_SectionArray image_sects, LNK_Obj *obj, CV_SymKind symbol_kind, U64 symbol_offset)
|
||||
lnk_voff_from_sect_off(U64 sect_idx, U64 sect_off, LNK_SectionArray image_sects, LNK_Obj *obj, CV_SymKind symbol_kind, U64 symbol_offset)
|
||||
{
|
||||
U64 virt_off = 0;
|
||||
U64 voff = 0;
|
||||
if (sect_idx < image_sects.count) {
|
||||
virt_off = image_sects.v[sect_idx].virt_off + sect_off;
|
||||
voff = image_sects.v[sect_idx]->voff + sect_off;
|
||||
} else {
|
||||
lnk_error_obj(LNK_Error_CvIllSymbolData, obj, "Out of bounds section index 0x%x in S_%S @ 0x%llx.",
|
||||
sect_idx, cv_string_from_sym_kind(symbol_kind), symbol_offset);
|
||||
}
|
||||
return virt_off;
|
||||
return voff;
|
||||
}
|
||||
|
||||
internal Rng1U64
|
||||
@@ -4456,8 +4431,8 @@ lnk_virt_range_from_sect_off_size(U64 sect_idx, U64 sect_off, U64 size, LNK_Sect
|
||||
{
|
||||
Rng1U64 virt_range = {0};
|
||||
if (sect_idx < image_sects.count) {
|
||||
U64 virt_off = image_sects.v[sect_idx].virt_off + sect_off;
|
||||
virt_range = rng_1u64(virt_off, virt_off + size);
|
||||
U64 voff = image_sects.v[sect_idx]->voff + sect_off;
|
||||
virt_range = rng_1u64(voff, voff + size);
|
||||
} else {
|
||||
lnk_error_obj(LNK_Error_CvIllSymbolData, obj, "Out of bounds section index 0x%x in S_%S @ 0x%llx.",
|
||||
sect_idx, cv_string_from_sym_kind(symbol_kind), symbol_offset);
|
||||
@@ -4589,8 +4564,8 @@ THREAD_POOL_TASK_FUNC(lnk_convert_line_tables_to_rdi_task)
|
||||
lnk_error_obj(LNK_Warning_IllData, obj, "Out of bounds section index (%u) in $$LINES; skip line info for \"%S\".", parsed_lines.sec_idx, file_path);
|
||||
continue;
|
||||
}
|
||||
LNK_Section *sect = &task->image_sects.v[parsed_lines.sec_idx];
|
||||
CV_LineArray lines = cv_c13_line_array_from_data(arena, raw_lines, sect->virt_off, parsed_lines);
|
||||
LNK_Section *sect = task->image_sects.v[parsed_lines.sec_idx];
|
||||
CV_LineArray lines = cv_c13_line_array_from_data(arena, raw_lines, sect->voff, parsed_lines);
|
||||
|
||||
// find source file for this line table
|
||||
String8 normal_path = lnk_normalize_src_file_path(scratch.arena, file_path);
|
||||
@@ -4734,7 +4709,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task)
|
||||
String8 name = str8_cstring_capped(data32 + 1, symbol.data.str + symbol.data.size);
|
||||
RDIB_Type *type = lnk_type_from_itype(data32->itype, task->tpi_itype_range, task->tpi_itype_map, obj, symbol.kind, symbol.offset);
|
||||
RDIB_Type *container_type = lnk_find_container_type(name, task->tpi_itype_range, task->udt_name_buckets, task->udt_name_buckets_cap, task->tpi_itype_map);
|
||||
U64 data_voff = lnk_virt_off_from_sect_off(data32->sec, data32->off, task->image_sects, obj, symbol.kind, symbol.offset);
|
||||
U64 data_voff = lnk_voff_from_sect_off(data32->sec, data32->off, task->image_sects, obj, symbol.kind, symbol.offset);
|
||||
|
||||
B32 is_comp_gen = symbol.kind == CV_SymKind_LDATA32 && name.size == 0 && type == 0;
|
||||
if (!is_comp_gen) {
|
||||
@@ -5330,32 +5305,26 @@ THREAD_POOL_TASK_FUNC(lnk_collect_obj_virtual_ranges_task)
|
||||
|
||||
RDIB_Unit *dst = &task->units[unit_chunk_idx].v[local_unit_idx];
|
||||
dst->virt_range_count = 0;
|
||||
dst->virt_ranges = push_array_no_zero(arena, Rng1U64, obj->sect_count);
|
||||
dst->virt_ranges = push_array_no_zero(arena, Rng1U64, obj->header.section_count_no_null);
|
||||
|
||||
for (U64 chunk_idx = 0; chunk_idx < obj->sect_count; ++chunk_idx) {
|
||||
LNK_Chunk *chunk = obj->chunk_arr[chunk_idx];
|
||||
if (!chunk || lnk_chunk_is_discarded(chunk)) {
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
|
||||
|
||||
for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) {
|
||||
COFF_SectionHeader *sect_header = §ion_table[sect_idx];
|
||||
|
||||
if (sect_header->flags & COFF_SectionFlag_LnkRemove) {
|
||||
continue;
|
||||
}
|
||||
if (sect_header->vsize == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LNK_Section *sect = lnk_sect_from_chunk_ref(task->sect_id_map, chunk->ref);
|
||||
if (!sect->has_layout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
U64 chunk_voff = lnk_virt_off_from_chunk_ref(task->sect_id_map, chunk->ref);
|
||||
U64 chunk_size = lnk_virt_size_from_chunk_ref(task->sect_id_map, chunk->ref);
|
||||
|
||||
if (chunk_size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dst->virt_ranges[dst->virt_range_count] = rng_1u64(chunk_voff, chunk_voff + chunk_size);
|
||||
dst->virt_ranges[dst->virt_range_count] = rng_1u64(sect_header->voff, sect_header->voff + sect_header->vsize);
|
||||
++dst->virt_range_count;
|
||||
}
|
||||
|
||||
// free unused memory
|
||||
arena_pop(arena, sizeof(dst->virt_ranges[0]) * (obj->sect_count - dst->virt_range_count));
|
||||
arena_pop(arena, sizeof(dst->virt_ranges[0]) * (obj->header.section_count_no_null - dst->virt_range_count));
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
@@ -5368,7 +5337,6 @@ lnk_build_rad_debug_info(TP_Context *tp,
|
||||
String8 image_name,
|
||||
String8 image_data,
|
||||
LNK_SectionArray image_sects,
|
||||
LNK_Section **sect_id_map,
|
||||
U64 obj_count,
|
||||
LNK_Obj *obj_arr,
|
||||
CV_DebugS *debug_s_arr,
|
||||
@@ -5386,10 +5354,8 @@ lnk_build_rad_debug_info(TP_Context *tp,
|
||||
{
|
||||
U64 image_vsize = 0;
|
||||
for (U64 sect_idx = 0; sect_idx < image_sects.count; sect_idx++) {
|
||||
LNK_Section *sect = &image_sects.v[sect_idx];
|
||||
U64 sect_virt_size = lnk_virt_size_from_chunk_ref(sect_id_map, sect->root->ref);
|
||||
U64 sect_voff_max = sect->virt_off + sect_virt_size;
|
||||
image_vsize = Max(image_vsize, sect_voff_max);
|
||||
LNK_Section *sect = image_sects.v[sect_idx];
|
||||
image_vsize = Max(image_vsize, sect->voff + sect->vsize);
|
||||
}
|
||||
|
||||
input.top_level_info.arch = arch;
|
||||
@@ -5405,18 +5371,15 @@ lnk_build_rad_debug_info(TP_Context *tp,
|
||||
input.sect_count = image_sects.count;
|
||||
input.sections = push_array(scratch.arena, RDIB_BinarySection, image_sects.count);
|
||||
for (U64 sect_idx = 0; sect_idx < image_sects.count; ++sect_idx) {
|
||||
LNK_Section *src = &image_sects.v[sect_idx];
|
||||
LNK_Section *src = image_sects.v[sect_idx];
|
||||
RDIB_BinarySection *dst = &input.sections[sect_idx];
|
||||
|
||||
U64 sect_virt_size = lnk_virt_size_from_chunk_ref(sect_id_map, src->root->ref);
|
||||
U64 sect_file_size = lnk_file_size_from_chunk_ref(sect_id_map, src->root->ref);
|
||||
|
||||
dst->name = push_str8_copy(scratch.arena, src->name);
|
||||
dst->flags = rdi_binary_section_flags_from_coff_section_flags(src->flags);
|
||||
dst->voff_first = src->virt_off;
|
||||
dst->voff_opl = src->virt_off + sect_virt_size;
|
||||
dst->foff_first = src->file_off;
|
||||
dst->foff_opl = src->file_off + sect_file_size;
|
||||
dst->voff_first = src->voff;
|
||||
dst->voff_opl = src->voff + src->vsize;
|
||||
dst->foff_first = src->foff;
|
||||
dst->foff_opl = src->foff + src->fsize;
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
@@ -5551,7 +5514,6 @@ lnk_build_rad_debug_info(TP_Context *tp,
|
||||
{
|
||||
LNK_ConvertUnitToRDITask task = {0};
|
||||
task.image_sects = image_sects;
|
||||
task.sect_id_map = sect_id_map;
|
||||
task.obj_arr = obj_arr;
|
||||
task.debug_s_arr = debug_s_arr;
|
||||
task.ipi = types[CV_TypeIndexSource_IPI];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
@@ -122,9 +122,9 @@ typedef union
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_Obj **obj_arr;
|
||||
LNK_ChunkList *sect_list_arr;
|
||||
CV_DebugS *debug_s_arr;
|
||||
LNK_Obj **obj_arr;
|
||||
String8List *sect_list_arr;
|
||||
CV_DebugS *debug_s_arr;
|
||||
} LNK_ParseDebugSTaskData;
|
||||
|
||||
typedef struct
|
||||
@@ -313,10 +313,10 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
LNK_Obj *obj_arr;
|
||||
LNK_Section **sect_id_map;
|
||||
PDB_DbiModule **mod_arr;
|
||||
PDB_DbiSectionContribList *sc_list;
|
||||
String8 image_data;
|
||||
Rng1U64Array image_section_file_ranges;
|
||||
} LNK_PushDbiSecContribTaskData;
|
||||
|
||||
typedef struct
|
||||
@@ -334,7 +334,6 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_SymbolHashTrieChunkList *chunk_lists;
|
||||
CV_SymbolList *pub_list_arr;
|
||||
|
||||
@@ -454,7 +453,6 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
LNK_SectionArray image_sects;
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_Obj *obj_arr;
|
||||
CV_DebugS *debug_s_arr;
|
||||
CV_DebugT ipi;
|
||||
@@ -496,8 +494,8 @@ typedef struct
|
||||
////////////////////////////////
|
||||
// CodeView
|
||||
|
||||
internal CV_DebugS * lnk_parse_debug_s_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, LNK_ChunkList *sect_list_arr);
|
||||
internal CV_DebugT * lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, LNK_ChunkList *debug_t_list_arr);
|
||||
internal CV_DebugS * lnk_parse_debug_s_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *sect_list_arr);
|
||||
internal CV_DebugT * lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *debug_t_list_arr);
|
||||
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);
|
||||
|
||||
@@ -557,7 +555,6 @@ internal String8List lnk_build_rad_debug_info(TP_Context *tp,
|
||||
String8 image_name,
|
||||
String8 image_data,
|
||||
LNK_SectionArray image_sects,
|
||||
LNK_Section **sect_id_map,
|
||||
U64 obj_count,
|
||||
LNK_Obj *obj_arr,
|
||||
CV_DebugS *debug_s_arr,
|
||||
@@ -574,25 +571,13 @@ internal LNK_ProcessedCodeViewC13Data lnk_process_c13_data(TP_Context *tp, TP_Ar
|
||||
internal U64 * lnk_hash_cv_symbol_ptr_arr(TP_Context *tp, Arena *arena, CV_SymbolPtrArray arr);
|
||||
internal CV_SymbolPtrArray lnk_dedup_gsi_symbols(TP_Context *tp, Arena *arena, PDB_GsiContext *gsi, U64 obj_count, CV_SymbolList *symbol_list_arr);
|
||||
|
||||
internal void lnk_build_pdb_public_symbols(TP_Context *tp,
|
||||
TP_Arena *arena,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_Section **sect_id_map,
|
||||
PDB_PsiContext *psi);
|
||||
internal void lnk_build_pdb_public_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, PDB_PsiContext *psi);
|
||||
|
||||
internal String8List lnk_build_pdb(TP_Context *tp,
|
||||
TP_Arena *tp_arena,
|
||||
String8 image_data,
|
||||
Guid guid,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U32 age,
|
||||
U64 page_size,
|
||||
String8 pdb_name,
|
||||
String8List lib_dir_list,
|
||||
String8List natvis_list,
|
||||
LNK_Config *config,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_Section **sect_id_map,
|
||||
U64 obj_count,
|
||||
LNK_Obj *obj_arr,
|
||||
CV_DebugS *debug_s_arr,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
static LNK_ErrorMode g_error_mode_arr[LNK_Error_Count];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
@@ -32,13 +32,13 @@ typedef enum
|
||||
LNK_Error_IO,
|
||||
LNK_Error_LargeAddrAwareRequired,
|
||||
LNK_Error_InvalidPath,
|
||||
LNK_Error_MultiplyDefinedSymbol,
|
||||
LNK_Error_StopLast,
|
||||
|
||||
LNK_Error_First,
|
||||
LNK_Error_AlreadyDefinedSymbol,
|
||||
LNK_Error_AlternateNameConflict,
|
||||
LNK_Error_CvPrecomp,
|
||||
LNK_Error_MultiplyDefinedSymbol,
|
||||
LNK_Error_Natvis,
|
||||
LNK_Error_TooManyFiles,
|
||||
LNK_Error_UndefinedSymbol,
|
||||
@@ -48,6 +48,8 @@ typedef enum
|
||||
LNK_Error_CvIllSymbolData,
|
||||
LNK_Error_IllegalAlternateNameRedifine,
|
||||
LNK_Error_InvalidTypeIndex,
|
||||
LNK_Error_UndefinedIsWeak,
|
||||
LNK_Error_WeakCycle,
|
||||
LNK_Error_Last,
|
||||
|
||||
LNK_Warning_First,
|
||||
@@ -81,6 +83,7 @@ typedef enum
|
||||
LNK_Warning_UnknownSwitch,
|
||||
LNK_Warning_TLSAlign,
|
||||
LNK_Warning_DirectiveSectionWithRelocs,
|
||||
LNK_Warning_NoLargeAddressAwarenessForDll,
|
||||
LNK_Warning_Last,
|
||||
|
||||
LNK_Error_Count
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
int
|
||||
@@ -61,19 +61,16 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
|
||||
LNK_Export *exp = 0;
|
||||
|
||||
// get export symbol
|
||||
LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Main, exp_parse->name);
|
||||
LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, exp_parse->name);
|
||||
if (symbol == 0) {
|
||||
lnk_error(LNK_Warning_IllExport, "symbol \"%S\" for export doesn't exist", exp_parse->name);
|
||||
goto exit;
|
||||
}
|
||||
symbol = lnk_resolve_symbol(symtab, symbol);
|
||||
if (!LNK_Symbol_IsDefined(symbol->type)) {
|
||||
if (symbol->type != LNK_Symbol_Defined) {
|
||||
lnk_error(LNK_Warning_IllExport, "unable to resolve symbol \"%S\" for export", exp_parse->name);
|
||||
goto exit;
|
||||
}
|
||||
LNK_DefinedSymbol *def = &symbol->u.defined;
|
||||
|
||||
|
||||
// NOTE: It is possible to export a global variable as CODE
|
||||
// with following snippet:
|
||||
// int global_bar = 0;
|
||||
@@ -85,13 +82,15 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
|
||||
COFF_ImportType type = coff_import_header_type_from_string(exp_parse->type);
|
||||
switch (type) {
|
||||
case COFF_ImportHeader_Code: {
|
||||
B32 is_export_data = !(def->flags & (LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk));
|
||||
COFF_ParsedSymbol defn = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
B32 is_export_data = !COFF_SymbolType_IsFunc(defn.type);
|
||||
if (is_export_data) {
|
||||
lnk_error(LNK_Error_IllExport, "export \"%S\" is DATA but has specifier CODE", exp_parse->name);
|
||||
}
|
||||
} break;
|
||||
case COFF_ImportHeader_Data: {
|
||||
B32 is_export_code = !!(def->flags & (LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk));
|
||||
COFF_ParsedSymbol defn = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
B32 is_export_code = COFF_SymbolType_IsFunc(defn.type);
|
||||
if (is_export_code) {
|
||||
lnk_error(LNK_Error_IllExport, "export \"%S\" is CODE but has specifier DATA", exp_parse->name);
|
||||
}
|
||||
@@ -106,7 +105,6 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
// error check multiple def
|
||||
exp = lnk_export_table_search(exptab, exp_parse->alias);
|
||||
if (exp) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
@@ -7,7 +7,7 @@ typedef struct LNK_Export
|
||||
{
|
||||
struct LNK_Export *next;
|
||||
String8 name;
|
||||
LNK_Symbol *symbol;
|
||||
struct LNK_Symbol *symbol;
|
||||
U32 id;
|
||||
U16 ordinal;
|
||||
COFF_ImportType type;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal LNK_ImportTable *
|
||||
@@ -55,7 +55,7 @@ internal LNK_ImportFunc *
|
||||
lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name)
|
||||
{
|
||||
LNK_ImportFunc *func = 0;
|
||||
hash_table_search_string_raw(dll->func_ht, name, &func);
|
||||
hash_table_search_string_raw(dll->func_ht, name, (void **)&func);
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_ImportDLL *dll,
|
||||
switch (dll->machine) {
|
||||
case COFF_MachineType_X64: {
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
|
||||
LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main);
|
||||
LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScope_Main);
|
||||
|
||||
// emit jmp thunk chunk
|
||||
jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
lnk_string_from_input_source(LNK_InputSourceType input_source)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (input_source) {
|
||||
case LNK_InputSource_CmdLine: result = str8_lit("CmdLine"); break;
|
||||
case LNK_InputSource_Default: result = str8_lit("Default"); break;
|
||||
case LNK_InputSource_Obj: result = str8_lit("Obj"); break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
}
|
||||
|
||||
internal LNK_InputObj *
|
||||
lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list)
|
||||
{
|
||||
LNK_InputObj *node = push_array(arena, LNK_InputObj, 1);
|
||||
lnk_input_obj_list_push_node(list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal LNK_InputObj **
|
||||
lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list)
|
||||
{
|
||||
LNK_InputObj **result = push_array_no_zero(arena, LNK_InputObj *, list.count);
|
||||
U64 i = 0;
|
||||
for (LNK_InputObj *n = list.first; n != 0; n = n->next, ++i) {
|
||||
Assert(i < list.count);
|
||||
result[i] = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_input_obj_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const LNK_InputObj **a = (const LNK_InputObj **) raw_a;
|
||||
const LNK_InputObj **b = (const LNK_InputObj **) raw_b;
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_input_obj_compar_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_InputObj **a = raw_a;
|
||||
LNK_InputObj **b = raw_b;
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path);
|
||||
int is_before = cmp < 0;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal LNK_InputObjList
|
||||
lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count)
|
||||
{
|
||||
LNK_InputObjList list = {0};
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
SLLQueuePush(list.first, list.last, arr[i]);
|
||||
++list.count;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal LNK_InputObjList
|
||||
lnk_input_obj_list_from_string_list(Arena *arena, String8List list)
|
||||
{
|
||||
LNK_InputObjList input_list = {0};
|
||||
for (String8Node *path = list.first; path != 0; path = path->next) {
|
||||
LNK_InputObj *input = lnk_input_obj_list_push(arena, &input_list);
|
||||
input->is_thin = 1;
|
||||
input->dedup_id = path->string;
|
||||
input->path = path->string;
|
||||
}
|
||||
return input_list;
|
||||
}
|
||||
|
||||
internal LNK_InputImport *
|
||||
lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list)
|
||||
{
|
||||
LNK_InputImport *node = push_array(arena, LNK_InputImport, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal LNK_InputImport **
|
||||
lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list)
|
||||
{
|
||||
LNK_InputImport **result = push_array_no_zero(arena, LNK_InputImport *, list.count);
|
||||
U64 idx = 0;
|
||||
for (LNK_InputImport *node = list.first; node != 0; node = node->next) {
|
||||
Assert(idx < list.count);
|
||||
result[idx++] = node;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal LNK_InputImportList
|
||||
lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count)
|
||||
{
|
||||
LNK_InputImportList list = {0};
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
SLLQueuePush(list.first, list.last, arr[i]);
|
||||
list.count += 1;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
int
|
||||
lnk_input_import_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_InputImport **a = raw_a;
|
||||
LNK_InputImport **b = raw_b;
|
||||
int cmp = str8_compar_ignore_case(&(*a)->import_header.dll_name, &(*b)->import_header.dll_name);
|
||||
if (cmp == 0) {
|
||||
cmp = str8_compar_case_sensitive(&(*a)->import_header.func_name, &(*b)->import_header.func_name);
|
||||
}
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
int
|
||||
lnk_input_import_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
LNK_InputImport * const *a = raw_a;
|
||||
LNK_InputImport * const *b = raw_b;
|
||||
int cmp = str8_compar_ignore_case(&(*a)->import_header.dll_name, &(*b)->import_header.dll_name);
|
||||
if (cmp == 0) {
|
||||
cmp = str8_compar_case_sensitive(&(*a)->import_header.func_name, &(*b)->import_header.func_name);
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_InputSource_CmdLine, // specified on command line
|
||||
LNK_InputSource_Default, // specified through defaultlib switch
|
||||
LNK_InputSource_Obj, // refrenced from objects
|
||||
LNK_InputSource_Count
|
||||
} LNK_InputSourceType;
|
||||
|
||||
typedef String8Node LNK_InputLib;
|
||||
typedef String8List LNK_InputLibList;
|
||||
|
||||
typedef struct LNK_InputImport
|
||||
{
|
||||
COFF_ParsedArchiveImportHeader import_header;
|
||||
struct LNK_InputImport *next;
|
||||
} LNK_InputImport;
|
||||
|
||||
typedef struct LNK_InputImportList
|
||||
{
|
||||
U64 count;
|
||||
LNK_InputImport *first;
|
||||
LNK_InputImport *last;
|
||||
} LNK_InputImportList;
|
||||
|
||||
typedef struct LNK_InputObj
|
||||
{
|
||||
struct LNK_InputObj *next;
|
||||
B32 is_thin;
|
||||
B32 has_disk_read_failed;
|
||||
String8 dedup_id;
|
||||
String8 path;
|
||||
String8 data;
|
||||
String8 lib_path;
|
||||
} LNK_InputObj;
|
||||
|
||||
typedef struct LNK_InputObjList
|
||||
{
|
||||
U64 count;
|
||||
LNK_InputObj *first;
|
||||
LNK_InputObj *last;
|
||||
} LNK_InputObjList;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source);
|
||||
|
||||
internal void lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node);
|
||||
internal LNK_InputObj * lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list);
|
||||
internal void lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat);
|
||||
|
||||
internal LNK_InputObj ** lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list);
|
||||
internal LNK_InputObjList lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count);
|
||||
internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list);
|
||||
|
||||
internal LNK_InputImport * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list);
|
||||
internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat);
|
||||
internal LNK_InputImport ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list);
|
||||
internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count);
|
||||
|
||||
+56
-39
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal LNK_LibNode *
|
||||
@@ -208,31 +208,6 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S
|
||||
return arr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
internal LNK_LibNode *
|
||||
lnk_lib_list_push(Arena *arena, LNK_LibList *list, String8 data, String8 path)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
TP_Arena pool_arena = {0};
|
||||
pool_arena.count = 1;
|
||||
pool_arena.v = &arena;
|
||||
|
||||
String8Array data_arr = {0};
|
||||
data_arr.count = 1;
|
||||
data_arr.v = &data;
|
||||
|
||||
String8Array path_arr = {0};
|
||||
path_arr.count = 1;
|
||||
path_arr.v = &path;
|
||||
|
||||
LNK_LibNodeArray node_arr = lnk_lib_list_push_parallel(&pool_arena, list, data_arr, path_arr);
|
||||
|
||||
ProfEnd();
|
||||
return node_arr.v;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_LibWriter *
|
||||
@@ -265,14 +240,31 @@ lnk_lib_writer_push_obj(LNK_LibWriter *writer, LNK_Obj *obj)
|
||||
lnk_lib_member_list_push(writer->arena, &writer->member_list, member);
|
||||
|
||||
// push external symbols
|
||||
for (LNK_SymbolNode *node = obj->symbol_list.first; node != 0; node = node->next) {
|
||||
LNK_Symbol *symbol = node->data;
|
||||
B32 is_extern = symbol->type == LNK_Symbol_DefinedExtern;
|
||||
if (is_extern) {
|
||||
LNK_LibSymbol lib_symbol = {0};
|
||||
lib_symbol.name = symbol->name;
|
||||
lib_symbol.member_idx = member_idx;
|
||||
lnk_lib_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol);
|
||||
{
|
||||
COFF_FileHeaderInfo coff_info = coff_file_header_info_from_data(obj->data);
|
||||
String8 string_table = str8_substr(obj->data, coff_info.string_table_range);
|
||||
String8 symbol_table = str8_substr(obj->data, coff_info.symbol_table_range);
|
||||
|
||||
COFF_ParsedSymbol symbol;
|
||||
for (U64 symbol_idx = 0; symbol_idx < coff_info.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
|
||||
void *symbol_ptr;
|
||||
if (coff_info.is_big_obj) {
|
||||
symbol_ptr = &((COFF_Symbol32 *)symbol_table.str)[symbol_idx];
|
||||
symbol = coff_parse_symbol32(string_table, symbol_ptr);
|
||||
} else {
|
||||
symbol_ptr = &((COFF_Symbol16 *)symbol_table.str)[symbol_idx];
|
||||
symbol = coff_parse_symbol16(string_table, symbol_ptr);
|
||||
}
|
||||
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Regular) {
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_LibSymbol lib_symbol = {0};
|
||||
lib_symbol.name = symbol.name;
|
||||
lib_symbol.member_idx = member_idx;
|
||||
lnk_lib_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,20 +582,45 @@ lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine,
|
||||
input->lib_path = lib_name;
|
||||
}
|
||||
|
||||
LNK_InputObj **inputs = lnk_array_from_input_obj_list(scratch.arena, input_obj_list);
|
||||
LNK_SectionTable *sectab = lnk_section_table_alloc(0,0,0);
|
||||
LNK_ObjList obj_list = {0};
|
||||
lnk_obj_list_push_parallel(tp, arena, &obj_list, sectab, 0, machine, input_obj_list.count, inputs);
|
||||
LNK_InputObj **inputs = lnk_array_from_input_obj_list(scratch.arena, input_obj_list);
|
||||
LNK_ObjList obj_list = {0};
|
||||
lnk_obj_list_push_parallel(tp, arena, &obj_list, machine, input_obj_list.count, inputs);
|
||||
|
||||
LNK_LibBuild import_lib = lnk_build_lib(scratch.arena, machine, time_stamp, dll_name, obj_list, exptab);
|
||||
B32 emit_second_member = 1;
|
||||
String8List coff_archive_data = lnk_coff_archive_from_lib_build(arena->v[0], &import_lib, emit_second_member, COFF_TimeStamp_Max, 0);
|
||||
|
||||
// cleanup memory
|
||||
lnk_section_table_release(§ab);
|
||||
scratch_end(scratch);
|
||||
|
||||
ProfEnd();
|
||||
return coff_archive_data;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task)
|
||||
{
|
||||
LNK_SymbolPusher *task = raw_task;
|
||||
LNK_SymbolTable *symtab = task->symtab;
|
||||
LNK_Lib *lib = &task->u.libs.v[task_id].data;
|
||||
|
||||
String8Node *name_node = lib->symbol_name_list.first;
|
||||
for (U64 symbol_idx = 0; symbol_idx < lib->symbol_count; ++symbol_idx, name_node = name_node->next) {
|
||||
LNK_Symbol *symbol = lnk_make_lib_symbol(arena, name_node->string, lib, lib->member_off_arr[symbol_idx]);
|
||||
|
||||
U64 hash = lnk_symbol_hash(symbol->name);
|
||||
lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, hash, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_input_lib_symbols(TP_Context *tp, LNK_SymbolTable *symtab, LNK_LibNodeArray libs)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
LNK_SymbolPusher task = {0};
|
||||
task.symtab = symtab;
|
||||
task.u.libs = libs;
|
||||
tp_for_parallel(tp, symtab->arena, libs.count, lnk_push_lib_symbols_task, &task);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
@@ -114,7 +114,6 @@ internal void lnk_lib_symbol_array_sort(LNK_LibSymbol *arr, U64 count
|
||||
internal LNK_Lib lnk_lib_from_data(Arena *arena, String8 data, String8 path);
|
||||
|
||||
internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr);
|
||||
internal LNK_LibNode * lnk_lib_list_push(Arena *arena, LNK_LibList *list, String8 data, String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
+273
-962
File diff suppressed because it is too large
Load Diff
+55
-147
@@ -1,27 +1,37 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct LNK_InputObj
|
||||
typedef struct LNK_Obj
|
||||
{
|
||||
struct LNK_InputObj *next;
|
||||
B32 is_thin;
|
||||
B32 has_disk_read_failed;
|
||||
String8 dedup_id;
|
||||
String8 path;
|
||||
String8 data;
|
||||
String8 lib_path;
|
||||
} LNK_InputObj;
|
||||
String8 data;
|
||||
String8 path;
|
||||
String8 lib_path;
|
||||
U64 input_idx;
|
||||
COFF_FileHeaderInfo header;
|
||||
} LNK_Obj;
|
||||
|
||||
typedef struct LNK_InputObjList
|
||||
typedef struct LNK_ObjNode
|
||||
{
|
||||
U64 count;
|
||||
LNK_InputObj *first;
|
||||
LNK_InputObj *last;
|
||||
} LNK_InputObjList;
|
||||
struct LNK_ObjNode *next;
|
||||
LNK_Obj data;
|
||||
} LNK_ObjNode;
|
||||
|
||||
typedef struct LNK_ObjList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ObjNode *first;
|
||||
LNK_ObjNode *last;
|
||||
} LNK_ObjList;
|
||||
|
||||
typedef struct LNK_ObjNodeArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ObjNode *v;
|
||||
} LNK_ObjNodeArray;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -46,133 +56,29 @@ typedef struct LNK_DirectiveInfo
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define LNK_MakeChunkInputIdx(obj_idx, sect_idx) (((U64)(obj_idx) << 32) | (U64)((sect_idx) & max_U32))
|
||||
|
||||
typedef struct LNK_Obj
|
||||
typedef struct LNK_SymbolInputResult
|
||||
{
|
||||
String8 data;
|
||||
String8 path;
|
||||
String8 lib_path;
|
||||
U64 input_idx;
|
||||
COFF_MachineType machine;
|
||||
U64 chunk_count;
|
||||
U64 sect_count;
|
||||
String8 *sect_name_arr;
|
||||
String8 *sect_sort_arr;
|
||||
LNK_RelocList *sect_reloc_list_arr;
|
||||
LNK_ChunkPtr *chunk_arr;
|
||||
LNK_SymbolList symbol_list;
|
||||
} LNK_Obj;
|
||||
|
||||
typedef struct LNK_ObjNode
|
||||
{
|
||||
struct LNK_ObjNode *next;
|
||||
LNK_Obj data;
|
||||
} LNK_ObjNode;
|
||||
|
||||
typedef struct LNK_ObjList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ObjNode *first;
|
||||
LNK_ObjNode *last;
|
||||
} LNK_ObjList;
|
||||
|
||||
typedef struct LNK_ObjNodeArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ObjNode *v;
|
||||
} LNK_ObjNodeArray;
|
||||
LNK_SymbolList weak_symbols;
|
||||
LNK_SymbolList undef_symbols;
|
||||
} LNK_SymbolInputResult;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct LNK_SectDefn
|
||||
{
|
||||
struct LNK_SectDefn *next;
|
||||
LNK_Obj *obj;
|
||||
String8 name;
|
||||
COFF_SectionFlags flags;
|
||||
U64 idx;
|
||||
} LNK_SectDefn;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 count;
|
||||
LNK_SectDefn *first;
|
||||
LNK_SectDefn *last;
|
||||
} LNK_SectDefnList;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_InputObj **inputs;
|
||||
LNK_ObjNode *obj_node_arr;
|
||||
LNK_ObjNodeArray objs;
|
||||
U64 obj_id_base;
|
||||
LNK_SectDefnList *defn_arr;
|
||||
LNK_SectionTable *sectab;
|
||||
U64 *function_pad_min;
|
||||
U32 machine;
|
||||
} LNK_ObjIniter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rng1U64 *range_arr;
|
||||
LNK_ObjNode *obj_node_arr;
|
||||
LNK_SectDefnList *defn_arr;
|
||||
LNK_SectDefnList *conf_arr;
|
||||
} LNK_ObjNewSectScanner;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SectionTable *sectab;
|
||||
LNK_ObjNode *obj_arr;
|
||||
U64 **chunk_counts;
|
||||
} LNK_ChunkCounter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_ChunkManager *cman;
|
||||
U64 *chunk_id;
|
||||
} LNK_ChunkRefAssign;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SectionTable *sectab;
|
||||
Rng1U64 *range_arr;
|
||||
U64 **chunk_ids;
|
||||
LNK_ObjNode *obj_arr;
|
||||
LNK_ChunkList **nosort_chunk_list_arr_arr;
|
||||
LNK_ChunkList **chunk_list_arr_arr;
|
||||
} LNK_ChunkRefAssigner;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolType type;
|
||||
LNK_ObjNodeArray in_arr;
|
||||
LNK_SymbolList *out_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_SymbolCollector;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_Obj **obj_arr;
|
||||
String8 name;
|
||||
String8 postfix;
|
||||
B32 collect_discarded;
|
||||
LNK_ChunkList *list_arr;
|
||||
} LNK_CollectObjChunksTaskData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rng1U64 *range_arr;
|
||||
LNK_ObjNodeArray in_arr;
|
||||
String8List *out_arr;
|
||||
} LNK_DefaultLibCollector;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_ObjNode *in_arr;
|
||||
String8List *out_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_ManifestDependencyCollector;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_ObjNodeArray objs;
|
||||
LNK_SymbolList *weak_lists;
|
||||
LNK_SymbolList *undef_lists;
|
||||
} LNK_InputCoffSymbolTable;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -180,29 +86,31 @@ internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node);
|
||||
internal void lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat);
|
||||
internal LNK_InputObj * lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list);
|
||||
internal LNK_InputObj ** lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list);
|
||||
internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list);
|
||||
internal LNK_InputObjList lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list);
|
||||
|
||||
internal LNK_Obj ** lnk_obj_arr_from_list(Arena *arena, LNK_ObjList list);
|
||||
internal LNK_ObjNodeArray lnk_obj_list_reserve(Arena *arena, LNK_ObjList *list, U64 count);
|
||||
internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8 name, String8 postfix, B32 collect_discarded);
|
||||
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *sectab, U64 *function_pad_min, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs);
|
||||
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs);
|
||||
|
||||
internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr);
|
||||
internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, LNK_Obj *obj, String8 obj_path, String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 sect_count, COFF_SectionHeader *section_table, U64 symbol_count, void *symbol_table, String8 string_table, LNK_ChunkPtr *chunk_table, LNK_Chunk *master_common_block);
|
||||
internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count);
|
||||
internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array);
|
||||
internal LNK_DirectiveInfo lnk_directive_info_from_sections(Arena *arena, String8 obj_path, String8 lib_path, U64 chunk_count, LNK_RelocList *reloc_list_arr, String8 *sect_name_arr, LNK_Chunk *chunk_arr);
|
||||
internal LNK_Obj ** lnk_obj_arr_from_list(Arena *arena, LNK_ObjList list);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U32 lnk_obj_get_features(LNK_Obj *obj);
|
||||
internal U32 lnk_obj_get_comp_id(LNK_Obj *obj);
|
||||
internal U32 lnk_obj_get_vol_md(LNK_Obj *obj);
|
||||
|
||||
internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff(LNK_Obj *obj, void *coff_symbol);
|
||||
internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal String8List * lnk_collect_obj_chunks_parallel(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8 name, String8 postfix, B32 collect_discarded);
|
||||
internal String8List lnk_collect_obj_chunks(Arena *arena, LNK_Obj *obj, String8 name, String8 postfix, B32 collect_discarded);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_parse_msvc_linker_directive(Arena *arena, LNK_Obj *obj, LNK_DirectiveInfo *directive_info, String8 buffer);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_SymbolList lnk_run_symbol_collector(TP_Context *tp, TP_Arena *arena, LNK_ObjNodeArray arr, LNK_SymbolType symbol_type);
|
||||
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal LNK_Reloc *
|
||||
lnk_reloc_list_reserve(Arena *arena, LNK_RelocList *list, U64 count)
|
||||
{
|
||||
LNK_Reloc *arr = NULL;
|
||||
if (count) {
|
||||
arr = push_array(arena, LNK_Reloc, count);
|
||||
for (LNK_Reloc *ptr = arr, *opl = arr + count; ptr < opl; ++ptr) {
|
||||
SLLQueuePush(list->first, list->last, ptr);
|
||||
}
|
||||
list->count += count;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal LNK_Reloc *
|
||||
lnk_reloc_list_push(Arena *arena, LNK_RelocList *list)
|
||||
{
|
||||
LNK_Reloc *node = push_array(arena, LNK_Reloc, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal LNK_RelocList
|
||||
lnk_reloc_list_copy(Arena *arena, LNK_RelocList *list)
|
||||
{
|
||||
LNK_RelocList result = {0};
|
||||
for (LNK_Reloc *n = list->first; n != NULL; n = n->next) {
|
||||
LNK_Reloc *r = lnk_reloc_list_push(arena, &result);
|
||||
r->chunk = n->chunk;
|
||||
r->type = n->type;
|
||||
r->apply_off = n->apply_off;
|
||||
r->symbol = n->symbol;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_reloc_list_concat_in_place(LNK_RelocList *list, LNK_RelocList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_reloc_list_concat_in_place_arr(LNK_RelocList *list, LNK_RelocList *arr, U64 count)
|
||||
{
|
||||
SLLConcatInPlaceArray(list, arr, count);
|
||||
}
|
||||
|
||||
internal LNK_RelocList **
|
||||
lnk_make_reloc_list_arr_arr(Arena *arena, U64 slot_count, U64 per_count)
|
||||
{
|
||||
LNK_RelocList **arr_arr = push_array_no_zero(arena, LNK_RelocList *, slot_count);
|
||||
for (U64 i = 0; i < slot_count; i += 1) {
|
||||
arr_arr[i] = push_array(arena, LNK_RelocList, per_count);
|
||||
}
|
||||
return arr_arr;
|
||||
}
|
||||
|
||||
internal LNK_RelocList
|
||||
lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count)
|
||||
{
|
||||
LNK_RelocList reloc_list = {0};
|
||||
|
||||
LNK_Reloc *reloc_arr = lnk_reloc_list_reserve(arena, &reloc_list, reloc_count);
|
||||
LNK_Reloc *reloc_ptr = reloc_arr;
|
||||
LNK_Reloc *reloc_opl = reloc_arr + reloc_count;
|
||||
COFF_Reloc *coff_reloc_ptr = reloc_v;
|
||||
|
||||
for (; reloc_ptr < reloc_opl; ++reloc_ptr, ++coff_reloc_ptr) {
|
||||
LNK_RelocType type = lnk_ext_reloc_type_from_coff(machine, coff_reloc_ptr->type);
|
||||
LNK_Chunk *reloc_chunk = chunk;
|
||||
U64 apply_off = coff_reloc_ptr->apply_off;
|
||||
LNK_Symbol *symbol = symbol_array.v + coff_reloc_ptr->isymbol;
|
||||
|
||||
if (chunk->type == LNK_Chunk_List) {
|
||||
reloc_chunk = chunk->u.list->last->data;
|
||||
U64 cursor = 0;
|
||||
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
|
||||
Assert(c->data->type == LNK_Chunk_Leaf);
|
||||
if (coff_reloc_ptr->apply_off < cursor + c->data->u.leaf.size) {
|
||||
reloc_chunk = c->data;
|
||||
break;
|
||||
}
|
||||
cursor += c->data->u.leaf.size;
|
||||
}
|
||||
apply_off = coff_reloc_ptr->apply_off - cursor;
|
||||
}
|
||||
|
||||
Assert(reloc_chunk->type == LNK_Chunk_Leaf);
|
||||
Assert(coff_reloc_ptr->isymbol < symbol_array.count);
|
||||
reloc_ptr->chunk = reloc_chunk;
|
||||
reloc_ptr->type = type;
|
||||
reloc_ptr->apply_off = apply_off;
|
||||
reloc_ptr->symbol = symbol;
|
||||
}
|
||||
return reloc_list;
|
||||
}
|
||||
|
||||
internal LNK_Reloc **
|
||||
lnk_reloc_array_from_list(Arena *arena, LNK_RelocList list)
|
||||
{
|
||||
LNK_Reloc **arr = push_array_no_zero(arena, LNK_Reloc *, list.count);
|
||||
U64 count = 0;
|
||||
for (LNK_Reloc *node = list.first; node != 0; node = node->next) {
|
||||
Assert(count < list.count);
|
||||
arr[count++] = node;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal LNK_RelocType
|
||||
lnk_ext_reloc_type_from_coff(COFF_MachineType machine, U32 type)
|
||||
{
|
||||
LNK_RelocType result = LNK_Reloc_NULL;
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: {
|
||||
switch (type) {
|
||||
case COFF_Reloc_X64_Abs: result = LNK_Reloc_NULL; break;
|
||||
case COFF_Reloc_X64_Addr64: result = LNK_Reloc_ADDR_64; break;
|
||||
case COFF_Reloc_X64_Addr32: result = LNK_Reloc_ADDR_32; break;
|
||||
case COFF_Reloc_X64_Addr32Nb: result = LNK_Reloc_VIRT_OFF_32; break;
|
||||
case COFF_Reloc_X64_Rel32: result = LNK_Reloc_REL32; break;
|
||||
case COFF_Reloc_X64_Rel32_1: result = LNK_Reloc_REL32_1; break;
|
||||
case COFF_Reloc_X64_Rel32_2: result = LNK_Reloc_REL32_2; break;
|
||||
case COFF_Reloc_X64_Rel32_3: result = LNK_Reloc_REL32_3; break;
|
||||
case COFF_Reloc_X64_Rel32_4: result = LNK_Reloc_REL32_4; break;
|
||||
case COFF_Reloc_X64_Rel32_5: result = LNK_Reloc_REL32_5; break;
|
||||
case COFF_Reloc_X64_Section: result = LNK_Reloc_SECT_IDX; break;
|
||||
case COFF_Reloc_X64_SecRel: result = LNK_Reloc_SECT_REL; break;
|
||||
case COFF_Reloc_X64_SecRel7: lnk_not_implemented("TODO: COFF_Reloc_X64_SecRel7"); break;
|
||||
case COFF_Reloc_X64_Token: lnk_not_implemented("TODO: COFF_Reloc_X64_Token"); break;
|
||||
case COFF_Reloc_X64_SRel32: lnk_not_implemented("TODO: COFF_Reloc_X64_SRel32"); break;
|
||||
case COFF_Reloc_X64_Pair: lnk_not_implemented("TODO: COFF_Reloc_X64_Pair"); break;
|
||||
case COFF_Reloc_X64_SSpan32: lnk_not_implemented("TODO: COFF_Reloc_X64_SSpan32"); break;
|
||||
default: lnk_invalid_path("unknown relocation type 0x%X", type);
|
||||
}
|
||||
} break;
|
||||
default: lnk_not_implemented("TODO: define remap for coff reloc types"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32
|
||||
lnk_ext_reloc_type_to_coff(COFF_MachineType machine, LNK_RelocType type)
|
||||
{
|
||||
U32 result = 0;
|
||||
switch (machine) {
|
||||
case COFF_MachineType_X64: {
|
||||
switch (type) {
|
||||
case LNK_Reloc_NULL: result = COFF_Reloc_X64_Abs; break;
|
||||
case LNK_Reloc_ADDR_64: result = COFF_Reloc_X64_Addr64; break;
|
||||
case LNK_Reloc_ADDR_32: result = COFF_Reloc_X64_Addr32; break;
|
||||
case LNK_Reloc_VIRT_OFF_32: result = COFF_Reloc_X64_Addr32Nb; break;
|
||||
case LNK_Reloc_REL32: result = COFF_Reloc_X64_Rel32; break;
|
||||
case LNK_Reloc_REL32_1: result = COFF_Reloc_X64_Rel32_1; break;
|
||||
case LNK_Reloc_REL32_2: result = COFF_Reloc_X64_Rel32_2; break;
|
||||
case LNK_Reloc_REL32_3: result = COFF_Reloc_X64_Rel32_3; break;
|
||||
case LNK_Reloc_REL32_4: result = COFF_Reloc_X64_Rel32_4; break;
|
||||
case LNK_Reloc_REL32_5: result = COFF_Reloc_X64_Rel32_5; break;
|
||||
case LNK_Reloc_SECT_IDX: result = COFF_Reloc_X64_Section; break;
|
||||
case LNK_Reloc_SECT_REL: result = COFF_Reloc_X64_SecRel; break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
} break;
|
||||
default: lnk_not_implemented("TODO: support for machine 0x%X", machine); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_Reloc_NULL,
|
||||
LNK_Reloc_ADDR_16,
|
||||
LNK_Reloc_ADDR_32,
|
||||
LNK_Reloc_ADDR_64,
|
||||
LNK_Reloc_CHUNK_SIZE_FILE_16,
|
||||
LNK_Reloc_CHUNK_SIZE_FILE_32,
|
||||
LNK_Reloc_CHUNK_SIZE_VIRT_32,
|
||||
LNK_Reloc_FILE_ALIGN_32,
|
||||
LNK_Reloc_FILE_OFF_15,
|
||||
LNK_Reloc_FILE_OFF_32,
|
||||
LNK_Reloc_FILE_OFF_64,
|
||||
LNK_Reloc_REL32,
|
||||
LNK_Reloc_REL32_1,
|
||||
LNK_Reloc_REL32_2,
|
||||
LNK_Reloc_REL32_3,
|
||||
LNK_Reloc_REL32_4,
|
||||
LNK_Reloc_REL32_5,
|
||||
LNK_Reloc_SECT_REL,
|
||||
LNK_Reloc_SECT_IDX,
|
||||
LNK_Reloc_VIRT_ALIGN_32,
|
||||
LNK_Reloc_VIRT_OFF_32,
|
||||
} LNK_RelocType;
|
||||
|
||||
typedef struct LNK_Reloc
|
||||
{
|
||||
struct LNK_Reloc *next;
|
||||
LNK_Chunk *chunk;
|
||||
LNK_RelocType type;
|
||||
U64 apply_off;
|
||||
struct LNK_Symbol *symbol;
|
||||
} LNK_Reloc;
|
||||
|
||||
typedef struct LNK_RelocList
|
||||
{
|
||||
U64 count;
|
||||
LNK_Reloc *first;
|
||||
LNK_Reloc *last;
|
||||
} LNK_RelocList;
|
||||
|
||||
internal LNK_Reloc * lnk_reloc_list_reserve(Arena *arena, LNK_RelocList *list, U64 count);
|
||||
internal LNK_Reloc * lnk_reloc_list_push(Arena *arena, LNK_RelocList *list);
|
||||
internal LNK_RelocList lnk_reloc_list_copy(Arena *arena, LNK_RelocList *list);
|
||||
internal void lnk_reloc_list_concat_in_place(LNK_RelocList *list, LNK_RelocList *to_concat);
|
||||
internal void lnk_reloc_list_concat_in_place_arr(LNK_RelocList *list, LNK_RelocList *arr, U64 count);
|
||||
internal LNK_RelocList ** lnk_make_reloc_list_arr_arr(Arena *arena, U64 slot_count, U64 per_count);
|
||||
internal LNK_Reloc ** lnk_reloc_array_from_list(Arena *arena, LNK_RelocList list);
|
||||
internal LNK_RelocType lnk_ext_reloc_type_from_coff(COFF_MachineType machine, U32 type);
|
||||
internal U32 lnk_ext_reloc_type_to_coff(COFF_MachineType machine, LNK_RelocType type);
|
||||
|
||||
+230
-771
File diff suppressed because it is too large
Load Diff
+81
-105
@@ -1,43 +1,84 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct LNK_SectionContrib
|
||||
{
|
||||
U16 align;
|
||||
union {
|
||||
String8Node *data_list;
|
||||
U64 bss_size;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
U16 sort_idx_size;
|
||||
U32 obj_idx;
|
||||
U8 *sort_idx;
|
||||
};
|
||||
struct {
|
||||
U16 sect_idx;
|
||||
U32 off;
|
||||
U32 size;
|
||||
};
|
||||
} u;
|
||||
} LNK_SectionContrib;
|
||||
|
||||
typedef struct LNK_CommonBlockContrib
|
||||
{
|
||||
struct LNK_Symbol *symbol;
|
||||
union {
|
||||
U32 size;
|
||||
U32 offset;
|
||||
} u;
|
||||
} LNK_CommonBlockContrib;
|
||||
|
||||
typedef struct LNK_SectionContribChunk
|
||||
{
|
||||
struct LNK_SectionContribChunk *next;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
LNK_SectionContrib *v;
|
||||
} LNK_SectionContribChunk;
|
||||
|
||||
typedef struct LNK_SectionContribChunkList
|
||||
{
|
||||
U64 chunk_count;
|
||||
LNK_SectionContribChunk *first;
|
||||
LNK_SectionContribChunk *last;
|
||||
} LNK_SectionContribChunkList;
|
||||
|
||||
typedef struct LNK_SectionDefinition
|
||||
{
|
||||
String8 name;
|
||||
COFF_SectionFlags flags;
|
||||
U64 contribs_count;
|
||||
struct LNK_Obj *obj;
|
||||
U64 obj_sect_idx;
|
||||
} LNK_SectionDefinition;
|
||||
|
||||
typedef struct LNK_Section
|
||||
{
|
||||
Arena *arena;
|
||||
U64 id;
|
||||
String8 name;
|
||||
String8 symbol_name;
|
||||
COFF_SectionFlags flags;
|
||||
String8 sort_index;
|
||||
Arena *arena;
|
||||
U64 id;
|
||||
String8 name;
|
||||
COFF_SectionFlags flags;
|
||||
B32 has_layout;
|
||||
B32 is_merged;
|
||||
|
||||
LNK_ChunkManager *cman;
|
||||
LNK_Chunk *root;
|
||||
LNK_SectionContribChunkList contribs;
|
||||
|
||||
// overwhelming number of chunks don't have sort index and grouping
|
||||
// them speeds up sort step
|
||||
LNK_Chunk *nosort_chunk;
|
||||
|
||||
LNK_RelocList reloc_list;
|
||||
|
||||
B32 emit_header; // TODO: this is a hack to make reloc serializer work in resource converter
|
||||
B32 has_layout;
|
||||
B32 is_loose;
|
||||
|
||||
B32 is_merged;
|
||||
U64 merge_sect_id;
|
||||
U64 *id_map;
|
||||
|
||||
U64 isect;
|
||||
U64 virt_off;
|
||||
U64 file_off;
|
||||
LNK_ChunkLayout layout;
|
||||
U64 voff;
|
||||
U64 vsize;
|
||||
U64 fsize;
|
||||
U64 foff;
|
||||
U64 sect_idx;
|
||||
} LNK_Section;
|
||||
|
||||
typedef struct LNK_SectionNode
|
||||
{
|
||||
struct LNK_SectionNode *next;
|
||||
struct LNK_SectionNode *prev;
|
||||
LNK_Section data;
|
||||
} LNK_SectionNode;
|
||||
|
||||
@@ -49,103 +90,38 @@ typedef struct LNK_SectionList
|
||||
} LNK_SectionList;
|
||||
|
||||
typedef struct LNK_SectionArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_Section *v;
|
||||
} LNK_SectionArray;
|
||||
|
||||
typedef struct LNK_SectionPtrArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_Section **v;
|
||||
} LNK_SectionPtrArray;
|
||||
} LNK_SectionArray;
|
||||
|
||||
typedef struct LNK_SectionTable
|
||||
{
|
||||
Arena *arena;
|
||||
U64 section_virt_off;
|
||||
U64 sect_align;
|
||||
U64 file_align;
|
||||
U64 id_max;
|
||||
U64 next_sect_idx;
|
||||
LNK_SectionList list;
|
||||
LNK_SectionList merge_list;
|
||||
LNK_SectionList empties_list;
|
||||
LNK_SectionNode *null_sect;
|
||||
LNK_SectionList free_list;
|
||||
HashTable *sect_ht; // name -> LNK_Section *
|
||||
} LNK_SectionTable;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COFF_MachineType machine;
|
||||
Rng1U64 *range_arr;
|
||||
LNK_Section **sect_arr;
|
||||
} LNK_SectionDataBuilder;
|
||||
internal U8 lnk_code_align_byte_from_machine(COFF_MachineType machine);
|
||||
internal U16 lnk_default_align_from_machine(COFF_MachineType machine);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_SectionNode * lnk_section_list_remove(LNK_SectionList *list, String8 name);
|
||||
internal LNK_SectionNode * lnk_section_list_search_node(LNK_SectionList *list, String8 name);
|
||||
internal LNK_Section * lnk_section_list_search(LNK_SectionList *list, String8 name);
|
||||
internal void lnk_section_list_remove(LNK_SectionList *list, LNK_SectionNode *node);
|
||||
internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionList list);
|
||||
|
||||
internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionList list);
|
||||
internal LNK_SectionPtrArray lnk_section_ptr_array_from_list(Arena *arena, LNK_SectionList list);
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_section_associate_chunks(LNK_Section *sect, LNK_Chunk *head, LNK_Chunk *associate);
|
||||
|
||||
internal LNK_Reloc * lnk_section_push_reloc(LNK_Section *sect, LNK_Chunk *chunk, LNK_RelocType type, U64 apply_off, LNK_Symbol *symbol);
|
||||
internal LNK_Reloc * lnk_section_push_reloc_undefined(LNK_Section *sect, LNK_Chunk *chunk, LNK_RelocType type, U64 apply_off, String8 undefined_symbol_name, LNK_SymbolScopeFlags scope_flags);
|
||||
|
||||
internal void lnk_section_merge(LNK_Section *dst, LNK_Section *src);
|
||||
internal void lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine);
|
||||
|
||||
internal String8 lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags, U64 section_index);
|
||||
|
||||
internal LNK_Chunk * lnk_section_push_chunk_raw(LNK_Section *sect, LNK_Chunk *parent, void *data_ptr, U64 data_size, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_section_push_chunk_data(LNK_Section *sect, LNK_Chunk *parent, String8 data, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_section_push_chunk_u32(LNK_Section *sect, LNK_Chunk *parent, U32 value, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_section_push_chunk_u64(LNK_Section *sect, LNK_Chunk *parent, U32 value, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_section_push_chunk_bss(LNK_Section *sect, LNK_Chunk *parent, U64 size, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_section_push_chunk_list(LNK_Section *sect, LNK_Chunk *parent, String8 sort_index);
|
||||
|
||||
internal LNK_SectionTable * lnk_section_table_alloc(U64 section_virt_off, U64 sect_align, U64 file_align);
|
||||
internal LNK_SectionTable * lnk_section_table_alloc(void);
|
||||
internal void lnk_section_table_release(LNK_SectionTable **st_ptr);
|
||||
internal LNK_Section * lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags);
|
||||
internal LNK_Section * lnk_section_table_push_null(LNK_SectionTable *sectab);
|
||||
internal void lnk_section_table_remove(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 name);
|
||||
internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 name);
|
||||
internal LNK_Section * lnk_section_table_search_id(LNK_SectionTable *sectab, U64 id);
|
||||
internal void lnk_section_table_remove(LNK_SectionTable *sectab, String8 name);
|
||||
internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags);
|
||||
internal void lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_list);
|
||||
internal void lnk_section_table_remove_empties(LNK_SectionTable *sectab, LNK_SymbolTable *symtab);
|
||||
internal void lnk_section_table_build_data(TP_Context *tp, LNK_SectionTable *sectab, COFF_MachineType machine);
|
||||
internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *sectab);
|
||||
internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *sectab);
|
||||
internal void lnk_section_table_assign_indices(LNK_SectionTable *sectab);
|
||||
internal String8 lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *sectab, COFF_MachineType machine);
|
||||
|
||||
internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *sectab);
|
||||
internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *sectab);
|
||||
internal LNK_ChunkRef lnk_get_final_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal LNK_Section * lnk_sect_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal LNK_Chunk * lnk_chunk_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkPtr **chunk_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_isect_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_virt_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_file_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_virt_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
|
||||
internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
|
||||
internal ISectOff lnk_sc_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_virt_off_from_reloc(LNK_Section **sect_id_map, LNK_Reloc *reloc);
|
||||
internal U64 lnk_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
internal U64 lnk_sect_off_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
internal U64 lnk_virt_off_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
internal U64 lnk_file_off_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
internal U64 lnk_virt_size_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
internal U64 lnk_file_size_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
|
||||
#if LNK_DEBUG_CHUNKS
|
||||
internal void lnk_dump_chunks(LNK_SectionTable *sectab);
|
||||
#endif
|
||||
internal LNK_SectionArray lnk_section_table_get_output_sections(Arena *arena, LNK_SectionTable *sectab);
|
||||
|
||||
|
||||
+207
-430
@@ -1,128 +1,40 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
lnk_init_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolType type)
|
||||
{
|
||||
symbol->name = name;
|
||||
symbol->type = type;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_init_defined_symbol(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags)
|
||||
{
|
||||
switch (visibility) {
|
||||
case LNK_DefinedSymbolVisibility_Static: lnk_init_symbol(symbol, name, LNK_Symbol_DefinedStatic); break;
|
||||
case LNK_DefinedSymbolVisibility_Extern: lnk_init_symbol(symbol, name, LNK_Symbol_DefinedExtern); break;
|
||||
case LNK_DefinedSymbolVisibility_Internal: lnk_init_symbol(symbol, name, LNK_Symbol_DefinedInternal); break;
|
||||
}
|
||||
LNK_DefinedSymbol *def = &symbol->u.defined;
|
||||
def->flags = flags;
|
||||
def->value_type = LNK_DefinedSymbolValue_Null;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_init_defined_symbol_chunk(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, LNK_Chunk *chunk, U64 offset, COFF_ComdatSelectType selection, U32 check_sum)
|
||||
{
|
||||
lnk_init_defined_symbol(symbol, name, visibility, flags);
|
||||
LNK_DefinedSymbol *def = &symbol->u.defined;
|
||||
def->value_type = LNK_DefinedSymbolValue_Chunk;
|
||||
def->u.chunk = chunk;
|
||||
def->u.chunk_offset = offset;
|
||||
def->u.check_sum = check_sum;
|
||||
def->u.selection = selection;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_init_defined_symbol_va(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, U64 va)
|
||||
{
|
||||
lnk_init_defined_symbol(symbol, name, visibility, flags);
|
||||
LNK_DefinedSymbol *def = &symbol->u.defined;
|
||||
def->value_type = LNK_DefinedSymbolValue_VA;
|
||||
def->u.va = va;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_init_undefined_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolScopeFlags scope_flags)
|
||||
{
|
||||
lnk_init_symbol(symbol, name, LNK_Symbol_Undefined);
|
||||
symbol->u.undefined.scope_flags = scope_flags;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_init_weak_symbol(LNK_Symbol *symbol, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback)
|
||||
{
|
||||
lnk_init_symbol(symbol, name, LNK_Symbol_Weak);
|
||||
symbol->u.weak.scope_flags = LNK_SymbolScopeFlag_Defined;
|
||||
symbol->u.weak.lookup_type = lookup;
|
||||
symbol->u.weak.fallback_symbol = fallback;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_init_lazy_symbol(LNK_Symbol *symbol, String8 name, LNK_Lib *lib, U64 member_offset)
|
||||
{
|
||||
lnk_init_symbol(symbol, name, LNK_Symbol_Lazy);
|
||||
symbol->u.lazy.lib = lib;
|
||||
symbol->u.lazy.member_offset = member_offset;
|
||||
}
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_make_defined_symbol(Arena *arena, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags)
|
||||
lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx)
|
||||
{
|
||||
LNK_Symbol *symbol = push_array_no_zero(arena, LNK_Symbol, 1);
|
||||
lnk_init_defined_symbol(symbol, name, visibility, flags);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_make_defined_symbol_chunk(Arena *arena, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, LNK_Chunk *chunk, U64 offset, COFF_ComdatSelectType selection, U32 check_sum)
|
||||
{
|
||||
LNK_Symbol *symbol = push_array_no_zero(arena, LNK_Symbol, 1);
|
||||
lnk_init_defined_symbol_chunk(symbol, name, visibility, flags, chunk, offset, selection, check_sum);
|
||||
LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1);
|
||||
symbol->name = name;
|
||||
symbol->type = LNK_Symbol_Defined;
|
||||
symbol->u.defined.obj = obj;
|
||||
symbol->u.defined.symbol_idx = symbol_idx;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_make_defined_symbol_va(Arena *arena, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, U64 va)
|
||||
lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset)
|
||||
{
|
||||
LNK_Symbol *symbol = push_array_no_zero(arena, LNK_Symbol, 1);
|
||||
lnk_init_defined_symbol_va(symbol, name, visibility, flags, va);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_make_undefined_symbol(Arena *arena, String8 name, LNK_SymbolScopeFlags flags)
|
||||
{
|
||||
LNK_Symbol *symbol = push_array_no_zero(arena, LNK_Symbol, 1);
|
||||
lnk_init_undefined_symbol(symbol, name, flags);
|
||||
LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1);
|
||||
symbol->name = name;
|
||||
symbol->type = LNK_Symbol_Lib;
|
||||
symbol->u.lib.lib = lib;
|
||||
symbol->u.lib.member_offset = member_offset;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback)
|
||||
lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj)
|
||||
{
|
||||
LNK_Symbol *symbol = push_array_no_zero(arena, LNK_Symbol, 1);
|
||||
lnk_init_weak_symbol(symbol, name, lookup, fallback);
|
||||
LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1);
|
||||
symbol->name = name;
|
||||
symbol->type = LNK_Symbol_Undefined;
|
||||
symbol->u.undef.obj = obj;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_make_lazy_symbol(Arena *arena, String8 name, LNK_Lib *lib, U64 member_offset)
|
||||
{
|
||||
LNK_Symbol *symbol = push_array_no_zero(arena, LNK_Symbol, 1);
|
||||
lnk_init_lazy_symbol(symbol, name, lib, member_offset);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_from_symbol(LNK_Symbol *symbol)
|
||||
{
|
||||
if (LNK_Symbol_IsDefined(symbol->type) && symbol->u.defined.value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
return symbol->u.defined.u.chunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void
|
||||
@@ -147,24 +59,6 @@ lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat)
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal LNK_SymbolNode *
|
||||
lnk_symbol_list_search_node(LNK_SymbolList list, String8 name, StringMatchFlags flags)
|
||||
{
|
||||
for (LNK_SymbolNode *node = list.first; node != 0; node = node->next) {
|
||||
if (str8_match(node->data->name, name, flags)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_list_search(LNK_SymbolList list, String8 name, StringMatchFlags flags)
|
||||
{
|
||||
LNK_SymbolNode *node = lnk_symbol_list_search_node(list, name, flags);
|
||||
return node ? node->data : 0;
|
||||
}
|
||||
|
||||
internal LNK_SymbolList
|
||||
lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr)
|
||||
{
|
||||
@@ -205,6 +99,48 @@ lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal ISectOff
|
||||
lnk_sc_from_symbol(LNK_Symbol *symbol)
|
||||
{
|
||||
COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
|
||||
ISectOff sc = {0};
|
||||
sc.isect = parsed_symbol.section_number;
|
||||
sc.off = parsed_symbol.value;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_isect_from_symbol(LNK_Symbol *symbol)
|
||||
{
|
||||
return lnk_sc_from_symbol(symbol).isect;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_sect_off_from_symbol(LNK_Symbol *symbol)
|
||||
{
|
||||
return lnk_sc_from_symbol(symbol).off;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol)
|
||||
{
|
||||
ISectOff sc = lnk_sc_from_symbol(symbol);
|
||||
U64 voff = section_table[sc.isect]->voff + sc.off;
|
||||
return voff;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol)
|
||||
{
|
||||
ISectOff sc = lnk_sc_from_symbol(symbol);
|
||||
U64 foff = section_table[sc.isect]->foff + sc.off;
|
||||
return foff;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_SymbolHashTrie *
|
||||
lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList *list, U64 cap)
|
||||
{
|
||||
@@ -229,120 +165,148 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
|
||||
B32 can_replace = 0;
|
||||
|
||||
// lazy vs lazy
|
||||
if (dst->type == LNK_Symbol_Lazy && src->type == LNK_Symbol_Lazy) {
|
||||
// lib vs lib
|
||||
if (dst->type == LNK_Symbol_Lib && src->type == LNK_Symbol_Lib) {
|
||||
// link.exe picks symbol from lib that is discovered first
|
||||
LNK_Lib *dst_lib = dst->u.lazy.lib;
|
||||
LNK_Lib *src_lib = src->u.lazy.lib;
|
||||
can_replace = dst_lib->input_idx > src_lib->input_idx;
|
||||
}
|
||||
// lazy vs weak
|
||||
else if (dst->type == LNK_Symbol_Lazy && (LNK_Symbol_IsDefined(src->type) || src->type == LNK_Symbol_Weak)) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// weak vs strong
|
||||
else if (dst->type == LNK_Symbol_Weak && LNK_Symbol_IsDefined(src->type)) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// weak vs weak
|
||||
else if (dst->type == LNK_Symbol_Weak && src->type == LNK_Symbol_Weak) {
|
||||
B32 is_fallback_same = str8_match(dst->u.weak.fallback_symbol->name, src->u.weak.fallback_symbol->name, 0);
|
||||
if (is_fallback_same) {
|
||||
if (src->obj && !dst->obj) {
|
||||
can_replace = 1;
|
||||
} else if (src->obj && dst->obj) {
|
||||
can_replace = src->obj->input_idx < dst->obj->input_idx;
|
||||
}
|
||||
} else {
|
||||
lnk_error(LNK_Error_MultiplyDefinedSymbol, "multiply defined weak symbol %S, symbol defined in:", src->name);
|
||||
lnk_supplement_error("%S", dst->obj->path);
|
||||
lnk_supplement_error("%S", src->obj->path);
|
||||
}
|
||||
can_replace = src->u.lib.lib->input_idx < dst->u.lib.lib->input_idx;
|
||||
}
|
||||
else if (dst->type == LNK_Symbol_Import) {
|
||||
AssertAlways(src->type != LNK_Symbol_Import);
|
||||
can_replace = 1;
|
||||
}
|
||||
// defined VA vs defined chunk
|
||||
else if (LNK_Symbol_IsDefined(dst->type) && dst->u.defined.value_type == LNK_DefinedSymbolValue_VA &&
|
||||
LNK_Symbol_IsDefined(src->type)) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// defined chunk vs defined chunk
|
||||
else if (LNK_Symbol_IsDefined(dst->type) && dst->u.defined.value_type == LNK_DefinedSymbolValue_Chunk &&
|
||||
LNK_Symbol_IsDefined(src->type) && src->u.defined.value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
LNK_DefinedSymbol *dst_defn = &dst->u.defined;
|
||||
LNK_DefinedSymbol *src_defn = &src->u.defined;
|
||||
// defined vs defined
|
||||
else if (dst->type == LNK_Symbol_Defined && src->type == LNK_Symbol_Defined) {
|
||||
LNK_Obj *dst_obj = dst->u.defined.obj;
|
||||
LNK_Obj *src_obj = src->u.defined.obj;
|
||||
|
||||
Assert(dst_defn->u.chunk->is_discarded == 0);
|
||||
Assert(dst_defn->u.chunk->type == LNK_Chunk_Leaf);
|
||||
Assert(src_defn->u.chunk->type == LNK_Chunk_Leaf);
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx);
|
||||
COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx);
|
||||
|
||||
COFF_ComdatSelectType dst_select = dst_defn->u.selection;
|
||||
COFF_ComdatSelectType src_select = src_defn->u.selection;
|
||||
COFF_SymbolValueInterpType dst_interp = coff_interp_symbol(dst_parsed.section_number, dst_parsed.value, dst_parsed.storage_class);
|
||||
COFF_SymbolValueInterpType src_interp = coff_interp_symbol(src_parsed.section_number, src_parsed.value, src_parsed.storage_class);
|
||||
|
||||
// handle objs compiled with /GR- and /GR
|
||||
if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) ||
|
||||
(src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) {
|
||||
dst_select = COFF_ComdatSelect_Largest;
|
||||
src_select = COFF_ComdatSelect_Largest;
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->u.defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->u.defined.symbol_idx, src->u.defined.obj->path, src->u.defined.symbol_idx);
|
||||
}
|
||||
// abs vs regular
|
||||
else if ((dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) ||
|
||||
(dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs)) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->u.defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->u.defined.symbol_idx, src->u.defined.obj->path, src->u.defined.symbol_idx);
|
||||
}
|
||||
// abs vs common
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) {
|
||||
if (dst->u.defined.obj->input_idx < src->u.defined.obj->input_idx) {
|
||||
can_replace = 1;
|
||||
} else {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->u.defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->u.defined.symbol_idx, src->u.defined.obj->path, src->u.defined.symbol_idx);
|
||||
}
|
||||
}
|
||||
// common vs abs
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
if (dst->u.defined.obj->input_idx < src->u.defined.obj->input_idx) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->u.defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->u.defined.symbol_idx, src->u.defined.obj->path, src->u.defined.symbol_idx);
|
||||
}
|
||||
}
|
||||
// weak vs weak
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
}
|
||||
// weak vs abs
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// abs vs weak
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
can_replace = 0;
|
||||
}
|
||||
// weak vs regular,common,abs
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak &&
|
||||
(src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common || src_interp == COFF_SymbolValueInterp_Abs)) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// regular,common vs regular,common
|
||||
else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) &&
|
||||
(src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) {
|
||||
COFF_ComdatSelectType dst_select;
|
||||
U32 dst_section_length;
|
||||
U32 dst_check_sum;
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular) {
|
||||
coff_parse_secdef(dst_parsed, dst_obj->header.is_big_obj, &dst_select, 0, &dst_section_length, &dst_check_sum);
|
||||
} else {
|
||||
dst_select = COFF_ComdatSelect_Largest;
|
||||
dst_section_length = dst_parsed.value;
|
||||
dst_check_sum = 0;
|
||||
}
|
||||
|
||||
if (src_select == dst_select) {
|
||||
LNK_Chunk *dst_chunk = dst_defn->u.chunk;
|
||||
LNK_Chunk *src_chunk = src_defn->u.chunk;
|
||||
U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk);
|
||||
U64 src_chunk_size = lnk_chunk_get_size(src_chunk);
|
||||
COFF_ComdatSelectType src_select;
|
||||
U32 src_section_length;
|
||||
U32 src_check_sum;
|
||||
if (src_interp == COFF_SymbolValueInterp_Regular) {
|
||||
coff_parse_secdef(src_parsed, src_obj->header.is_big_obj, &src_select, 0, &src_section_length, &src_check_sum);
|
||||
} else {
|
||||
src_select = COFF_ComdatSelect_Largest;
|
||||
src_section_length = src_parsed.value;
|
||||
src_check_sum = 0;
|
||||
}
|
||||
|
||||
switch (src_select) {
|
||||
case COFF_ComdatSelect_Null:
|
||||
case COFF_ComdatSelect_Any: {
|
||||
if (src_chunk_size == dst_chunk_size) {
|
||||
can_replace = src_chunk->input_idx < dst_chunk->input_idx;
|
||||
} else {
|
||||
// both COMDATs are valid but to get smaller exe pick smallest
|
||||
can_replace = src_chunk_size < dst_chunk_size;
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_NoDuplicates: {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path);
|
||||
} break;
|
||||
case COFF_ComdatSelect_SameSize: {
|
||||
if (dst_chunk_size != src_chunk_size) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path);
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_ExactMatch: {
|
||||
if (dst_defn->u.check_sum != src_defn->u.check_sum) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path);
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_Largest: {
|
||||
if (dst_chunk_size == src_chunk_size) {
|
||||
if (dst_defn->u.chunk->u.leaf.str == 0 && src_defn->u.chunk->u.leaf.size > 0) {
|
||||
// handle communal variable
|
||||
//
|
||||
// MSVC CRT relies on this behaviour (e.g. __scrt_ucrt_dll_is_in_use in ucrt_detection.c)
|
||||
can_replace = 1;
|
||||
// handle objs compiled with /GR- and /GR
|
||||
if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) ||
|
||||
(src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) {
|
||||
dst_select = COFF_ComdatSelect_Largest;
|
||||
src_select = COFF_ComdatSelect_Largest;
|
||||
}
|
||||
|
||||
if (src_select == dst_select) {
|
||||
switch (src_select) {
|
||||
case COFF_ComdatSelect_Null:
|
||||
case COFF_ComdatSelect_Any: {
|
||||
if (src_section_length == dst_section_length) {
|
||||
can_replace = src_obj->input_idx < dst_obj->input_idx;
|
||||
} else {
|
||||
can_replace = src_chunk->input_idx < dst_chunk->input_idx;
|
||||
// both COMDATs are valid but to get smaller exe pick smallest
|
||||
can_replace = src_section_length < dst_section_length;
|
||||
}
|
||||
} else {
|
||||
can_replace = dst_chunk_size < src_chunk_size;
|
||||
} break;
|
||||
case COFF_ComdatSelect_NoDuplicates: {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S.", dst->name, dst_obj->path);
|
||||
} break;
|
||||
case COFF_ComdatSelect_SameSize: {
|
||||
if (dst_section_length != src_section_length) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S.", dst->name, dst_obj->path);
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_ExactMatch: {
|
||||
if (dst_check_sum != src_check_sum) {
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S.", dst->name, dst_obj->path);
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_Largest: {
|
||||
if (dst_section_length == src_section_length) {
|
||||
if (dst_interp == COFF_SymbolValueInterp_Common) {
|
||||
// handle communal variable
|
||||
//
|
||||
// MSVC CRT relies on this behaviour (e.g. __scrt_ucrt_dll_is_in_use in ucrt_detection.c)
|
||||
can_replace = 1;
|
||||
} else {
|
||||
can_replace = src_obj->input_idx < dst_obj->input_idx;
|
||||
}
|
||||
} else {
|
||||
can_replace = dst_section_length < src_section_length;
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_Associative: {
|
||||
// ignore
|
||||
} break;
|
||||
default: { InvalidPath; }
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_Associative: {
|
||||
// ignore
|
||||
} break;
|
||||
default: {
|
||||
lnk_error_obj(LNK_Error_InvalidPath, src->obj, "unknown COMDAT selection %#x", src->obj, src_select);
|
||||
} break;
|
||||
} else {
|
||||
String8 src_select_str = coff_string_from_comdat_select_type(src_select);
|
||||
String8 dst_select_str = coff_string_from_comdat_select_type(dst_select);
|
||||
lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj,
|
||||
"%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S",
|
||||
src->name, src_select_str, dst_select_str, dst_obj);
|
||||
}
|
||||
} else {
|
||||
String8 src_select_str = coff_string_from_comdat_select_type(src_defn->u.selection);
|
||||
String8 dst_select_str = coff_string_from_comdat_select_type(dst_defn->u.selection);
|
||||
lnk_error_obj(LNK_Warning_UnresolvedComdat, src->obj,
|
||||
"%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S",
|
||||
src->name, src_select_str, dst_select_str, dst->obj->path);
|
||||
lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination");
|
||||
}
|
||||
} else {
|
||||
lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination");
|
||||
@@ -355,33 +319,12 @@ internal void
|
||||
lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
{
|
||||
Assert(dst != src);
|
||||
|
||||
if (dst->type == LNK_Symbol_Lazy && src->type == LNK_Symbol_Lazy) {
|
||||
dst->u.lazy = src->u.lazy;
|
||||
} else if (LNK_Symbol_IsDefined(dst->type)) {
|
||||
LNK_DefinedSymbol *dst_defined = &dst->u.defined;
|
||||
|
||||
if (dst_defined->value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
// discard chunk from output
|
||||
dst_defined->u.chunk->is_discarded = 1;
|
||||
|
||||
if (LNK_Symbol_IsDefined(src->type)) {
|
||||
LNK_DefinedSymbol *src_defined = &src->u.defined;
|
||||
|
||||
if (src_defined->value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
// static symbols that are not part of obj's symbol table might point to discarded chunk
|
||||
dst_defined->u.chunk->ref = src_defined->u.chunk->ref;
|
||||
|
||||
// copy offset because after folding COMDATS we might end
|
||||
// up with larger sized chunk and, for instance, a vftable
|
||||
// might have a function pointer preceeding lead symbol
|
||||
dst_defined->u.chunk = src_defined->u.chunk;
|
||||
dst_defined->u.chunk_offset = src_defined->u.chunk_offset;
|
||||
}
|
||||
} else {
|
||||
InvalidPath;
|
||||
}
|
||||
}
|
||||
if (dst->type == LNK_Symbol_Lib && src->type == LNK_Symbol_Lib) {
|
||||
dst->u.lib = src->u.lib;
|
||||
} else if (dst->type == LNK_Symbol_Defined && src->type == LNK_Symbol_Defined) {
|
||||
dst->u.defined = src->u.defined;
|
||||
} else {
|
||||
InvalidPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,38 +444,28 @@ lnk_symbol_table_init(TP_Arena *arena)
|
||||
{
|
||||
LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1);
|
||||
symtab->arena = arena;
|
||||
for (U64 i = 0; i < LNK_SymbolScopeIndex_Count; ++i) {
|
||||
for (U64 i = 0; i < LNK_SymbolScope_Count; ++i) {
|
||||
symtab->chunk_lists[i] = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count);
|
||||
}
|
||||
return symtab;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, U64 hash, String8 name)
|
||||
lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScope scope, U64 hash, String8 name)
|
||||
{
|
||||
LNK_Symbol *result = 0;
|
||||
while (scope_flags) {
|
||||
LNK_SymbolScopeIndex scope_idx = ctz64(scope_flags);
|
||||
scope_flags &= scope_flags - 1;
|
||||
|
||||
LNK_SymbolHashTrie *match = lnk_symbol_hash_trie_search(symtab->scopes[scope_idx], hash, name);
|
||||
if (match) {
|
||||
result = match->symbol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
LNK_SymbolHashTrie *trie = lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name);
|
||||
return trie ? trie->symbol : 0;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name)
|
||||
lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name)
|
||||
{
|
||||
U64 hash = lnk_symbol_hash(name);
|
||||
return lnk_symbol_table_search_hash(symtab, scope, hash, name);
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, char *fmt, ...)
|
||||
lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
@@ -541,16 +474,16 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_fla
|
||||
String8 name = push_str8fv(scratch.arena, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
LNK_Symbol *symbol = lnk_symbol_table_search(symtab, scope_flags, name);
|
||||
LNK_Symbol *symbol = lnk_symbol_table_search(symtab, scope, name);
|
||||
|
||||
scratch_end(scratch);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolScopeIndex scope_idx, U64 hash, LNK_Symbol *symbol)
|
||||
lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_SymbolScope scope, U64 hash, LNK_Symbol *symbol)
|
||||
{
|
||||
lnk_symbol_hash_trie_insert_or_replace(arena, chunk_list, &symtab->scopes[scope_idx], hash, symbol);
|
||||
lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunk_lists[scope][worker_id], &symtab->scopes[scope], hash, symbol);
|
||||
}
|
||||
|
||||
internal void
|
||||
@@ -558,29 +491,10 @@ lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol
|
||||
{
|
||||
switch (symbol->type) {
|
||||
case LNK_Symbol_Null: break;
|
||||
|
||||
case LNK_Symbol_Import:
|
||||
case LNK_Symbol_DefinedExtern: {
|
||||
lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Defined][0], LNK_SymbolScopeIndex_Defined, hash, symbol);
|
||||
} break;
|
||||
|
||||
case LNK_Symbol_DefinedInternal: {
|
||||
lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Internal][0], LNK_SymbolScopeIndex_Internal, hash, symbol);
|
||||
} break;
|
||||
|
||||
case LNK_Symbol_Weak: {
|
||||
lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Weak][0], LNK_SymbolScopeIndex_Weak, hash, symbol);
|
||||
} break;
|
||||
|
||||
case LNK_Symbol_Lazy: {
|
||||
lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Lib][0], LNK_SymbolScopeIndex_Lib, hash, symbol);
|
||||
} break;
|
||||
|
||||
// symbols not supported
|
||||
case LNK_Symbol_Undefined:
|
||||
case LNK_Symbol_DefinedStatic: {
|
||||
InvalidPath;
|
||||
} break;
|
||||
case LNK_Symbol_Defined:
|
||||
case LNK_Symbol_Import: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Defined, hash, symbol); } break;
|
||||
case LNK_Symbol_Lib: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Lib, hash, symbol); } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +506,7 @@ lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol)
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name)
|
||||
lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name)
|
||||
{
|
||||
U64 hash = lnk_symbol_hash(name);
|
||||
LNK_SymbolHashTrie *trie = lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name);
|
||||
@@ -601,141 +515,4 @@ lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, Str
|
||||
}
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_push_defined_chunk(LNK_SymbolTable *symtab, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, LNK_Chunk *chunk, U64 offset, COFF_ComdatSelectType selection, U32 check_sum)
|
||||
{
|
||||
LNK_Symbol *symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], name, visibility, flags, chunk, offset, selection, check_sum);
|
||||
lnk_symbol_table_push(symtab, symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_push_defined(LNK_SymbolTable *symtab, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags)
|
||||
{
|
||||
LNK_Symbol *symbol = lnk_make_defined_symbol(symtab->arena->v[0], name, visibility, flags);
|
||||
lnk_symbol_table_push(symtab, symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_push_defined_va(LNK_SymbolTable *symtab, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, U64 va)
|
||||
{
|
||||
LNK_Symbol *symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], name, visibility, flags, va);
|
||||
lnk_symbol_table_push(symtab, symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_symbol_table_push_weak(LNK_SymbolTable *symtab, String8 weak_name, COFF_WeakExtType lookup, String8 strong_name)
|
||||
{
|
||||
weak_name = push_str8_copy(symtab->arena->v[0], weak_name);
|
||||
strong_name = push_str8_copy(symtab->arena->v[0], strong_name);
|
||||
LNK_Symbol *strong_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], strong_name, LNK_SymbolScopeFlag_Main);
|
||||
LNK_Symbol *weak_symbol = lnk_make_weak_symbol(symtab->arena->v[0], weak_name, COFF_WeakExt_SearchAlias, strong_symbol);
|
||||
lnk_symbol_table_push(symtab, weak_symbol);
|
||||
return weak_symbol;
|
||||
}
|
||||
|
||||
internal LNK_Symbol *
|
||||
lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol)
|
||||
{
|
||||
LNK_Symbol *symbol = resolve_symbol;
|
||||
B32 run_resolver;
|
||||
do {
|
||||
run_resolver = 0;
|
||||
switch (symbol->type) {
|
||||
case LNK_Symbol_Null: break;
|
||||
case LNK_Symbol_Undefined: {
|
||||
LNK_UndefinedSymbol *undef_symbol = &symbol->u.undefined;
|
||||
LNK_Symbol *def = lnk_symbol_table_search(symtab, undef_symbol->scope_flags, symbol->name);
|
||||
if (def) {
|
||||
symbol = def;
|
||||
run_resolver = 1;
|
||||
}
|
||||
} break;
|
||||
case LNK_Symbol_Weak: {
|
||||
LNK_WeakSymbol *weak = &symbol->u.weak;
|
||||
LNK_Symbol *def = lnk_symbol_table_search(symtab, weak->scope_flags, symbol->name);
|
||||
if (def) {
|
||||
Assert(LNK_Symbol_IsDefined(def->type));
|
||||
symbol = def;
|
||||
} else {
|
||||
symbol = symbol->u.weak.fallback_symbol;
|
||||
}
|
||||
run_resolver = 1;
|
||||
} break;
|
||||
case LNK_Symbol_DefinedExtern: {
|
||||
// search for defined symbol because we don't update symbol pointers in relocations
|
||||
// whenver we replace them in the symbol table
|
||||
symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Defined, symbol->name);
|
||||
Assert(symbol);
|
||||
} break;
|
||||
case LNK_Symbol_DefinedStatic:
|
||||
case LNK_Symbol_DefinedInternal: {
|
||||
// symbol resolved
|
||||
} break;
|
||||
default: NotImplemented;
|
||||
}
|
||||
} while (run_resolver);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
internal void
|
||||
lnk_symbol_hash_trie_debug(LNK_SymbolHashTrie *root)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
U64 i;
|
||||
LNK_SymbolHashTrie *trie;
|
||||
};
|
||||
|
||||
struct Stack *stack = push_array(scratch.arena, struct Stack, 1);
|
||||
stack->i = 0;
|
||||
stack->trie = root;
|
||||
|
||||
U64 cur_depth = 1;
|
||||
U64 max_depth = 0;
|
||||
|
||||
char *dashes = "--------------------------------";
|
||||
|
||||
FILE *f = fopen("trie.txt", "w");
|
||||
|
||||
while (stack) {
|
||||
for (; stack->i < ArrayCount(stack->trie->child); ++stack->i) {
|
||||
|
||||
if (stack->i == 0 && stack->trie->symbol) {
|
||||
fprintf(f, "%.*s%.*s\n", (int)cur_depth, dashes, str8_varg(stack->trie->symbol->name));
|
||||
}
|
||||
|
||||
if (stack->trie->child[stack->i] != 0) {
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->i = 0;
|
||||
frame->trie = stack->trie->child[stack->i];
|
||||
|
||||
stack->i += 1;
|
||||
SLLStackPush(stack, frame);
|
||||
|
||||
cur_depth += 1;
|
||||
max_depth = Max(cur_depth, max_depth);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack->i >= ArrayCount(stack->trie->child)) {
|
||||
cur_depth -= 1;
|
||||
SLLStackPop(stack);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "Max Depth: %llu\n", max_depth);
|
||||
fclose(f);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+56
-113
@@ -1,109 +1,49 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_SymbolScopeIndex_Defined,
|
||||
LNK_SymbolScopeIndex_Internal, // symbols defined by linker
|
||||
LNK_SymbolScopeIndex_Weak,
|
||||
LNK_SymbolScopeIndex_Lib,
|
||||
LNK_SymbolScopeIndex_Count
|
||||
} LNK_SymbolScopeIndex;
|
||||
////////////////////////////////
|
||||
|
||||
enum
|
||||
{
|
||||
LNK_SymbolScopeFlag_Defined = 1,
|
||||
LNK_SymbolScopeFlag_Internal = 2,
|
||||
LNK_SymbolScopeFlag_Weak = 4,
|
||||
LNK_SymbolScopeFlag_Lib = 8,
|
||||
|
||||
LNK_SymbolScopeFlag_Main = LNK_SymbolScopeFlag_Defined | LNK_SymbolScopeFlag_Weak,
|
||||
LNK_SymbolScopeFlag_All = LNK_SymbolScopeFlag_Defined | LNK_SymbolScopeFlag_Weak | LNK_SymbolScopeFlag_Lib | LNK_SymbolScopeFlag_Internal
|
||||
};
|
||||
typedef U64 LNK_SymbolScopeFlags;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_DefinedSymbolVisibility_Static,
|
||||
LNK_DefinedSymbolVisibility_Extern,
|
||||
LNK_DefinedSymbolVisibility_Internal,
|
||||
} LNK_DefinedSymbolVisibility;
|
||||
|
||||
enum
|
||||
{
|
||||
LNK_DefinedSymbolFlag_IsFunc = (1 << 0),
|
||||
LNK_DefinedSymbolFlag_IsThunk = (1 << 1),
|
||||
};
|
||||
typedef U64 LNK_DefinedSymbolFlags;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_DefinedSymbolValue_Null,
|
||||
LNK_DefinedSymbolValue_Chunk,
|
||||
LNK_DefinedSymbolValue_VA
|
||||
} LNK_DefinedSymbolValueType;
|
||||
|
||||
typedef struct LNK_DefinedSymbol
|
||||
{
|
||||
LNK_DefinedSymbolFlags flags;
|
||||
LNK_DefinedSymbolValueType value_type;
|
||||
union {
|
||||
struct {
|
||||
LNK_Chunk *chunk;
|
||||
U64 chunk_offset;
|
||||
U32 check_sum;
|
||||
COFF_ComdatSelectType selection;
|
||||
};
|
||||
U64 va;
|
||||
} u;
|
||||
} LNK_DefinedSymbol;
|
||||
|
||||
typedef struct LNK_WeakSymbol
|
||||
{
|
||||
LNK_SymbolScopeFlags scope_flags;
|
||||
COFF_WeakExtType lookup_type;
|
||||
struct LNK_Symbol *fallback_symbol;
|
||||
} LNK_WeakSymbol;
|
||||
|
||||
typedef struct LNK_UndefinedSymbol
|
||||
{
|
||||
LNK_SymbolScopeFlags scope_flags;
|
||||
} LNK_UndefinedSymbol;
|
||||
|
||||
typedef struct LNK_LazySymbol
|
||||
{
|
||||
struct LNK_Lib *lib;
|
||||
U64 member_offset;
|
||||
} LNK_LazySymbol;
|
||||
|
||||
#define LNK_Symbol_IsDefined(type) ((type) == LNK_Symbol_DefinedStatic || (type) == LNK_Symbol_DefinedExtern || (type) == LNK_Symbol_DefinedInternal)
|
||||
typedef enum
|
||||
{
|
||||
LNK_Symbol_Null,
|
||||
LNK_Symbol_DefinedStatic,
|
||||
LNK_Symbol_DefinedExtern,
|
||||
LNK_Symbol_DefinedInternal,
|
||||
LNK_Symbol_Weak,
|
||||
LNK_Symbol_Lazy,
|
||||
LNK_Symbol_Undefined,
|
||||
LNK_Symbol_Defined,
|
||||
LNK_Symbol_Import,
|
||||
LNK_Symbol_Lib,
|
||||
LNK_Symbol_Undefined,
|
||||
} LNK_SymbolType;
|
||||
|
||||
typedef struct LNK_SymbolDefined
|
||||
{
|
||||
struct LNK_Obj *obj;
|
||||
U32 symbol_idx;
|
||||
} LNK_SymbolDefined;
|
||||
|
||||
typedef struct LNK_SymbolLib
|
||||
{
|
||||
struct LNK_Lib *lib;
|
||||
U64 member_offset;
|
||||
} LNK_SymbolLib;
|
||||
|
||||
typedef struct LNK_SymbolUndefined
|
||||
{
|
||||
struct LNK_Obj *obj;
|
||||
} LNK_SymbolUndefined;
|
||||
|
||||
typedef struct LNK_Symbol
|
||||
{
|
||||
String8 name;
|
||||
LNK_SymbolType type;
|
||||
struct LNK_Obj *obj;
|
||||
String8 name;
|
||||
LNK_SymbolType type;
|
||||
union {
|
||||
LNK_DefinedSymbol defined;
|
||||
LNK_WeakSymbol weak;
|
||||
LNK_UndefinedSymbol undefined;
|
||||
LNK_LazySymbol lazy;
|
||||
LNK_SymbolDefined defined;
|
||||
LNK_SymbolLib lib;
|
||||
LNK_SymbolUndefined undef;
|
||||
} u;
|
||||
} LNK_Symbol;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct LNK_SymbolNode
|
||||
{
|
||||
struct LNK_SymbolNode *next;
|
||||
@@ -129,6 +69,15 @@ typedef struct LNK_SymbolArray
|
||||
LNK_Symbol *v;
|
||||
} LNK_SymbolArray;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_SymbolScope_Defined,
|
||||
LNK_SymbolScope_Lib,
|
||||
LNK_SymbolScope_Count
|
||||
} LNK_SymbolScope;
|
||||
|
||||
typedef struct LNK_SymbolHashTrie
|
||||
{
|
||||
String8 *name;
|
||||
@@ -154,8 +103,8 @@ typedef struct LNK_SymbolHashTrieChunkList
|
||||
typedef struct LNK_SymbolTable
|
||||
{
|
||||
TP_Arena *arena;
|
||||
LNK_SymbolHashTrie *scopes[LNK_SymbolScopeIndex_Count];
|
||||
LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScopeIndex_Count];
|
||||
LNK_SymbolHashTrie *scopes[LNK_SymbolScope_Count];
|
||||
LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScope_Count];
|
||||
} LNK_SymbolTable;
|
||||
|
||||
////////////////////////////////
|
||||
@@ -170,26 +119,14 @@ typedef struct
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
global read_only LNK_Symbol g_null_symbol = { str8_lit_comp("NULL"), LNK_Symbol_DefinedStatic };
|
||||
global read_only LNK_Symbol g_null_symbol = { str8_lit_comp("NULL"), LNK_Symbol_Null };
|
||||
global read_only LNK_Symbol *g_null_symbol_ptr = &g_null_symbol;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_init_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolType type);
|
||||
internal void lnk_init_defined_symbol(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags);
|
||||
internal void lnk_init_defined_symbol_chunk(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, LNK_Chunk *chunk, U64 offset, COFF_ComdatSelectType selection, U32 check_sum);
|
||||
internal void lnk_init_defined_symbol_va(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, U64 va);
|
||||
internal void lnk_init_undefined_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolScopeFlags scope_flags);
|
||||
internal void lnk_init_weak_symbol(LNK_Symbol *symbol, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback);
|
||||
|
||||
internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags);
|
||||
internal LNK_Symbol * lnk_make_defined_symbol_chunk(Arena *arena, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, LNK_Chunk *chunk, U64 offset, COFF_ComdatSelectType selection, U32 check_sum);
|
||||
internal LNK_Symbol * lnk_make_defined_symbol_va(Arena *arena, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, U64 va);
|
||||
internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, LNK_SymbolScopeFlags scope_flags);
|
||||
internal LNK_Symbol * lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback);
|
||||
internal LNK_Symbol * lnk_make_lazy_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
|
||||
|
||||
internal LNK_Chunk * lnk_chunk_from_symbol(LNK_Symbol *symbol);
|
||||
internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx);
|
||||
internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
|
||||
internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -202,6 +139,14 @@ internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_Symbol
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal ISectOff lnk_sc_from_symbol (LNK_Symbol *symbol);
|
||||
internal U64 lnk_isect_from_symbol (LNK_Symbol *symbol);
|
||||
internal U64 lnk_sect_off_from_symbol(LNK_Symbol *symbol);
|
||||
internal U64 lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol);
|
||||
internal U64 lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *symbol);
|
||||
internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name);
|
||||
internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie);
|
||||
@@ -211,12 +156,10 @@ internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *tr
|
||||
internal U64 lnk_symbol_hash(String8 string);
|
||||
|
||||
internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena);
|
||||
internal LNK_Symbol * lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, U64 hash, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, char *fmt, ...);
|
||||
internal LNK_Symbol * lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScope scope, U64 hash, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...);
|
||||
internal void lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol);
|
||||
internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
|
||||
internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name);
|
||||
|
||||
internal LNK_Symbol * lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol);
|
||||
internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global LNK_Timer g_timers[LNK_Timer_Count];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal RDIB_DataModel
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal RDI_Arch
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal RDI_Arch
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
Reference in New Issue
Block a user