point TLS directory to TLS header

This commit is contained in:
Nikita Smith
2025-06-25 10:53:23 -07:00
committed by Ryan Fleury
parent 3d2b1e19e3
commit 86556c68ed
4 changed files with 67 additions and 61 deletions
+25 -32
View File
@@ -3062,7 +3062,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
U32 load_config_size = 0; U32 load_config_size = 0;
if (sizeof(load_config_size) <= load_config_data.size) { if (sizeof(load_config_size) <= load_config_data.size) {
PE_DataDirectory *load_config_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_LOAD_CONFIG, sizeof(PE_DataDirectory)); PE_DataDirectory *load_config_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_LOAD_CONFIG);
load_config_dir->virt_off = lnk_virt_off_from_symbol(image_section_table, load_config_symbol); load_config_dir->virt_off = lnk_virt_off_from_symbol(image_section_table, load_config_symbol);
load_config_dir->virt_size = load_config_size; load_config_dir->virt_size = load_config_size;
} else { } else {
@@ -3091,7 +3091,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
} }
ProfEnd(); ProfEnd();
PE_DataDirectory *pdata_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, sizeof(PE_DataDirectory)); PE_DataDirectory *pdata_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_EXCEPTIONS);
pdata_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, pdata_sect); pdata_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, pdata_sect);
pdata_dir->virt_size = lnk_get_section_contrib_size(pdata_sect); pdata_dir->virt_size = lnk_get_section_contrib_size(pdata_sect);
} }
@@ -3101,7 +3101,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
{ {
LNK_Section *edata_sect = lnk_section_table_search(sectab, str8_lit(".edata"), PE_EDATA_SECTION_FLAGS); LNK_Section *edata_sect = lnk_section_table_search(sectab, str8_lit(".edata"), PE_EDATA_SECTION_FLAGS);
if (edata_sect) { if (edata_sect) {
PE_DataDirectory *export_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXPORT, sizeof(PE_DataDirectory)); PE_DataDirectory *export_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_EXPORT);
LNK_SectionContrib *edata_first_contrib = lnk_get_first_section_contrib(edata_sect); LNK_SectionContrib *edata_first_contrib = lnk_get_first_section_contrib(edata_sect);
LNK_SectionContrib *edata_last_contrib = lnk_get_last_section_contrib(edata_sect); LNK_SectionContrib *edata_last_contrib = lnk_get_last_section_contrib(edata_sect);
export_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, edata_sect); export_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, edata_sect);
@@ -3113,7 +3113,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
{ {
LNK_Section *reloc_sect = lnk_section_table_search(sectab, str8_lit(".reloc"), PE_RELOC_SECTION_FLAGS); LNK_Section *reloc_sect = lnk_section_table_search(sectab, str8_lit(".reloc"), PE_RELOC_SECTION_FLAGS);
if (reloc_sect) { if (reloc_sect) {
PE_DataDirectory *reloc_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_BASE_RELOC, sizeof(PE_DataDirectory)); PE_DataDirectory *reloc_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_BASE_RELOC);
reloc_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, reloc_sect); reloc_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, reloc_sect);
reloc_dir->virt_size = lnk_get_section_contrib_size(reloc_sect); reloc_dir->virt_size = lnk_get_section_contrib_size(reloc_sect);
} }
@@ -3127,7 +3127,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
if (idata_sect && null_import_desc && null_thunk_data) { if (idata_sect && null_import_desc && null_thunk_data) {
COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx);
LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect); LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect);
PE_DataDirectory *import_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_IMPORT, sizeof(PE_DataDirectory)); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_IMPORT);
import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff + idata_first_contrib->u.off; import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff + idata_first_contrib->u.off;
import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off; import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off;
@@ -3135,7 +3135,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
U64 null_thunk_data_voff = image_section_table[null_thunk_data_parsed.section_number]->voff + null_thunk_data_parsed.value; U64 null_thunk_data_voff = image_section_table[null_thunk_data_parsed.section_number]->voff + null_thunk_data_parsed.value;
U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff + idata_first_contrib->u.off; U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff + idata_first_contrib->u.off;
PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import)); PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import));
PE_DataDirectory *import_addr_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_IMPORT_ADDR, sizeof(PE_DataDirectory)); PE_DataDirectory *import_addr_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_IMPORT_ADDR);
import_addr_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, idata_sect); import_addr_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, idata_sect);
import_addr_dir->virt_size = null_thunk_data_voff - first_import->import_addr_table_voff /* null */ + coff_word_size_from_machine(config->machine); import_addr_dir->virt_size = null_thunk_data_voff - first_import->import_addr_table_voff /* null */ + coff_word_size_from_machine(config->machine);
} }
@@ -3149,61 +3149,54 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
if (didat_sect && null_import_desc && last_null_thunk) { if (didat_sect && null_import_desc && last_null_thunk) {
COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx);
LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect); LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect);
PE_DataDirectory *import_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DELAY_IMPORT, sizeof(PE_DataDirectory)); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_DELAY_IMPORT);
Assert(null_import_desc_parsed.section_number == didat_first_contrib->u.sect_idx+1);
Assert(null_import_desc_parsed.value >= didat_first_contrib->u.off);
import_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, didat_sect); import_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, didat_sect);
import_dir->virt_size = lnk_get_section_contrib_size(didat_sect); import_dir->virt_size = lnk_get_section_contrib_size(didat_sect);
} }
} }
// patch TLS // patch TLS
{
LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, LNK_TLS_SYMBOL_NAME); LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, LNK_TLS_SYMBOL_NAME);
if (tls_used_symbol) { if (tls_used_symbol) {
ProfBegin("Patch TLS Align"); ProfBegin("Patch TLS");
// loop over .tls sections and extract max alignment // find max align in .tls
LNK_Section *tls_sect = lnk_section_table_search(sectab, str8_lit(".tls"), PE_RDATA_SECTION_FLAGS);
U64 tls_align = 0; U64 tls_align = 0;
LNK_Section *tls_sect = lnk_section_table_search(sectab, str8_lit(".tls"), PE_TLS_SECTION_FLAGS);
for (LNK_SectionContribChunk *sc_chunk = tls_sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) { for (LNK_SectionContribChunk *sc_chunk = tls_sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) { for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
LNK_SectionContrib *sc = sc_chunk->v[sc_idx]; Assert(IsPow2(sc_chunk->v[sc_idx]->align));
tls_align = Max(tls_align, sc->align); tls_align = Max(tls_align, sc_chunk->v[sc_idx]->align);
} }
} }
if (IsPow2(tls_align)) { // patch-in align
// compute TLS header offset
U64 tls_header_foff = lnk_file_off_from_symbol(image_section_table, tls_used_symbol); U64 tls_header_foff = lnk_file_off_from_symbol(image_section_table, tls_used_symbol);
B32 is_tls_header64 = coff_word_size_from_machine(config->machine) == 8;
// patch TLS header if (is_tls_header64) {
if (coff_word_size_from_machine(config->machine) == 8) { PE_TLSHeader64 *tls_header = str8_deserial_get_raw_ptr(image_data, tls_header_foff, sizeof(*tls_header));
String8 raw_tls_used = str8_substr(image_data, rng_1u64(tls_header_foff, tls_header_foff + sizeof(PE_TLSHeader64)));
PE_TLSHeader64 *tls_header = (PE_TLSHeader64 *) raw_tls_used.str;
tls_header->characteristics |= coff_section_flag_from_align_size(tls_align); tls_header->characteristics |= coff_section_flag_from_align_size(tls_align);
} else { } else {
String8 raw_tls_used = str8_substr(image_data, rng_1u64(tls_header_foff, tls_header_foff + sizeof(PE_TLSHeader32))); PE_TLSHeader32 *tls_header = str8_deserial_get_raw_ptr(image_data, tls_header_foff, sizeof(*tls_header));
PE_TLSHeader32 *tls_header = (PE_TLSHeader32 *) raw_tls_used.str;
tls_header->characteristics |= coff_section_flag_from_align_size(tls_align); tls_header->characteristics |= coff_section_flag_from_align_size(tls_align);
} }
} else {
lnk_error(LNK_Warning_TLSAlign, "unable to patch TLS Header characteristics, alignment must be power of two, align inferred from section flags: %llu", tls_align);
}
PE_DataDirectory *tls_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, sizeof(PE_DataDirectory)); // patch directory
tls_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, tls_sect); PE_DataDirectory *tls_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_TLS);
tls_dir->virt_size = lnk_get_section_contrib_size(tls_sect); tls_dir->virt_off = lnk_virt_off_from_symbol(image_section_table, tls_used_symbol);
tls_dir->virt_size = is_tls_header64 ? sizeof(PE_TLSHeader64) : sizeof(PE_TLSHeader32);
ProfEnd(); ProfEnd();
} }
}
// patch debug // patch debug
{ {
LNK_Section *debug_dir_sect = lnk_section_table_search(sectab, str8_lit(".RAD_LINK_PE_DEBUG_DIR"), PE_RDATA_SECTION_FLAGS); LNK_Section *debug_dir_sect = lnk_section_table_search(sectab, str8_lit(".RAD_LINK_PE_DEBUG_DIR"), PE_RDATA_SECTION_FLAGS);
if (debug_dir_sect) { if (debug_dir_sect) {
// patch directory // patch directory
PE_DataDirectory *debug_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, sizeof(PE_DataDirectory)); PE_DataDirectory *debug_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_DEBUG);
debug_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, debug_dir_sect); debug_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, debug_dir_sect);
debug_dir->virt_size = lnk_get_section_contrib_size(debug_dir_sect); debug_dir->virt_size = lnk_get_section_contrib_size(debug_dir_sect);
@@ -3229,7 +3222,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
{ {
LNK_Section *rsrc_sect = lnk_section_table_search(sectab, str8_lit(".rsrc"), PE_RSRC_SECTION_FLAGS); LNK_Section *rsrc_sect = lnk_section_table_search(sectab, str8_lit(".rsrc"), PE_RSRC_SECTION_FLAGS);
if (rsrc_sect) { if (rsrc_sect) {
PE_DataDirectory *rsrc_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_RESOURCES, sizeof(PE_DataDirectory)); PE_DataDirectory *rsrc_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_RESOURCES);
rsrc_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, rsrc_sect); rsrc_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, rsrc_sect);
rsrc_dir->virt_size = lnk_get_section_contrib_size(rsrc_sect); rsrc_dir->virt_size = lnk_get_section_contrib_size(rsrc_sect);
} }
+10
View File
@@ -650,6 +650,16 @@ pe_bin_info_from_data(Arena *arena, String8 data)
return info; return info;
} }
internal PE_DataDirectory *
pe_data_directory_from_idx(String8 file_data, PE_BinInfo pe, PE_DataDirectoryIndex dir_idx)
{
PE_DataDirectory *result = 0;
if (dir_idx < pe.data_dir_count) {
result = str8_deserial_get_raw_ptr(file_data, pe.data_dir_range.min + sizeof(*result)*dir_idx, sizeof(*result));
}
return result;
}
internal PE_DebugInfoList internal PE_DebugInfoList
pe_debug_info_list_from_raw_debug_dir(Arena *arena, String8 raw_image, String8 raw_debug_dir) pe_debug_info_list_from_raw_debug_dir(Arena *arena, String8 raw_image, String8 raw_debug_dir)
{ {
+2
View File
@@ -1062,6 +1062,8 @@ internal String8 pe_string_from_dll_characteristics(Arena *arena, PE_DllCharacte
internal B32 pe_check_magic(String8 data); internal B32 pe_check_magic(String8 data);
internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data); internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data);
internal PE_DataDirectory * pe_data_directory_from_idx(String8 file_data, PE_BinInfo pe, PE_DataDirectoryIndex dir_idx);
internal PE_DebugInfoList pe_parse_debug_directory(Arena *arena, String8 raw_image, String8 raw_debug_dir);
internal PE_DebugInfoList pe_debug_info_list_from_raw_debug_dir(Arena *arena, String8 raw_image, String8 raw_debug_dir); internal PE_DebugInfoList pe_debug_info_list_from_raw_debug_dir(Arena *arena, String8 raw_image, String8 raw_debug_dir);
internal PE_ParsedStaticImportTable pe_static_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range); internal PE_ParsedStaticImportTable pe_static_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range);
internal PE_ParsedDelayImportTable pe_delay_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range); internal PE_ParsedDelayImportTable pe_delay_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range);
+1
View File
@@ -22,6 +22,7 @@
#define PE_GEHCONT_SECTION_FLAGS PE_RDATA_SECTION_FLAGS #define PE_GEHCONT_SECTION_FLAGS PE_RDATA_SECTION_FLAGS
#define PE_RELOC_SECTION_FLAGS (PE_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable) #define PE_RELOC_SECTION_FLAGS (PE_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
#define PE_DEBUG_SECTION_FLAGS (PE_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable) #define PE_DEBUG_SECTION_FLAGS (PE_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
#define PE_TLS_SECTION_FLAGS PE_DATA_SECTION_FLAGS
#endif // PE_SECTION_FLAGS_H #endif // PE_SECTION_FLAGS_H