use string table extension for long section names

This commit is contained in:
Nikita Smith
2026-02-05 19:45:35 -08:00
parent 010f54674f
commit 71a46985b6
3 changed files with 68 additions and 7 deletions
+35 -6
View File
@@ -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();
+1 -1
View File
@@ -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 ------------------------------------------------------------------
+32
View File
@@ -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)