mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-07-13 04:51:25 -07:00
516 lines
30 KiB
C
516 lines
30 KiB
C
// Copyright (c) Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
internal void
|
|
pe_make_import_header_list_push_node(PE_MakeImportList *list, PE_MakeImportNode *node)
|
|
{
|
|
SLLQueuePush(list->first, list->last, node);
|
|
list->count += 1;
|
|
}
|
|
|
|
internal PE_MakeImportNode *
|
|
pe_make_import_header_list_push(Arena *arena, PE_MakeImportList *list, PE_MakeImport v)
|
|
{
|
|
PE_MakeImportNode *node = push_array(arena, PE_MakeImportNode, 1);
|
|
node->v = v;
|
|
pe_make_import_header_list_push_node(list, node);
|
|
return node;
|
|
}
|
|
|
|
internal COFF_ObjSymbol *
|
|
pe_make_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
static U8 thunk[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp [__imp_<FUNC_NAME>]
|
|
|
|
// emit chunk
|
|
String8 jmp_data = push_str8_copy(obj_writer->arena, str8_array_fixed(thunk));
|
|
U64 jmp_data_offset = code_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &code_sect->data, jmp_data);
|
|
|
|
// patch thunk with imports address
|
|
static const U64 JMP_OPERAND_OFFSET = 2;
|
|
coff_obj_writer_section_push_reloc(obj_writer, code_sect, jmp_data_offset + JMP_OPERAND_OFFSET, iat_symbol, COFF_Reloc_X64_Rel32);
|
|
|
|
COFF_ObjSymbol *jmp_thunk_symbol = coff_obj_writer_push_symbol_extern_func(obj_writer, thunk_name, jmp_data_offset, code_sect);
|
|
|
|
ProfEnd();
|
|
return jmp_thunk_symbol;
|
|
}
|
|
|
|
internal COFF_ObjSymbol *
|
|
pe_make_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *imp_addr_ptr, COFF_ObjSymbol *tail_merge, String8 func_name)
|
|
{
|
|
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
|
|
U64 load_thunk_data_offset = code_sect->data.total_size;
|
|
String8 load_thunk_data = push_str8_copy(obj_writer->arena, str8_array_fixed(load_thunk));
|
|
str8_list_push(obj_writer->arena, &code_sect->data, load_thunk_data);
|
|
|
|
// patch lea with IAT entry
|
|
static const U64 LEA_OPERAND_OFFSET = 3;
|
|
coff_obj_writer_section_push_reloc(obj_writer, code_sect, load_thunk_data_offset + LEA_OPERAND_OFFSET, imp_addr_ptr, COFF_Reloc_X64_Rel32);
|
|
|
|
// patch jmp __tailMerge_<DLL_NAME>
|
|
static const U64 JMP_OPERAND_OFFSET = 8;
|
|
coff_obj_writer_section_push_reloc(obj_writer, code_sect, load_thunk_data_offset + JMP_OPERAND_OFFSET, tail_merge, COFF_Reloc_X64_Rel32);
|
|
|
|
// emit symbol
|
|
String8 thunk_name = push_str8f(obj_writer->arena, "__imp_load_%S", func_name);
|
|
COFF_ObjSymbol *load_thunk_symbol = coff_obj_writer_push_symbol_extern_func(obj_writer, thunk_name, load_thunk_data_offset, code_sect);
|
|
|
|
ProfEnd();
|
|
return load_thunk_symbol;
|
|
}
|
|
|
|
internal COFF_ObjSymbol *
|
|
pe_make_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, String8 dll_name, String8 delay_load_helper_name, COFF_ObjSymbol *dll_import_descriptor)
|
|
{
|
|
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(obj_writer->arena, str8_array_fixed(tail_merge));
|
|
U64 tail_merge_off = code_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &code_sect->data, tail_merge_data);
|
|
|
|
// patch lea __DELAY_IMPORT_DESCRIPTOR_<DLL_NAME>
|
|
static const U64 LEA_OPERAND_OFFSET = 54;
|
|
coff_obj_writer_section_push_reloc(obj_writer, code_sect, tail_merge_off + LEA_OPERAND_OFFSET, dll_import_descriptor, COFF_Reloc_X64_Rel32);
|
|
|
|
COFF_ObjSymbol *delay_load_helper = coff_obj_writer_push_symbol_undef(obj_writer, delay_load_helper_name);
|
|
|
|
// patch call __delayLoadHelper2
|
|
static const U64 CALL_OPERAND_OFFSET = 59;
|
|
coff_obj_writer_section_push_reloc(obj_writer, code_sect, tail_merge_off + CALL_OPERAND_OFFSET, delay_load_helper, COFF_Reloc_X64_Rel32);
|
|
|
|
// emit symbol
|
|
String8 tail_merge_name = push_str8f(obj_writer->arena, "__tailMerge_%S", dll_name);
|
|
COFF_ObjSymbol *tail_merge_symbol = coff_obj_writer_push_symbol_extern(obj_writer, tail_merge_name, tail_merge_off, code_sect);
|
|
|
|
ProfEnd();
|
|
return tail_merge_symbol;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_import_entry_obj_delayed(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
String8 dll_name_cstr = push_cstr(arena, dll_name);
|
|
PE_DelayedImportEntry *null_import_entry = push_array(obj_writer->arena, PE_DelayedImportEntry, 1);
|
|
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *didat2 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$2"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(null_import_entry));
|
|
COFF_ObjSection *didat6 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
|
|
coff_obj_writer_push_symbol_extern(obj_writer, push_str8f(obj_writer->arena, "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name), 0, didat2);
|
|
coff_obj_writer_push_symbol_sect(obj_writer, didat2->name, didat2);
|
|
coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR"));
|
|
coff_obj_writer_push_symbol_undef(obj_writer, push_str8f(obj_writer->arena, "\x7f%S_NULL_THUNK_DATA_DLA", dll_name));
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
coff_obj_writer_release(&obj_writer);
|
|
|
|
ProfEnd();
|
|
return obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_null_import_descriptor_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
PE_DelayedImportEntry *import_desc = push_array(obj_writer->arena, PE_DelayedImportEntry, 1);
|
|
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *didat3 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$3"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(import_desc));
|
|
coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR"), 0, didat3);
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
coff_obj_writer_release(&obj_writer);
|
|
|
|
ProfEnd();
|
|
return obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_null_thunk_data_obj_delayed(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
String8 null_thunk = str8(push_array(obj_writer->arena, U8, import_size), import_size);
|
|
String8 null_lookup = str8(push_array(obj_writer->arena, U8, import_size), import_size);
|
|
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *didat4 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$4"), PE_IDATA_SECTION_FLAGS|coff_section_flag_from_align_size(import_size), null_lookup);
|
|
COFF_ObjSection *didat5 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$5"), PE_IDATA_SECTION_FLAGS|coff_section_flag_from_align_size(import_size), null_thunk);
|
|
COFF_ObjSection *didat8 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$8"), PE_IDATA_SECTION_FLAGS|coff_section_flag_from_align_size(import_size), null_thunk);
|
|
COFF_ObjSection *didat9 = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$9"), PE_IDATA_SECTION_FLAGS|coff_section_flag_from_align_size(import_size), null_thunk);
|
|
coff_obj_writer_push_symbol_extern(obj_writer, push_str8f(obj_writer->arena, "\x7f%S_NULL_THUNK_DATA_DLA", dll_name), 0, didat5);
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
|
|
ProfEnd();
|
|
return obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
|
|
PE_ImportEntry *null_import_entry = push_array(obj_writer->arena, PE_ImportEntry, 1);
|
|
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *idata2 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(null_import_entry));
|
|
COFF_ObjSection *idata6 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
|
|
coff_obj_writer_push_symbol_extern(obj_writer, push_str8f(obj_writer->arena, "__IMPORT_DESCRIPTOR_%S", dll_name), 0, idata2);
|
|
coff_obj_writer_push_symbol_sect(obj_writer, idata2->name, idata2);
|
|
|
|
COFF_ObjSymbol *null_desc_undef = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR"));
|
|
COFF_ObjSymbol *null_thunk_undef = coff_obj_writer_push_symbol_undef(obj_writer, push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name));
|
|
|
|
COFF_ObjSymbol *idata6_symbol = coff_obj_writer_push_symbol_static(obj_writer, idata6->name, 0, idata6);
|
|
COFF_ObjSymbol *idata4_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$4"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData);
|
|
COFF_ObjSymbol *idata5_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$5"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, idata2, OffsetOf(PE_ImportEntry, name_voff), idata6_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, idata2, OffsetOf(PE_ImportEntry, lookup_table_voff), idata4_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, idata2, OffsetOf(PE_ImportEntry, import_addr_table_voff), idata5_symbol);
|
|
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
coff_obj_writer_release(&obj_writer);
|
|
|
|
ProfEnd();
|
|
return obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
PE_ImportEntry *import_desc = push_array(obj_writer->arena, PE_ImportEntry, 1);
|
|
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *idata3 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$3"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(import_desc));
|
|
coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR"), 0, idata3);
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
coff_obj_writer_release(&obj_writer);
|
|
|
|
ProfEnd();
|
|
return obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
String8 null_lookup = str8(push_array(obj_writer->arena, U8, import_size), import_size);
|
|
String8 null_thunk = str8(push_array(obj_writer->arena, U8, import_size), import_size);
|
|
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *idata4 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$4"), PE_IDATA_SECTION_FLAGS|coff_section_flag_from_align_size(import_size), null_lookup);
|
|
COFF_ObjSection *idata5 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), PE_IDATA_SECTION_FLAGS|coff_section_flag_from_align_size(import_size), null_thunk);
|
|
coff_obj_writer_push_symbol_extern(obj_writer, push_str8f(obj_writer->arena, "\x7f%S_NULL_THUNK_DATA", dll_name), 0, idata5);
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
coff_obj_writer_release(&obj_writer);
|
|
|
|
ProfEnd();
|
|
return obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, PE_MakeImportList import_headers)
|
|
{
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
COFF_SectionFlags import_align = coff_section_flag_from_align_size(import_size);
|
|
|
|
PE_ImportEntry *impdesc = push_array(obj_writer->arena, PE_ImportEntry, 1);
|
|
String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
|
|
|
|
COFF_ObjSection *dll_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(impdesc));
|
|
COFF_ObjSection *ilt_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$4"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
|
|
COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
|
|
COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
|
|
COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$7"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
|
|
COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$zz"), PE_TEXT_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
|
|
|
|
COFF_ObjSymbol *ilt_symbol = coff_obj_writer_push_symbol_static(obj_writer, ilt_sect->name, 0, ilt_sect);
|
|
COFF_ObjSymbol *iat_symbol = coff_obj_writer_push_symbol_static(obj_writer, iat_sect->name, 0, iat_sect);
|
|
COFF_ObjSymbol *dll_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll_name_sect->name, 0, dll_name_sect);
|
|
|
|
// patch import DLL header
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, lookup_table_voff), ilt_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, name_voff), dll_name_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, import_addr_table_voff), iat_symbol);
|
|
|
|
for (PE_MakeImportNode *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) {
|
|
COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->v.header);
|
|
|
|
COFF_ObjSymbol *iat_symbol = 0;
|
|
switch (import_header.import_by) {
|
|
case COFF_ImportBy_Ordinal: {
|
|
String8 ordinal_data = coff_ordinal_data_from_hint(obj_writer->arena, import_header.machine, import_header.hint_or_ordinal);
|
|
String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name);
|
|
iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_sect->data.total_size, iat_sect);
|
|
str8_list_push(obj_writer->arena, &ilt_sect->data, ordinal_data);
|
|
str8_list_push(obj_writer->arena, &iat_sect->data, ordinal_data);
|
|
} break;
|
|
case COFF_ImportBy_Name: {
|
|
// put together name look up entry
|
|
COFF_ObjSymbol *int_symbol = coff_obj_writer_push_symbol_static(obj_writer, int_sect->name, int_sect->data.total_size, int_sect);
|
|
String8 int_data = coff_make_import_lookup(obj_writer->arena, import_header.hint_or_ordinal, import_header.func_name);
|
|
str8_list_push(obj_writer->arena, &int_sect->data, int_data);
|
|
|
|
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses
|
|
String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name);
|
|
iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_sect->data.total_size, iat_sect);
|
|
|
|
// patch IAT and ILT
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, ilt_sect, ilt_sect->data.total_size, int_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, iat_sect, iat_sect->data.total_size, int_symbol);
|
|
|
|
U64 import_size = coff_word_size_from_machine(import_header.machine);
|
|
U8 *import_entry = push_array(obj_writer->arena, U8, import_size);
|
|
str8_list_push(obj_writer->arena, &ilt_sect->data, str8_array(import_entry, import_size));
|
|
str8_list_push(obj_writer->arena, &iat_sect->data, str8_array(import_entry, import_size));
|
|
} break;
|
|
case COFF_ImportBy_Undecorate: { NotImplemented; } break;
|
|
case COFF_ImportBy_NameNoPrefix: { NotImplemented; } break;
|
|
default: { InvalidPath; } break;
|
|
}
|
|
|
|
// emit thunks
|
|
if (import_header_n->v.make_jump_thunk) {
|
|
if (import_header.type == COFF_ImportHeader_Code) {
|
|
switch (import_header.machine) {
|
|
case COFF_MachineType_Unknown: {} break;
|
|
case COFF_MachineType_X64: { pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); } break;
|
|
default: { NotImplemented; } break;
|
|
}
|
|
} else {
|
|
Assert(0 && "unable to make a jump thunk for non-code target");
|
|
}
|
|
}
|
|
}
|
|
|
|
str8_list_push(obj_writer->arena, &ilt_sect->data, str8(0, coff_word_size_from_machine(machine)));
|
|
str8_list_push(obj_writer->arena, &iat_sect->data, str8(0, coff_word_size_from_machine(machine)));
|
|
|
|
String8 dll_obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
|
|
coff_obj_writer_release(&obj_writer);
|
|
return dll_obj;
|
|
}
|
|
|
|
internal String8
|
|
pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, PE_MakeImportList import_headers, B32 emit_biat, B32 emit_uiat)
|
|
{
|
|
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
|
|
|
|
// import descriptor
|
|
PE_DelayedImportEntry *impdesc = push_array(obj_writer->arena, PE_DelayedImportEntry, 1);
|
|
impdesc->attributes = 1;
|
|
|
|
// DLL name cstring
|
|
String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
|
|
|
|
// DLL handle
|
|
U64 handle_size = coff_word_size_from_machine(machine);
|
|
U8 *handle = push_array(obj_writer->arena, U8, handle_size);
|
|
|
|
// import align
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
COFF_SectionFlags import_align = coff_section_flag_from_align_size(import_size);
|
|
|
|
// push sections
|
|
COFF_ObjSection *dll_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$2"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(impdesc));
|
|
COFF_ObjSection *ilt_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$4"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
|
|
COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$5"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
|
|
COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
|
|
COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$7"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
|
|
COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$"), PE_TEXT_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
|
|
COFF_ObjSection *handle_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".data$"), PE_DATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_array(handle, handle_size));
|
|
COFF_ObjSection *debug_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
|
COFF_ObjSection *biat_sect = 0;
|
|
COFF_ObjSection *uiat_sect = 0;
|
|
|
|
// sections symbols
|
|
COFF_ObjSymbol *dll_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll_sect->name, 0, dll_sect);
|
|
COFF_ObjSymbol *dll_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, dll_name_sect->name, 0, dll_name_sect);
|
|
COFF_ObjSymbol *handle_symbol = coff_obj_writer_push_symbol_static(obj_writer, handle_sect->name, 0, handle_sect);
|
|
COFF_ObjSymbol *iat_symbol = coff_obj_writer_push_symbol_static(obj_writer, iat_sect->name, 0, iat_sect);
|
|
COFF_ObjSymbol *ilt_symbol = coff_obj_writer_push_symbol_static(obj_writer, ilt_sect->name, 0, ilt_sect);
|
|
|
|
// patch virutal offsets in import header
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, name_voff), dll_name_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_symbol);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, name_table_voff), ilt_symbol);
|
|
|
|
// patch BIAT virtual offset in import header
|
|
if (emit_biat) {
|
|
biat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$8"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
|
|
COFF_ObjSymbol *biat_symbol = coff_obj_writer_push_symbol_static(obj_writer, biat_sect->name, 0, biat_sect);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol);
|
|
}
|
|
|
|
// patch UIAT virtual offset in import header
|
|
if (emit_uiat) {
|
|
uiat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".didat$9"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero());
|
|
COFF_ObjSymbol *uiat_symbol = coff_obj_writer_push_symbol_static(obj_writer, uiat_sect->name, 0, uiat_sect);
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol);
|
|
}
|
|
|
|
// emit tail merge
|
|
COFF_ObjSymbol *tail_merge_symbol = 0;
|
|
switch (machine) {
|
|
case COFF_MachineType_Unknown: {} break;
|
|
case COFF_MachineType_X64: { tail_merge_symbol = pe_make_tail_merge_thunk_x64(obj_writer, code_sect, dll_name, delay_load_helper_name, dll_symbol); } break;
|
|
default: { NotImplemented; } break;
|
|
}
|
|
|
|
for (PE_MakeImportNode *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) {
|
|
COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->v.header);
|
|
|
|
// emit thunks
|
|
COFF_ObjSymbol *load_thunk_symbol = 0;
|
|
if (import_header.type == COFF_ImportHeader_Code) {
|
|
switch (machine) {
|
|
case COFF_MachineType_Unknown: {} break;
|
|
case COFF_MachineType_X64: {
|
|
String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name);
|
|
iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_sect->data.total_size, iat_sect);
|
|
|
|
if (import_header_n->v.make_jump_thunk) {
|
|
pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name);
|
|
}
|
|
|
|
// emit load thunk
|
|
load_thunk_symbol = pe_make_load_thunk_x64(obj_writer, code_sect, iat_symbol, tail_merge_symbol, import_header.func_name);
|
|
} break;
|
|
default: { NotImplemented; } break;
|
|
}
|
|
}
|
|
|
|
switch (import_header.import_by) {
|
|
case COFF_ImportBy_Ordinal: {
|
|
String8 ordinal_data = coff_ordinal_data_from_hint(obj_writer->arena, import_header.machine, import_header.hint_or_ordinal);
|
|
str8_list_push(obj_writer->arena, &ilt_sect->data, ordinal_data);
|
|
|
|
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
|
|
U64 iat_offset = iat_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &iat_sect->data, str8(0, import_size));
|
|
|
|
// patch-in thunk address
|
|
coff_obj_writer_section_push_reloc_addr(obj_writer, iat_sect, iat_offset, load_thunk_symbol);
|
|
|
|
if (emit_biat) {
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
U64 biat_offset = biat_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &biat_sect->data, str8(0,import_size));
|
|
coff_obj_writer_section_push_reloc_addr(obj_writer, biat_sect, biat_offset, load_thunk_symbol);
|
|
}
|
|
if (emit_uiat) {
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
U64 uiat_offset = uiat_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &biat_sect->data, str8(0,import_size));
|
|
coff_obj_writer_section_push_reloc_addr(obj_writer, uiat_sect, uiat_offset, load_thunk_symbol);
|
|
}
|
|
} break;
|
|
case COFF_ImportBy_Name: {
|
|
// put together name look up entry
|
|
String8 int_data = coff_make_import_lookup(obj_writer->arena, import_header.hint_or_ordinal, import_header.func_name);
|
|
U64 int_data_offset = int_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &int_sect->data, int_data);
|
|
|
|
// create symbol for lookup chunk
|
|
String8 int_symbol_name = push_str8f(obj_writer->arena, "%S.%S.name.delayed", dll_name, import_header.func_name);
|
|
COFF_ObjSymbol *int_symbol = coff_obj_writer_push_symbol_static(obj_writer, int_symbol_name, int_data_offset, int_sect);
|
|
|
|
U64 import_size = coff_word_size_from_machine(machine);
|
|
|
|
// dynamic linker patches this voff on DLL load event
|
|
U64 ilt_data_offset = ilt_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &ilt_sect->data, str8(0, import_size));
|
|
|
|
// patch-in ILT with import voff
|
|
coff_obj_writer_section_push_reloc_voff(obj_writer, ilt_sect, ilt_data_offset, int_symbol);
|
|
|
|
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
|
|
U64 iat_offset = iat_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &iat_sect->data, str8(0, import_size));
|
|
|
|
// patch-in thunk address
|
|
coff_obj_writer_section_push_reloc_addr(obj_writer, iat_sect, iat_offset, load_thunk_symbol);
|
|
|
|
if (emit_biat) {
|
|
U64 biat_data_offset = biat_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &biat_sect->data, str8(0, import_size));
|
|
|
|
// patch-in thunk address
|
|
coff_obj_writer_section_push_reloc_addr(obj_writer, biat_sect, biat_data_offset, load_thunk_symbol);
|
|
}
|
|
|
|
if (emit_uiat) {
|
|
U64 uiat_data_offset = uiat_sect->data.total_size;
|
|
str8_list_push(obj_writer->arena, &uiat_sect->data, str8(0, import_size));
|
|
|
|
// patch-in thunk address
|
|
coff_obj_writer_section_push_reloc_addr(obj_writer, uiat_sect, uiat_data_offset, load_thunk_symbol);
|
|
}
|
|
} break;
|
|
case COFF_ImportBy_Undecorate: { NotImplemented; } break;
|
|
case COFF_ImportBy_NameNoPrefix: { NotImplemented; } break;
|
|
}
|
|
}
|
|
|
|
str8_list_push(obj_writer->arena, &ilt_sect->data, str8(0, coff_word_size_from_machine(machine)));
|
|
str8_list_push(obj_writer->arena, &iat_sect->data, str8(0, coff_word_size_from_machine(machine)));
|
|
if (emit_biat) {
|
|
str8_list_push(obj_writer->arena, &biat_sect->data, str8(0, coff_word_size_from_machine(machine)));
|
|
}
|
|
if (emit_uiat) {
|
|
str8_list_push(obj_writer->arena, &uiat_sect->data, str8(0, coff_word_size_from_machine(machine)));
|
|
}
|
|
|
|
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
|
coff_obj_writer_release(&obj_writer);
|
|
return obj;
|
|
}
|