mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-07-28 02:10:13 +00:00
Initial implementation of the symbol table allowed us to push symbols from one thread at a time and required a wonky lock-step and spread out logic for replacing symbols. And because it was a externally chained hash table we had to guesstimate optimal capacity for small and big targets. We erred on the side of larger capacity to prevent degradation and rehashing, however this meant small targets had to spent unreasonable amount of time memory allocing slots. With hash trie we can dynamically scale up to 4 ^ 32 items and atomically replace symbols when needed. Neat!
764 lines
38 KiB
C
764 lines
38 KiB
C
// Copyright (c) 2024 Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
internal LNK_ImportTable *
|
|
lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
LNK_Section *data_sect = lnk_section_table_push(st, str8_lit(".idata"), LNK_IDATA_SECTION_FLAGS);
|
|
LNK_Section *code_sect = lnk_section_table_search(st, str8_lit(".text"));
|
|
|
|
LNK_Chunk *dll_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *int_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *iat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *ilt_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, code_sect->root, str8_zero());
|
|
|
|
LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_ImportEntry)), str8_lit("zzzzz"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR");
|
|
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
|
|
|
|
Arena *arena = arena_alloc();
|
|
LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1);
|
|
imptab->machine = machine;
|
|
imptab->arena = arena;
|
|
imptab->data_sect = data_sect;
|
|
imptab->code_sect = code_sect;
|
|
imptab->dll_table_chunk = dll_table_chunk;
|
|
imptab->int_chunk = int_chunk;
|
|
imptab->iat_chunk = iat_chunk;
|
|
imptab->ilt_chunk = ilt_chunk;
|
|
imptab->code_chunk = code_chunk;
|
|
imptab->dll_ht = hash_table_init(arena, LNK_IMPORT_DLL_HASH_TABLE_BUCKET_COUNT);
|
|
|
|
ProfEnd();
|
|
return imptab;
|
|
}
|
|
|
|
internal LNK_ImportTable *
|
|
lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
LNK_Section *data_sect = lnk_section_table_push(st, str8_lit(".didat"), LNK_DEBUG_DIR_SECTION_FLAGS);
|
|
LNK_Section *code_sect = lnk_section_table_search(st, str8_lit(".text"));
|
|
|
|
LNK_Chunk *dll_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *int_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *handle_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *iat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *ilt_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *biat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *uiat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero());
|
|
LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, code_sect->root, str8_zero());
|
|
|
|
LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_DelayedImportEntry)), str8_lit("~0"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR");
|
|
|
|
if (is_unloadable) {
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
LNK_Chunk *null_uiat_chunk = lnk_section_push_chunk_bss(data_sect, uiat_chunk, import_size, str8_lit("~1"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_uiat_chunk, "UIAT_TERMINATOR");
|
|
}
|
|
|
|
if (is_bindable) {
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
LNK_Chunk *null_biat_chunk = lnk_section_push_chunk_bss(data_sect, biat_chunk, import_size, str8_lit("~2"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_biat_chunk, "BIAT_TERMINATOR");
|
|
}
|
|
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0);
|
|
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
|
|
|
|
LNK_ImportTableFlags flags = 0;
|
|
if (is_unloadable) {
|
|
flags |= LNK_ImportTableFlag_EmitUiat;
|
|
}
|
|
if (is_bindable) {
|
|
flags |= LNK_ImportTableFlag_EmitBiat;
|
|
}
|
|
|
|
Arena *arena = arena_alloc();
|
|
LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1);
|
|
imptab->arena = arena;
|
|
imptab->machine = machine;
|
|
imptab->data_sect = data_sect;
|
|
imptab->code_sect = code_sect;
|
|
imptab->dll_table_chunk = dll_table_chunk;
|
|
imptab->int_chunk = int_chunk;
|
|
imptab->handle_table_chunk = handle_table_chunk;
|
|
imptab->iat_chunk = iat_chunk;
|
|
imptab->ilt_chunk = ilt_chunk;
|
|
imptab->biat_chunk = biat_chunk;
|
|
imptab->uiat_chunk = uiat_chunk;
|
|
imptab->code_chunk = code_chunk;
|
|
imptab->flags = flags;
|
|
imptab->dll_ht = hash_table_init(arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT);
|
|
|
|
ProfEnd();
|
|
return imptab;
|
|
}
|
|
|
|
internal void
|
|
lnk_import_table_release(LNK_ImportTable **imptab_ptr)
|
|
{
|
|
ProfBeginFunction();
|
|
arena_release((*imptab_ptr)->arena);
|
|
*imptab_ptr = 0;
|
|
ProfEnd();
|
|
}
|
|
|
|
internal BucketNode *
|
|
lnk_import_table_push_dll_node(LNK_ImportTable *imptab, LNK_ImportDLL *dll)
|
|
{
|
|
// update list
|
|
SLLQueuePush(imptab->first_dll, imptab->last_dll, dll);
|
|
|
|
// update name -> dll hash table
|
|
return hash_table_push_path_raw(imptab->arena, imptab->dll_ht, dll->name, dll);
|
|
}
|
|
|
|
internal BucketNode *
|
|
lnk_import_table_push_func_node(LNK_ImportTable *imptab, LNK_ImportDLL *dll, LNK_ImportFunc *func)
|
|
{
|
|
// update list
|
|
SLLQueuePush(dll->first_func, dll->last_func, func);
|
|
|
|
// update name -> func hash table
|
|
return hash_table_push_string_raw(imptab->arena, dll->func_ht, func->name, func);
|
|
}
|
|
|
|
internal LNK_ImportDLL *
|
|
lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name)
|
|
{
|
|
KeyValuePair *kv = hash_table_search_path(imptab->dll_ht, name);
|
|
if (kv) {
|
|
Assert(kv->value_raw);
|
|
return kv->value_raw;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
internal LNK_ImportFunc *
|
|
lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name)
|
|
{
|
|
KeyValuePair *kv = hash_table_search_string(dll->func_ht, name);
|
|
if (kv) {
|
|
Assert(kv->value_raw);
|
|
return kv->value_raw;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
internal LNK_ImportDLL *
|
|
lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
// TODO: error handle
|
|
Assert(imptab->machine == machine);
|
|
|
|
LNK_Section *data_sect = imptab->data_sect;
|
|
LNK_Section *code_sect = imptab->code_sect;
|
|
|
|
LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, str8_zero());
|
|
LNK_Chunk *ilt_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->ilt_chunk, str8_zero());
|
|
LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero());
|
|
LNK_Chunk *code_table_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero());
|
|
|
|
String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.lookup_table_voff", dll_name);
|
|
LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0);
|
|
|
|
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "%S.import_addr_table_voff", dll_name);
|
|
LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
|
|
|
|
String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name);
|
|
LNK_Chunk *dll_name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, dll_name_cstr, str8_zero());
|
|
lnk_chunk_set_debugf(data_sect->arena, dll_name_chunk, "DLL name chunk (%S)", dll_name);
|
|
|
|
String8 dll_name_voff_name = push_str8f(symtab->arena->v[0], "%S.name_voff", dll_name);
|
|
LNK_Symbol *dll_name_voff_symbol = lnk_symbol_table_push_defined_chunk(symtab, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0);
|
|
|
|
// chunk for dll directory entry
|
|
PE_ImportEntry *dir = push_array(imptab->arena, PE_ImportEntry, 1);
|
|
LNK_Chunk *dll_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, str8_struct(dir), str8_zero());
|
|
lnk_chunk_set_debugf(data_sect->arena, dll_chunk, "DLL Directory for %S", dll_name);
|
|
|
|
// patch dll import fields
|
|
lnk_section_push_reloc(data_sect, dll_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ImportEntry, lookup_table_voff), ilt_symbol);
|
|
lnk_section_push_reloc(data_sect, dll_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ImportEntry, name_voff), dll_name_voff_symbol);
|
|
lnk_section_push_reloc(data_sect, dll_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ImportEntry, import_addr_table_voff), iat_symbol);
|
|
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
|
|
// null entry to terminate import lookup table array
|
|
LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, str8(0, import_size), str8_lit("zzzzzz"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name);
|
|
|
|
// null entry to terminate import address table array
|
|
LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, str8(0, import_size), str8_lit("zzzzzz"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name);
|
|
|
|
// push to list
|
|
LNK_ImportDLL *dll = push_array(imptab->arena, LNK_ImportDLL, 1);
|
|
dll->name = push_str8_copy(imptab->arena, dll_name);
|
|
dll->dll_chunk = dll_chunk;
|
|
dll->int_table_chunk = int_table_chunk;
|
|
dll->ilt_table_chunk = ilt_table_chunk;
|
|
dll->iat_table_chunk = iat_table_chunk;
|
|
dll->code_table_chunk = code_table_chunk;
|
|
dll->machine = machine;
|
|
dll->func_ht = hash_table_init(imptab->arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT);
|
|
|
|
lnk_import_table_push_dll_node(imptab, dll);
|
|
|
|
ProfEnd();
|
|
return dll;
|
|
}
|
|
|
|
internal LNK_ImportDLL *
|
|
lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
Assert(imptab->machine == machine);
|
|
|
|
U64 handle_size = coff_word_size_from_machine(machine);
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
|
|
// shortcuts
|
|
LNK_Section *data_sect = imptab->data_sect;
|
|
LNK_Section *code_sect = imptab->code_sect;
|
|
|
|
// init DLL entry
|
|
PE_DelayedImportEntry *imp_desc = push_array(data_sect->arena, PE_DelayedImportEntry, 1);
|
|
imp_desc->attributes = 1;
|
|
imp_desc->name_voff = 0; // relocated
|
|
imp_desc->module_handle_voff = 0; // relocated
|
|
imp_desc->iat_voff = 0; // relocated
|
|
imp_desc->name_table_voff = 0; // relocated
|
|
imp_desc->bound_table_voff = 0; // relocated
|
|
imp_desc->unload_table_voff = 0; // relocated
|
|
imp_desc->time_stamp = 0;
|
|
|
|
// emit entry chunk
|
|
String8 imp_desc_data = str8_struct(imp_desc);
|
|
LNK_Chunk *imp_desc_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, imp_desc_data, str8_zero());
|
|
|
|
// emit entry symbol
|
|
String8 imp_desc_name = push_str8f(symtab->arena->v[0], "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name);
|
|
LNK_Symbol *imp_desc_symbol = lnk_symbol_table_push_defined_chunk(symtab, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0);
|
|
|
|
// emit string table chunk
|
|
String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name);
|
|
LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug);
|
|
|
|
String8 int_table_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.int", dll_name);
|
|
LNK_Symbol *int_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0);
|
|
|
|
LNK_Chunk *null_string_chunk = lnk_section_push_chunk_list(data_sect, int_table_chunk, str8_lit("zzzzz"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "string table null");
|
|
|
|
// emit DLL name chunk
|
|
String8 name_chunk_data = push_cstr(data_sect->arena, dll_name);
|
|
LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero());
|
|
|
|
String8 name_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.name", dll_name);
|
|
LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
|
|
|
|
// patch DLL name voff
|
|
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_voff), name_symbol);
|
|
|
|
// emit DLL handle chunk
|
|
LNK_Chunk *handle_chunk = lnk_section_push_chunk_bss(data_sect, imptab->handle_table_chunk, handle_size, str8_zero());
|
|
|
|
String8 handle_name = push_str8f(symtab->arena->v[0], "delayed.%S.handle", dll_name);
|
|
LNK_Symbol *handle_symbol = lnk_symbol_table_push_defined_chunk(symtab, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0);
|
|
|
|
// patch DLL handle voff
|
|
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol);
|
|
|
|
// emit IAT chunk
|
|
LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero());
|
|
|
|
String8 iat_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.iat", dll_name);
|
|
LNK_Symbol *iat_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
|
|
|
|
LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, str8_lit("zzzzzz"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name);
|
|
|
|
// emit ILT chunk
|
|
LNK_Chunk *ilt_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->ilt_chunk, str8_zero());
|
|
|
|
LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, str8_lit("zzzzzz"));
|
|
lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name);
|
|
|
|
String8 ilt_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.ilt", dll_name);
|
|
LNK_Symbol *ilt_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0);
|
|
|
|
// patch import address table voff
|
|
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_table_symbol);
|
|
|
|
// patch string table voff
|
|
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_table_voff), ilt_table_symbol);
|
|
|
|
// emit bound table chunk
|
|
LNK_Chunk *biat_chunk = 0;
|
|
if (imptab->flags & LNK_ImportTableFlag_EmitBiat) {
|
|
biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero());
|
|
|
|
String8 biat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.BIAT", dll_name);
|
|
LNK_Symbol *biat_symbol = lnk_symbol_table_push_defined_chunk(symtab, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0);
|
|
|
|
// patch BIAT field off
|
|
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol);
|
|
}
|
|
|
|
// emit unload table chunk
|
|
LNK_Chunk *uiat_chunk = NULL;
|
|
if (imptab->flags & LNK_ImportTableFlag_EmitUiat) {
|
|
uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero());
|
|
|
|
String8 uiat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.UIAT", dll_name);
|
|
LNK_Symbol *uiat_symbol = lnk_symbol_table_push_defined_chunk(symtab, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0);
|
|
|
|
// patch UIAT field voff
|
|
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol);
|
|
}
|
|
|
|
// emit chunk for DLL thunk/load code
|
|
LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero());
|
|
lnk_chunk_set_debugf(code_sect->arena, code_chunk, "code for %S", dll_name);
|
|
|
|
// emit tail merge
|
|
LNK_Chunk *tail_merge_chunk = 0;
|
|
switch (machine) {
|
|
case COFF_MachineType_X64: {
|
|
LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main);
|
|
tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol);
|
|
} break;
|
|
default: {
|
|
lnk_not_implemented("TODO: __tailMerge for %S", coff_string_from_machine_type(machine));
|
|
} break;
|
|
}
|
|
|
|
// fill out result
|
|
LNK_ImportDLL *dll = push_array(imptab->arena, LNK_ImportDLL, 1);
|
|
dll->dll_chunk = imp_desc_chunk;
|
|
dll->int_table_chunk = int_table_chunk;
|
|
dll->iat_table_chunk = iat_table_chunk;
|
|
dll->ilt_table_chunk = ilt_table_chunk;
|
|
dll->biat_table_chunk = biat_chunk;
|
|
dll->uiat_table_chunk = uiat_chunk;
|
|
dll->code_table_chunk = code_chunk;
|
|
dll->tail_merge_symbol = lnk_emit_tail_merge_symbol(symtab, tail_merge_chunk, dll_name);
|
|
dll->name = push_str8_copy(imptab->arena, dll_name);
|
|
dll->machine = machine;
|
|
dll->func_ht = hash_table_init(imptab->arena, LNK_IMPORT_FUNC_HASH_TABLE_BUCKET_COUNT);
|
|
|
|
lnk_import_table_push_dll_node(imptab, dll);
|
|
|
|
ProfEnd();
|
|
return dll;
|
|
}
|
|
|
|
internal LNK_ImportFunc *
|
|
lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
Assert(header->machine == dll->machine); // TODO: error handling
|
|
|
|
LNK_Section *data_sect = imptab->data_sect;
|
|
LNK_Section *code_sect = imptab->code_sect;
|
|
|
|
LNK_Chunk *int_table_chunk = dll->int_table_chunk;
|
|
LNK_Chunk *ilt_table_chunk = dll->ilt_table_chunk;
|
|
LNK_Chunk *iat_table_chunk = dll->iat_table_chunk;
|
|
LNK_Chunk *code_table_chunk = dll->code_table_chunk;
|
|
|
|
LNK_Chunk *ilt_chunk = g_null_chunk_ptr;
|
|
LNK_Chunk *iat_chunk = g_null_chunk_ptr;
|
|
|
|
U64 import_size = coff_word_size_from_machine(dll->machine);
|
|
|
|
// generate sort index (optional)
|
|
String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint);
|
|
|
|
switch (header->name_type) {
|
|
case COFF_ImportHeaderNameType_ORDINAL: {
|
|
String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint);
|
|
ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index);
|
|
iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, ordinal_data, sort_index);
|
|
|
|
// associate chunks
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk);
|
|
} break;
|
|
case COFF_ImportHeaderNameType_NAME: {
|
|
// put together name look up entry
|
|
String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint, header->func_name);
|
|
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
|
|
|
|
// create symbol for lookup chunk
|
|
String8 int_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.name", dll->name, header->func_name);
|
|
LNK_Symbol *int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
|
|
|
|
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
|
|
ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
|
|
iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index);
|
|
lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "ILT entry for %S.%S", dll->name, header->func_name);
|
|
lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IAT entry for %S.%S", dll->name, header->func_name);
|
|
|
|
// associate chunks
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk);
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, int_chunk);
|
|
|
|
// patch IAT and ILT
|
|
lnk_section_push_reloc(data_sect, ilt_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol);
|
|
lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol);
|
|
} break;
|
|
case COFF_ImportHeaderNameType_UNDECORATE: {
|
|
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_UNDECORATE");
|
|
} break;
|
|
case COFF_ImportHeaderNameType_NAME_NOPREFIX: {
|
|
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_NAME_NOPREFIX");
|
|
} break;
|
|
}
|
|
|
|
String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.ilt", dll->name, header->func_name);
|
|
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
|
|
LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
|
|
LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
|
|
|
|
// generate thunks
|
|
LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr;
|
|
if (header->type == COFF_ImportHeaderType_CODE) {
|
|
switch (dll->machine) {
|
|
case COFF_MachineType_X64: {
|
|
// generate jump thunk
|
|
LNK_Chunk *jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol);
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk);
|
|
|
|
// push jump thunk symbol
|
|
String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena->v[0], header->func_name);
|
|
jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, jmp_thunk_symbol_name);
|
|
} break;
|
|
default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
|
|
}
|
|
}
|
|
|
|
// fill out import
|
|
LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1);
|
|
func->name = push_str8_copy(imptab->arena, header->func_name);
|
|
func->thunk_symbol_name = push_str8_copy(imptab->arena, jmp_thunk_symbol->name);
|
|
func->iat_symbol_name = push_str8_copy(imptab->arena, iat_symbol->name);
|
|
|
|
lnk_import_table_push_func_node(imptab, dll, func);
|
|
|
|
ProfEnd();
|
|
return func;
|
|
}
|
|
|
|
internal LNK_ImportFunc *
|
|
lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
Assert(dll->machine == header->machine); // TODO: error handle
|
|
|
|
U64 import_size = coff_word_size_from_machine(dll->machine);
|
|
|
|
LNK_Section *data_sect = imptab->data_sect;
|
|
LNK_Section *code_sect = imptab->code_sect;
|
|
|
|
LNK_Chunk *int_table_chunk = dll->int_table_chunk;
|
|
LNK_Chunk *ilt_table_chunk = dll->ilt_table_chunk;
|
|
LNK_Chunk *iat_table_chunk = dll->iat_table_chunk;
|
|
LNK_Chunk *biat_table_chunk = dll->biat_table_chunk;
|
|
LNK_Chunk *uiat_table_chunk = dll->uiat_table_chunk;
|
|
LNK_Chunk *code_table_chunk = dll->code_table_chunk;
|
|
|
|
LNK_Chunk *ilt_chunk = g_null_chunk_ptr;
|
|
LNK_Chunk *iat_chunk = g_null_chunk_ptr;
|
|
LNK_Chunk *uiat_chunk = g_null_chunk_ptr;
|
|
LNK_Chunk *biat_chunk = g_null_chunk_ptr;
|
|
|
|
LNK_Symbol *int_symbol = 0;
|
|
|
|
// generate sort index (optional)
|
|
String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint);
|
|
|
|
// generate thunks
|
|
LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr;
|
|
LNK_Symbol *load_thunk_symbol = g_null_symbol_ptr;
|
|
LNK_Chunk *jmp_thunk_chunk = 0;
|
|
LNK_Chunk *load_thunk_chunk = 0;
|
|
if (header->type == COFF_ImportHeaderType_CODE) {
|
|
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);
|
|
|
|
// emit jmp thunk chunk
|
|
jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol);
|
|
jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, header->func_name);
|
|
|
|
// emit load thunk
|
|
load_thunk_chunk = lnk_emit_load_thunk_x64(code_sect, code_table_chunk, iat_symbol, dll->tail_merge_symbol);
|
|
load_thunk_symbol = lnk_emit_load_thunk_symbol(symtab, load_thunk_chunk, header->func_name);
|
|
} break;
|
|
default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
|
|
}
|
|
}
|
|
|
|
switch (header->name_type) {
|
|
case COFF_ImportHeaderNameType_ORDINAL: {
|
|
String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint);
|
|
Assert(ordinal_data.size == import_size);
|
|
ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index);
|
|
iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index);
|
|
lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
|
|
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk);
|
|
if (imptab->flags & LNK_ImportTableFlag_EmitBiat) {
|
|
biat_chunk = lnk_section_push_chunk_bss(data_sect, biat_table_chunk, import_size, sort_index);
|
|
lnk_section_push_reloc(data_sect, biat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, biat_chunk);
|
|
}
|
|
if (imptab->flags & LNK_ImportTableFlag_EmitUiat) {
|
|
uiat_chunk = lnk_section_push_chunk_bss(data_sect, uiat_table_chunk, import_size, sort_index);
|
|
lnk_section_push_reloc(data_sect, uiat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, uiat_chunk);
|
|
}
|
|
} break;
|
|
case COFF_ImportHeaderNameType_NAME: {
|
|
// put together name look up entry
|
|
String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint, header->func_name);
|
|
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
|
|
|
|
// create symbol for lookup chunk
|
|
String8 int_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.name.delayed", dll->name, header->func_name);
|
|
int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
|
|
|
|
// dynamic linker patches this voff on DLL load event
|
|
ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
|
|
lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "ILT entry (delayed) %S.%S", dll->name, header->func_name);
|
|
|
|
// patch-in ILT with import voff
|
|
lnk_section_push_reloc(data_sect, ilt_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol);
|
|
|
|
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
|
|
iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index);
|
|
lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IAT entre (delayed) %S.%S", dll->name, header->func_name);
|
|
|
|
// associate chunks
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk);
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, int_chunk);
|
|
|
|
// patch-in thunk address
|
|
lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
|
|
|
|
if (imptab->flags & LNK_ImportTableFlag_EmitBiat) {
|
|
biat_chunk = lnk_section_push_chunk_bss(data_sect, biat_table_chunk, import_size, sort_index);
|
|
lnk_chunk_set_debugf(data_sect->arena, biat_chunk, "%S.biat.%S (delayed)", dll->name, header->func_name);
|
|
|
|
// patch-in thunk address
|
|
lnk_section_push_reloc(data_sect, biat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
|
|
}
|
|
|
|
if (imptab->flags & LNK_ImportTableFlag_EmitUiat) {
|
|
uiat_chunk = lnk_section_push_chunk_bss(data_sect, uiat_table_chunk, import_size, sort_index);
|
|
lnk_chunk_set_debugf(data_sect->arena, uiat_chunk, "%S.uiat.%S (delayed)", dll->name, header->func_name);
|
|
|
|
// patch-in thunk address
|
|
lnk_section_push_reloc(data_sect, uiat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
|
|
}
|
|
} break;
|
|
case COFF_ImportHeaderNameType_UNDECORATE: {
|
|
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_UNDECORATE");
|
|
} break;
|
|
case COFF_ImportHeaderNameType_NAME_NOPREFIX: {
|
|
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_NAME_NOPREFIX");
|
|
} break;
|
|
}
|
|
|
|
if (jmp_thunk_chunk) {
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk);
|
|
}
|
|
if (load_thunk_chunk) {
|
|
lnk_section_associate_chunks(data_sect, iat_chunk, load_thunk_chunk);
|
|
}
|
|
|
|
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
|
|
LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
|
|
|
|
String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.ilt.delayed", dll->name, header->func_name);
|
|
LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
|
|
|
|
// fill out import
|
|
LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1);
|
|
func->name = push_str8_copy(imptab->arena, header->func_name);
|
|
func->thunk_symbol_name = push_str8_copy(imptab->arena, jmp_thunk_symbol->name);
|
|
func->iat_symbol_name = push_str8_copy(imptab->arena, iat_symbol->name);
|
|
|
|
lnk_import_table_push_func_node(imptab, dll, func);
|
|
|
|
ProfEnd();
|
|
return func;
|
|
}
|
|
|
|
internal String8
|
|
lnk_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint)
|
|
{
|
|
String8 ordinal_data = str8_zero();
|
|
switch (machine) {
|
|
case COFF_MachineType_X64: {
|
|
U64 *ordinal = push_array(arena, U64, 1);
|
|
*ordinal = coff_make_ordinal_64(hint);
|
|
ordinal_data = str8_struct(ordinal);
|
|
} break;
|
|
case COFF_MachineType_X86: {
|
|
U32 *ordinal = push_array(arena, U32, 1);
|
|
*ordinal = coff_make_ordinal_32(hint);
|
|
ordinal_data = str8_struct(ordinal);
|
|
} break;
|
|
default: lnk_not_implemented("TODO: support for machine 0x%x", machine);
|
|
}
|
|
return ordinal_data;
|
|
}
|
|
|
|
internal LNK_Chunk *
|
|
lnk_emit_indirect_jump_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *addr_ptr)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
static U8 thunk[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp [__imp_<FUNC_NAME>]
|
|
|
|
// emit chunk
|
|
String8 jmp_data = push_str8_copy(sect->arena, str8_array_fixed(thunk));
|
|
LNK_Chunk *jmp_chunk = lnk_section_push_chunk_data(sect, parent, jmp_data, str8_zero());
|
|
|
|
// patch thunk with imports address
|
|
static const U64 JMP_OPERAND_OFFSET = 2;
|
|
lnk_section_push_reloc(sect, jmp_chunk, LNK_Reloc_REL32, JMP_OPERAND_OFFSET, addr_ptr);
|
|
|
|
ProfEnd();
|
|
return jmp_chunk;
|
|
}
|
|
|
|
internal LNK_Chunk *
|
|
lnk_emit_load_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *imp_addr_ptr, LNK_Symbol *tail_merge)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
static U8 load_thunk[] = {
|
|
0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00, // lea rax, [__imp_<FUNC_NAME>]
|
|
0xE9, 0x00, 0x00, 0x00, 0x00 // jmp __tailMerge_<DLL_NAME>
|
|
};
|
|
|
|
// emit load thunk chunk
|
|
String8 load_thunk_data = push_str8_copy(sect->arena, str8_array_fixed(load_thunk));
|
|
LNK_Chunk *load_thunk_chunk = lnk_section_push_chunk_data(sect, parent, load_thunk_data, str8_zero());
|
|
|
|
// patch lea with IAT entry
|
|
static const U64 LEA_OPERAND_OFFSET = 3;
|
|
lnk_section_push_reloc(sect, load_thunk_chunk, LNK_Reloc_REL32, LEA_OPERAND_OFFSET, imp_addr_ptr);
|
|
|
|
// patch jmp __tailMerge_<DLL_NAME>
|
|
static const U64 JMP_OPERAND_OFFSET = 8;
|
|
lnk_section_push_reloc(sect, load_thunk_chunk, LNK_Reloc_REL32, JMP_OPERAND_OFFSET, tail_merge);
|
|
|
|
ProfEnd();
|
|
return load_thunk_chunk;
|
|
}
|
|
|
|
internal LNK_Chunk *
|
|
lnk_emit_tail_merge_thunk_x64(LNK_Section *sect, LNK_Chunk *parent, LNK_Symbol *dll_import_descriptor, LNK_Symbol *delay_load_helper)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
static U8 tail_merge[] = {
|
|
0x48, 0x89, 0x4C, 0x24, 0x08, // mov qword ptr [rsp+8],rcx
|
|
0x48, 0x89, 0x54, 0x24, 0x10, // mov qword ptr [rsp+10h],rdx
|
|
0x4C, 0x89, 0x44, 0x24, 0x18, // mov qword ptr [rsp+18h],r8
|
|
0x4C, 0x89, 0x4C, 0x24, 0x20, // mov qword ptr [rsp+20h],r9
|
|
0x48, 0x83, 0xEC, 0x68, // sub rsp,68h
|
|
0x66, 0x0F, 0x7F, 0x44, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h],xmm0
|
|
0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h],xmm1
|
|
0x66, 0x0F, 0x7F, 0x54, 0x24, 0x40, // movdqa xmmword ptr [rsp+40h],xmm2
|
|
0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x50, // movdqa xmmword ptr [rsp+50h],xmm3
|
|
0x48, 0x8B, 0xD0, // mov rdx,rax
|
|
0x48, 0x8D, 0x0D, 0x00, 0x00, 0x00, 0x00, // lea rcx,[__DELAY_IMPORT_DESCRIPTOR_<DLL_NAME>]
|
|
0xE8, 0x00, 0x00, 0x00, 0x00, // call __delayLoadHelper2
|
|
0x66, 0x0F, 0x6F, 0x44, 0x24, 0x20, // movdqa xmm0,xmmword ptr [rsp+20h]
|
|
0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x30, // movdqa xmm1,xmmword ptr [rsp+30h]
|
|
0x66, 0x0F, 0x6F, 0x54, 0x24, 0x40, // movdqa xmm2,xmmword ptr [rsp+40h]
|
|
0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x50, // movdqa xmm3,xmmword ptr [rsp+50h]
|
|
0x48, 0x8B, 0x4C, 0x24, 0x70, // mov rcx,qword ptr [rsp+70h]
|
|
0x48, 0x8B, 0x54, 0x24, 0x78, // mov rdx,qword ptr [rsp+78h]
|
|
0x4C, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, // mov r8,qword ptr [rsp+80h]
|
|
0x4C, 0x8B, 0x8C, 0x24, 0x88, 0x00, 0x00, 0x00, // mov r9,qword ptr [rsp+88h]
|
|
0x48, 0x83, 0xC4, 0x68, // add rsp,68h
|
|
0xFF, 0xE0, // jmp rax
|
|
};
|
|
|
|
// emit tail merge chunk
|
|
String8 tail_merge_data = push_str8_copy(sect->arena, str8_array_fixed(tail_merge));
|
|
LNK_Chunk *tail_merge_chunk = lnk_section_push_chunk_data(sect, parent, tail_merge_data, str8_zero());
|
|
|
|
// patch lea __DELAY_IMPORT_DESCRIPTOR_<DLL_NAME>
|
|
static const U64 LEA_OPERAND_OFFSET = 54;
|
|
lnk_section_push_reloc(sect, tail_merge_chunk, LNK_Reloc_REL32, LEA_OPERAND_OFFSET, dll_import_descriptor);
|
|
|
|
// patch call __delayLoadHelper2
|
|
static const U64 CALL_OPERAND_OFFSET = 59;
|
|
lnk_section_push_reloc(sect, tail_merge_chunk, LNK_Reloc_REL32, CALL_OPERAND_OFFSET, delay_load_helper);
|
|
|
|
ProfEnd();
|
|
return tail_merge_chunk;
|
|
}
|
|
|
|
internal LNK_Symbol *
|
|
lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
|
|
{
|
|
ProfBeginFunction();
|
|
// emit load thunk symbol
|
|
String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name);
|
|
LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
|
ProfEnd();
|
|
return load_thunk_symbol;
|
|
}
|
|
|
|
internal LNK_Symbol *
|
|
lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
|
|
{
|
|
ProfBeginFunction();
|
|
String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name);
|
|
LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
|
ProfEnd();
|
|
return jmp_thunk_symbol;
|
|
}
|
|
|
|
internal LNK_Symbol *
|
|
lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
|
|
{
|
|
ProfBeginFunction();
|
|
String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name);
|
|
LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
|
ProfEnd();
|
|
return tail_merge_symbol;
|
|
}
|
|
|