add /RAD_REMOVE_SECTION switch and special case debug sections

This commit is contained in:
Nikita Smith
2025-05-28 09:42:05 -07:00
committed by Ryan Fleury
parent 9c59cfd4e7
commit 89e2ea15ad
7 changed files with 116 additions and 69 deletions
+83 -52
View File
@@ -149,6 +149,10 @@
////////////////////////////////
global read_only LNK_SectionContrib g_null_sc;
////////////////////////////////
internal LNK_Config *
lnk_config_from_argcv(Arena *arena, int argc, char **argv)
{
@@ -204,6 +208,7 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv)
#else
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "%u", LNK_Error_InvalidTypeIndex);
#endif
// default section merges
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".xdata=.rdata");
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".tls=.data");
@@ -212,6 +217,9 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv)
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".didat=.rdata");
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".RAD_LINKER_DEBUG_DIR=.rdata");
// sections to remove from the image
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".debug");
// set default max worker count
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_SharedThreadPool)) {
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, "");
@@ -1195,10 +1203,24 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
for (U64 sect_idx = 0; sect_idx < obj_header.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *section_header = &section_table[sect_idx];
// was section discarded?
// was section removed?
if (section_header->flags & COFF_SectionFlag_LnkRemove) {
continue;
}
if (section_header->flags & COFF_SectionFlag_CntUninitializedData) {
continue;
}
// get section file range
Rng1U64 section_frange = rng_1u64(section_header->foff, section_header->foff + section_header->fsize);
// get section bytes
String8 section_data;
if (lnk_is_coff_section_debug(obj, sect_idx)) {
section_data = str8_substr(obj->data, section_frange);
} else {
section_data = str8_substr(task->image_data, section_frange);
}
// find section relocs
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header);
@@ -1217,8 +1239,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
NotImplemented;
}
// compute relocation file/virtual offsets
U64 reloc_foff = section_header->foff + reloc->apply_off;
// compute virtual offsets
U64 reloc_voff = section_header->voff + reloc->apply_off;
// compute symbol location values
@@ -1267,16 +1288,16 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
}
// read addend
Assert(reloc_foff + reloc_value.size <= task->image_data.size);
Assert(reloc_value.size <= section_data.size);
U64 raw_addend = 0;
str8_deserial_read(task->image_data, reloc_foff, &raw_addend, reloc_value.size, 1);
str8_deserial_read(section_data, reloc->apply_off, &raw_addend, reloc_value.size, 1);
// compute new reloc value
S64 addend = extend_sign64(raw_addend, reloc_value.size);
U64 reloc_result = reloc_value.value + addend;
// commit new reloc value
MemoryCopy(task->image_data.str + reloc_foff, &reloc_result, reloc_value.size);
MemoryCopy(section_data.str + reloc->apply_off, &reloc_result, reloc_value.size);
}
}
}
@@ -2174,7 +2195,7 @@ lnk_pdata_is_before_x8664(void *raw_a, void *raw_b)
}
internal String8
lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, LNK_ObjList obj_list)
lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs)
{
Temp scratch = scratch_begin(arena->v, arena->count);
@@ -2186,14 +2207,8 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
lnk_section_table_push(sectab, str8_lit(".data"), PE_DATA_SECTION_FLAGS);
lnk_section_table_push(sectab, str8_lit(".rdata"), PE_RDATA_SECTION_FLAGS);
//
// obj list -> array
//
U64 objs_count = obj_list.count;
LNK_Obj **objs = lnk_array_from_obj_list(scratch.arena, obj_list);
ProfBegin("Remove Associatives");
{
ProfBegin("Remove Associative Sections");
for (U64 obj_idx = 0; obj_idx < objs_count; obj_idx += 1) {
LNK_Obj *obj = objs[obj_idx];
String8 string_table = str8_substr(obj->data, obj->header.string_table_range);
@@ -2227,8 +2242,8 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
}
}
}
ProfEnd();
}
ProfEnd();
{
ProfBegin("Define And Count Sections");
@@ -2247,7 +2262,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *sect_header = &section_table[sect_idx];
// discard section
// remove section
if (sect_header->flags & COFF_SectionFlag_LnkRemove) {
continue;
}
@@ -2257,19 +2272,13 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
String8 sect_name, sect_sort_idx;
coff_parse_section_name(full_sect_name, &sect_name, &sect_sort_idx);
// remove debug sections
if (str8_match(sect_name, str8_lit(".debug"), 0)) {
sect_header->flags |= COFF_SectionFlag_LnkRemove;
continue;
}
// strip linker flags
COFF_SectionFlags sect_flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
// was section defined?
COFF_SectionFlags sect_flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
String8 sect_name_with_flags = lnk_make_name_with_flags(temp.arena, sect_name, sect_flags);
LNK_SectionDefinition *sect_defn = 0;
hash_table_search_string_raw(sect_defn_ht, sect_name_with_flags, &sect_defn);
// create section definition
if (sect_defn == 0) {
sect_defn = push_array(temp.arena, LNK_SectionDefinition, 1);
sect_defn->name = sect_name;
@@ -2314,20 +2323,30 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
for (U64 defn_idx = 0; defn_idx < sect_defns_count; defn_idx += 1) {
LNK_SectionDefinition *sect_defn = sect_defns[defn_idx];
// do not create definitions for sections that are removed from the image
{
B32 skip = 0;
for (String8Node *name_n = config->remove_sections.first; name_n != 0; name_n = name_n->next) {
if (str8_match(sect_defn->name, name_n->string, 0)) {
skip = 1;
break;
}
}
if (skip) { continue; }
}
// warn about conflicting section flags
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
LNK_Section *sect = &sect_n->data;
if (str8_match(sect->name, sect_defn->name, 0)) {
if (sect->flags != sect_defn->flags) {
LNK_Obj *obj = sect_defn->obj;
String8 string_table = str8_substr(obj->data, obj->header.string_table_range);
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
COFF_SectionHeader *sect_header = &section_table[sect_defn->obj_sect_idx];
String8 full_sect_name = coff_name_from_section_header(string_table, sect_header);
U32 sect_number = sect_defn->obj_sect_idx + 1;
COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, sect_number);
String8 sect_name = coff_name_from_section_header(str8_substr(obj->data, obj->header.string_table_range), sect_header);
String8 expected_flags_str = coff_string_from_section_flags(temp.arena, sect->flags);
String8 current_flags_str = coff_string_from_section_flags(temp.arena, sect_defn->flags);
lnk_error_obj(LNK_Warning_SectionFlagsConflict, sect_defn->obj, "detected section flags conflict in %S(No. %X); expected {%S} but got {%S}", full_sect_name, sect_number, expected_flags_str, current_flags_str);
lnk_error_obj(LNK_Warning_SectionFlagsConflict, sect_defn->obj, "detected section flags conflict in %S(No. %X); expected {%S} but got {%S}", sect_name, sect_number, expected_flags_str, current_flags_str);
}
}
}
@@ -2371,30 +2390,36 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
String8 sect_name, sect_sort_idx;
coff_parse_section_name(full_sect_name, &sect_name, &sect_sort_idx);
// extract section bytes
String8 sect_data = str8_substr(obj->data, rng_1u64(sect_header->foff, sect_header->foff + sect_header->fsize));
// extract align
U16 sc_align = coff_align_size_from_section_flags(sect_header->flags);
if (sc_align == 0) {
sc_align = default_align;
}
// search for section to contribute
COFF_SectionFlags flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
LNK_Section *sect = lnk_section_table_search(sectab, sect_name, flags);
String8Node *data_n = push_array(sectab->arena, String8Node, 1);
data_n->string = sect_data;
LNK_SectionContrib *sc;
if (sect) {
// extract align
U16 sc_align = coff_align_size_from_section_flags(sect_header->flags);
if (sc_align == 0) {
sc_align = default_align;
}
// fill out contrib
LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(sect->contribs.first, 1);
sc->align = sc_align;
sc->data_list = data_n;
sc->u.obj_idx = obj_idx;
sc->u.obj_sect_idx = sect_idx;
sc->u.sort_idx_size = (U16)sect_sort_idx.size;
sc->u.sort_idx = sect_sort_idx.str;
// extract section bytes
String8 sect_data = str8_substr(obj->data, rng_1u64(sect_header->foff, sect_header->foff + sect_header->fsize));
String8Node *data_n = push_array(sectab->arena, String8Node, 1);
data_n->string = sect_data;
// fill out contrib
sc = lnk_section_contrib_chunk_push(sect->contribs.first, 1);
sc->align = sc_align;
sc->data_list = data_n;
sc->u.obj_idx = obj_idx;
sc->u.obj_sect_idx = sect_idx;
sc->u.sort_idx_size = (U16)sect_sort_idx.size;
sc->u.sort_idx = sect_sort_idx.str;
} else {
// section was removed, fill slot with pointer to null contrib
sc = &g_null_sc;
}
sect_map[obj_idx][sect_idx] = sc;
}
@@ -2619,7 +2644,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
U32 section_number = 0;
U32 value = 0;
{
COFF_SectionHeader *sect_header = lnk_section_header_from_section_number(obj, symbol.section_number);
COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number);
if (~sect_header->flags & COFF_SectionFlag_LnkRemove) {
LNK_SectionContrib *sc = sect_map[obj_idx][symbol.section_number-1];
section_number = safe_cast_u32(sc->u.sect_idx + 1);
@@ -2933,7 +2958,9 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
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 = &section_table[sect_idx];
if (~sect_header->flags & COFF_SectionFlag_LnkRemove) {
B32 patch_section_header = (~sect_header->flags & COFF_SectionFlag_LnkRemove) &&
!lnk_is_coff_section_debug(obj, sect_idx);
if (patch_section_header) {
LNK_SectionContrib *sc = sect_map[obj_idx][sect_idx];
LNK_Section *sect = sects.v[sc->u.sect_idx];
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
@@ -4578,8 +4605,12 @@ lnk_run(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
}
} break;
case State_BuildImage: {
// obj list -> array
U64 objs_count = obj_list.count;
LNK_Obj **objs = lnk_array_from_obj_list(scratch.arena, obj_list);
// build image
image_data = lnk_build_win32_image(tp_arena, tp, config, symtab, obj_list);
image_data = lnk_build_win32_image(tp_arena, tp, config, symtab, objs_count, objs);
// write image to disk in a background thread
{
+1 -1
View File
@@ -175,7 +175,7 @@ internal void lnk_queue_lib_member_input(Arena *arena, PathStyle pat
internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
internal String8List lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_temp, LNK_Config *config, U64 objs_count, LNK_Obj **objs);
internal String8List lnk_build_win32_image_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sect_arr, U64 expected_image_header_size);
internal String8 lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, LNK_ObjList obj_list);
internal String8 lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, LNK_Obj **objs);
// --- Logger ------------------------------------------------------------------
+9
View File
@@ -145,6 +145,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = {
{ LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
{ LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." },
{ LNK_CmdSwitch_Rad_SectVirtOff, 0, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." },
{ LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" },
{ LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." },
@@ -1779,6 +1780,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &config->pdb_hash_type_name_length, 0);
} break;
case LNK_CmdSwitch_Rad_RemoveSection: {
String8 sect_name = {0};
if (lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, &sect_name)) {
sect_name = push_str8_copy(arena, sect_name);
str8_list_push(arena, &config->remove_sections, sect_name);
}
} break;
case LNK_CmdSwitch_Rad_SectVirtOff: {
U64 sect_virt_off;
if (lnk_cmd_switch_parse_u64(obj_path, lib_path, cmd_switch, value_strings, &sect_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) {
+7 -5
View File
@@ -130,8 +130,8 @@ typedef enum
LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll,
LNK_CmdSwitch_Rad_ChunkMap,
LNK_CmdSwitch_Rad_Debug,
LNK_CmdSwitch_Rad_DebugName,
LNK_CmdSwitch_Rad_DebugAltPath,
LNK_CmdSwitch_Rad_DebugName,
LNK_CmdSwitch_Rad_DelayBind,
LNK_CmdSwitch_Rad_DoMerge,
LNK_CmdSwitch_Rad_EnvLib,
@@ -145,22 +145,23 @@ typedef enum
LNK_CmdSwitch_Rad_OsVer,
LNK_CmdSwitch_Rad_PageSize,
LNK_CmdSwitch_Rad_PathStyle,
LNK_CmdSwitch_Rad_PdbHashTypeNames,
LNK_CmdSwitch_Rad_PdbHashTypeNameMap,
LNK_CmdSwitch_Rad_PdbHashTypeNameLength,
LNK_CmdSwitch_Rad_PdbHashTypeNameMap,
LNK_CmdSwitch_Rad_PdbHashTypeNames,
LNK_CmdSwitch_Rad_RemoveSection,
LNK_CmdSwitch_Rad_SectVirtOff,
LNK_CmdSwitch_Rad_SharedThreadPool,
LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers,
LNK_CmdSwitch_Rad_SuppressError,
LNK_CmdSwitch_Rad_SymbolTableCapDefined,
LNK_CmdSwitch_Rad_SymbolTableCapInternal,
LNK_CmdSwitch_Rad_SymbolTableCapWeak,
LNK_CmdSwitch_Rad_SymbolTableCapLib,
LNK_CmdSwitch_Rad_WriteTempFiles,
LNK_CmdSwitch_Rad_SymbolTableCapWeak,
LNK_CmdSwitch_Rad_TargetOs,
LNK_CmdSwitch_Rad_TimeStamp,
LNK_CmdSwitch_Rad_Version,
LNK_CmdSwitch_Rad_Workers,
LNK_CmdSwitch_Rad_WriteTempFiles,
LNK_CmdSwitch_Help,
@@ -380,6 +381,7 @@ typedef struct LNK_Config
String8 temp_pdb_name;
String8 temp_rad_debug_name;
String8 temp_rad_chunk_map_name;
String8List remove_sections;
} LNK_Config;
typedef enum
+1 -1
View File
@@ -64,7 +64,7 @@ lnk_make_dll_import_debug_symbols(Arena *arena, COFF_MachineType machine, String
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
// S_END
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_END, str8_zero());
//cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_END, str8_zero());
// TODO: add thunks
+14 -10
View File
@@ -420,6 +420,20 @@ lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number)
return section_header;
}
internal B32
lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx)
{
String8 string_table = str8_substr(obj->data, obj->header.string_table_range);
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx+1);
String8 full_name = coff_name_from_section_header(string_table, section_header);
String8 name, postfix;
coff_parse_section_name(full_name, &name, &postfix);
B32 is_debug = str8_match(name, str8_lit(".debug"), 0);
return is_debug;
}
internal COFF_ParsedSymbol
lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx)
{
@@ -436,16 +450,6 @@ lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx)
return result;
}
internal COFF_SectionHeader *
lnk_section_header_from_section_number(LNK_Obj *obj, U64 section_number)
{
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
if (section_number > 0 && section_number <= obj->header.section_count_no_null) {
return &section_table[section_number-1];
}
return 0;
}
internal
THREAD_POOL_TASK_FUNC(lnk_collect_obj_chunks_task)
{
+1
View File
@@ -108,6 +108,7 @@ 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 COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number);
internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx);
// --- Helpers -----------------------------------------------------------------