// 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_] // 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_] 0xE9, 0x00, 0x00, 0x00, 0x00 // jmp __tailMerge_ }; // 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_ 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_] 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_ 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; }