From 71a46985b6ba1a699cfe5846c2f2c13bc8f01ec8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 5 Feb 2026 00:58:32 -0800 Subject: [PATCH] use string table extension for long section names --- src/linker/lnk.c | 41 ++++++++++++++++++++++++++++++----- src/linker/lnk.h | 2 +- src/torture/torture_radlink.c | 32 +++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 2f8c472d..5f42ac5f 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3892,7 +3892,7 @@ lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, U6 } internal String8List -lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sects, U64 expected_image_header_size) +lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sects, U64 expected_image_header_size, U64 *file_header_offset_out, String8List *string_table_out) { ProfBeginFunction(); @@ -3951,6 +3951,8 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config file_header->section_count = sects.count; file_header->optional_header_size = (has_pe_plus_header ? sizeof(PE_OptionalHeader32Plus) : sizeof(PE_OptionalHeader32)) + (sizeof(PE_DataDirectory) * config->data_dir_count); file_header->flags = config->file_characteristics; + + *file_header_offset_out = result.total_size; str8_list_push(arena, &result, str8_struct(file_header)); } @@ -4061,13 +4063,21 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config if (coff_section->flags & COFF_SectionFlag_LnkRemove) { continue; } - // TODO: for objs we can store long name in string table and write here /offset + String8 section_name = sect->name; + + // use string table extension to store long section names if (sect->name.size > sizeof(coff_section->name)) { - lnk_error(LNK_Warning_LongSectionName, "not enough space in COFF section header to store entire name \"%S\"", sect->name); + if (string_table_out->node_count == 0) { + U32 *string_table_size = push_array(arena, U32, 1); + str8_list_push_front(arena, string_table_out, str8_struct(string_table_size)); + } + U64 name_offset = string_table_out->total_size; + str8_list_push(arena, string_table_out, push_cstr(arena, sect->name)); + section_name = push_str8f(arena, "/%u", name_offset); } MemorySet(&coff_section->name[0], 0, sizeof(coff_section->name)); - MemoryCopy(&coff_section->name[0], sect->name.str, Min(sect->name.size, sizeof(coff_section->name))); + MemoryCopy(&coff_section->name[0], section_name.str, Min(section_name.size, sizeof(coff_section->name))); coff_section->vsize = sect->vsize; coff_section->voff = sect->voff; coff_section->fsize = sect->fsize; @@ -4108,6 +4118,12 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config scratch_end(scratch); } + // write string table size + if (string_table_out->total_size) { + U32 *string_table_size = (U32 *)string_table_out->first->string.str; + *string_table_size = safe_cast_u32(string_table_out->total_size); + } + Assert(result.total_size == expected_image_header_size); ProfEnd(); return result; @@ -4453,8 +4469,10 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT } // build win32 image header + U64 image_file_header_off = 0; + String8List image_string_table = {0}; { - String8List image_header_data = lnk_build_win32_header(sectab->arena, symtab, config, task.image_sects, AlignPow2(expected_image_header_size, config->file_align)); + String8List image_header_data = lnk_build_win32_header(sectab->arena, symtab, config, task.image_sects, AlignPow2(expected_image_header_size, config->file_align), &image_file_header_off, &image_string_table); LNK_Section *image_header_sect = lnk_section_table_push(sectab, str8_lit(".rad_linker_image_header_section"), 0); LNK_SectionContribChunk *image_header_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &image_header_sect->contribs, 1, str8_zero()); LNK_SectionContrib *image_header_sc = lnk_section_contrib_chunk_push(image_header_sc_chunk, 1); @@ -4471,7 +4489,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT ProfBegin("Image Fill"); ProfBeginV("Alloc Image Buffer [%M]", lnk_section_table_total_fsize(sectab)); - image_data.size = lnk_section_table_total_fsize(sectab); + image_data.size = lnk_section_table_total_fsize(sectab) + image_string_table.total_size; image_data.str = push_array_no_zero(arena->v[0], U8, image_data.size); ProfEnd(); @@ -4522,6 +4540,17 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT task.u.image_fill.fill_nodes = fill_nodes; tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_image_fill_task, &task, "Fill"); + if (image_string_table.total_size) { + ProfBegin("Copy String Table"); + String8 buffer = str8_list_join(scratch.arena, &image_string_table, 0); + MemoryCopy(image_data.str + (image_data.size - buffer.size), buffer.str, buffer.size); + ProfEnd(); + + // patch string table offset + COFF_FileHeader *file_header = (COFF_FileHeader *)(image_data.str + image_file_header_off); + file_header->symbol_table_foff = safe_cast_u32(image_data.size - buffer.size); + } + temp_end(temp); ProfEnd(); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index d565e023..8ef2d4cf 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -378,7 +378,7 @@ internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *c 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 String8 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 String8List lnk_build_win32_image_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sect_arr, U64 expected_image_header_size, U64 *file_header_offset_out, String8List *string_table_out); internal LNK_ImageContext lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, LNK_Obj **objs); // --- Logger ------------------------------------------------------------------ diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index 21040f40..c6909da1 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -3909,6 +3909,38 @@ T_BeginTest(fail_if_mismatch) } T_EndTest; +T_BeginTest(long_section_name) +{ + Arch arch = Arch_x64; + + COFF_ObjWriter *cow = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { 0xc3 }; + COFF_ObjSection *text_sect = coff_obj_writer_push_section(cow, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_section(cow, str8_lit(".debug_info"), PE_DATA_SECTION_FLAGS, str8_lit("DEBUG_INFO")); + coff_obj_writer_push_section(cow, str8_lit(".debug_abbrev"), PE_DATA_SECTION_FLAGS, str8_lit("DEBUG_ABBREV")); + coff_obj_writer_push_symbol_extern(cow, str8_lit("entry"), 0, text_sect); + String8 raw_coff = coff_obj_writer_serialize(scratch.arena, cow); + coff_obj_writer_release(&cow); + + // link test.obj + T_Ok(t_write_file(str8_lit("test.obj"), raw_coff)); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe test.obj"); + T_Ok(g_last_exit_code == 0); + + // load linked exe + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + + COFF_SectionHeader *debug_info = coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".debug_info")); + T_Ok(debug_info); + + COFF_SectionHeader *debug_abbrev = coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".debug_abbrev")); + T_Ok(debug_abbrev); +} +T_EndTest; + #if 0 T_BeginTest(fold_two_funcs)