Primary MachO writing

This commit is contained in:
David Gonzalez Martin 2024-10-03 19:30:00 -06:00 committed by David
parent 4fe18ffaa8
commit dacb9334e5
3 changed files with 653 additions and 144 deletions

View File

@ -18,18 +18,18 @@ jobs:
- name: Build and test - name: Build and test
run: | run: |
./project.sh test all ./project.sh test all
# macos_build_and_test: macos_build_and_test:
# runs-on: macos-latest runs-on: macos-latest
# timeout-minutes: 15 timeout-minutes: 15
# steps: steps:
# - name: Checkout - name: Checkout
# uses: actions/checkout@v4 uses: actions/checkout@v4
# - name: Install LLVM - name: Install LLVM
# run: | run: |
# brew list llvm || brew install llvm brew list llvm || brew install llvm
# - name: Build and test - name: Build and test
# run: | run: |
# ./project.sh test all ./project.sh test all
windows_build_and_test: windows_build_and_test:
runs-on: windows-latest runs-on: windows-latest
timeout-minutes: 15 timeout-minutes: 15

View File

@ -3061,6 +3061,19 @@ may_be_unused fn void run_command(Arena* arena, CStringSlice arguments, char* en
if (CreateProcessA(0, bytes, 0, 0, handle_inheritance, 0, 0, 0, &startup_info, &process_information)) if (CreateProcessA(0, bytes, 0, 0, handle_inheritance, 0, 0, 0, &startup_info, &process_information))
{ {
WaitForSingleObject(process_information.hProcess, INFINITE); WaitForSingleObject(process_information.hProcess, INFINITE);
DWORD exit_code;
if (GetExitCodeProcess(process_information.hProcess, &exit_code))
{
if (exit_code != 0)
{
fail();
}
}
else
{
fail();
}
CloseHandle(process_information.hProcess); CloseHandle(process_information.hProcess);
CloseHandle(process_information.hThread); CloseHandle(process_information.hThread);
} }
@ -3233,7 +3246,6 @@ may_be_unused fn u8* vb_append_bytes(VirtualBuffer(u8*) vb, Slice(u8) bytes)
#define vb_ensure_capacity(a, count) vb_generic_ensure_capacity((VirtualBuffer(u8)*)(a), sizeof(*((a)->pointer)), count) #define vb_ensure_capacity(a, count) vb_generic_ensure_capacity((VirtualBuffer(u8)*)(a), sizeof(*((a)->pointer)), count)
#define vb_add_array(vb, arr) memcpy(vb_add(vb, sizeof(arr)), arr, sizeof(arr)) #define vb_add_array(vb, arr) memcpy(vb_add(vb, sizeof(arr)), arr, sizeof(arr))
may_be_unused fn Hash32 hash32_fib_end(Hash32 hash) may_be_unused fn Hash32 hash32_fib_end(Hash32 hash)
{ {
auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32); auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32);

View File

@ -365,11 +365,11 @@ typedef enum ElfProgramHeaderType : u32
PT_SHLIB = 5, PT_SHLIB = 5,
PT_PHDR = 6, PT_PHDR = 6,
PT_TLS = 7, PT_TLS = 7,
PT_GNU_EH_FRAME = 0x6474e550, /* GCC .eh_frame_hdr segment */ PT_GNU_EH_FRAME = 0x6474e550, /* GCC .eh_frame_hdr segment */
PT_GNU_STACK = 0x6474e551, /* Indicates stack executability */ PT_GNU_STACK = 0x6474e551, /* Indicates stack executability */
PT_GNU_RELRO = 0x6474e552, /* Read-only after relocation */ PT_GNU_RELRO = 0x6474e552, /* Read-only after relocation */
PT_GNU_PROPERTY = 0x6474e553, /* GNU property */ PT_GNU_PROPERTY = 0x6474e553, /* GNU property */
PT_GNU_SFRAME = 0x6474e554, /* SFrame segment. */ PT_GNU_SFRAME = 0x6474e554, /* SFrame segment. */
} ElfProgramHeaderType; } ElfProgramHeaderType;
STRUCT(ElfProgramHeaderFlags) STRUCT(ElfProgramHeaderFlags)
@ -7960,10 +7960,13 @@ STRUCT(SymbolRelocation)
}; };
decl_vb(SymbolRelocation); decl_vb(SymbolRelocation);
may_be_unused fn void write_elf(Thread* thread, ObjectOptions options) STRUCT(FileBuffer)
{ {
unused(thread); VirtualBuffer(u8) buffer;
};
may_be_unused fn String write_elf(Thread* thread, ObjectOptions options)
{
ELFBuilder builder_stack = {}; ELFBuilder builder_stack = {};
ELFBuilder* restrict builder = &builder_stack; ELFBuilder* restrict builder = &builder_stack;
// Initialization // Initialization
@ -8595,14 +8598,14 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
0x48, 0x83, 0xC4, 0x08, 0x48, 0x83, 0xC4, 0x08,
0xC3, 0xC3,
}; };
// 1000: f3 0f 1e fa endbr64 // 1000: f3 0f 1e fa endbr64
// 1004: 48 83 ec 08 sub rsp,0x8 // 1004: 48 83 ec 08 sub rsp,0x8
// 1008: 48 8b 05 c1 2f 00 00 mov rax,QWORD PTR [rip+0x2fc1] # 3fd0 <__gmon_start__@Base> // 1008: 48 8b 05 c1 2f 00 00 mov rax,QWORD PTR [rip+0x2fc1] # 3fd0 <__gmon_start__@Base>
// 100f: 48 85 c0 test rax,rax // 100f: 48 85 c0 test rax,rax
// 1012: 74 02 je 1016 <_init+0x16> // 1012: 74 02 je 1016 <_init+0x16>
// 1014: ff d0 call rax // 1014: ff d0 call rax
// 1016: 48 83 c4 08 add rsp,0x8 // 1016: 48 83 c4 08 add rsp,0x8
// 101a: c3 ret // 101a: c3 ret
*vb_add(&symbol_relocations, 1) = (SymbolRelocation){ *vb_add(&symbol_relocations, 1) = (SymbolRelocation){
.name = strlit("__gmon_start__"), .name = strlit("__gmon_start__"),
@ -8679,19 +8682,19 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
.offset = offset + 0x1f + 2, .offset = offset + 0x1f + 2,
}; };
// 1020: f3 0f 1e fa endbr64 // 1020: f3 0f 1e fa endbr64
// 1024: 31 ed xor ebp,ebp // 1024: 31 ed xor ebp,ebp
// 1026: 49 89 d1 mov r9,rdx // 1026: 49 89 d1 mov r9,rdx
// 1029: 5e pop rsi // 1029: 5e pop rsi
// 102a: 48 89 e2 mov rdx,rsp // 102a: 48 89 e2 mov rdx,rsp
// 102d: 48 83 e4 f0 and rsp,0xfffffffffffffff0 // 102d: 48 83 e4 f0 and rsp,0xfffffffffffffff0
// 1031: 50 push rax // 1031: 50 push rax
// 1032: 54 push rsp // 1032: 54 push rsp
// 1033: 45 31 c0 xor r8d,r8d // 1033: 45 31 c0 xor r8d,r8d
// 1036: 31 c9 xor ecx,ecx // 1036: 31 c9 xor ecx,ecx
// 1038: 48 8d 3d dd 00 00 00 lea rdi,[rip+0xdd] # 111c <main> // 1038: 48 8d 3d dd 00 00 00 lea rdi,[rip+0xdd] # 111c <main>
// 103f: ff 15 7b 2f 00 00 call QWORD PTR [rip+0x2f7b] # 3fc0 <__libc_start_main@GLIBC_2.34> // 103f: ff 15 7b 2f 00 00 call QWORD PTR [rip+0x2f7b] # 3fc0 <__libc_start_main@GLIBC_2.34>
// 1045: f4 hlt // 1045: f4 hlt
_start_size = sizeof(data); _start_size = sizeof(data);
memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data));
@ -8734,17 +8737,17 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
.offset = offset + 0x63 - 0x20 + 3, .offset = offset + 0x63 - 0x20 + 3,
}; };
// 1050: 48 8d 3d b9 2f 00 00 lea rdi,[rip+0x2fb9] # 4010 <__TMC_END__> // 1050: 48 8d 3d b9 2f 00 00 lea rdi,[rip+0x2fb9] # 4010 <__TMC_END__>
// 1057: 48 8d 05 b2 2f 00 00 lea rax,[rip+0x2fb2] # 4010 <__TMC_END__> // 1057: 48 8d 05 b2 2f 00 00 lea rax,[rip+0x2fb2] # 4010 <__TMC_END__>
// 105e: 48 39 f8 cmp rax,rdi // 105e: 48 39 f8 cmp rax,rdi
// 1061: 74 15 je 1078 <_start+0x58> // 1061: 74 15 je 1078 <_start+0x58>
// 1063: 48 8b 05 5e 2f 00 00 mov rax,QWORD PTR [rip+0x2f5e] # 3fc8 <_ITM_deregisterTMCloneTable@Base> // 1063: 48 8b 05 5e 2f 00 00 mov rax,QWORD PTR [rip+0x2f5e] # 3fc8 <_ITM_deregisterTMCloneTable@Base>
// 106a: 48 85 c0 test rax,rax // 106a: 48 85 c0 test rax,rax
// 106d: 74 09 je 1078 <_start+0x58> // 106d: 74 09 je 1078 <_start+0x58>
// 106f: ff e0 jmp rax // 106f: ff e0 jmp rax
// 1071: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0] // 1071: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
// 1078: c3 ret // 1078: c3 ret
// 1079: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0] // 1079: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data));
} }
@ -8770,22 +8773,22 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
.offset = offset + 0xa4 - 0x20 + 3, .offset = offset + 0xa4 - 0x20 + 3,
}; };
// 1080: 48 8d 3d 89 2f 00 00 lea rdi,[rip+0x2f89] # 4010 <__TMC_END__> // 1080: 48 8d 3d 89 2f 00 00 lea rdi,[rip+0x2f89] # 4010 <__TMC_END__>
// 1087: 48 8d 35 82 2f 00 00 lea rsi,[rip+0x2f82] # 4010 <__TMC_END__> // 1087: 48 8d 35 82 2f 00 00 lea rsi,[rip+0x2f82] # 4010 <__TMC_END__>
// 108e: 48 29 fe sub rsi,rdi // 108e: 48 29 fe sub rsi,rdi
// 1091: 48 89 f0 mov rax,rsi // 1091: 48 89 f0 mov rax,rsi
// 1094: 48 c1 ee 3f shr rsi,0x3f // 1094: 48 c1 ee 3f shr rsi,0x3f
// 1098: 48 c1 f8 03 sar rax,0x3 // 1098: 48 c1 f8 03 sar rax,0x3
// 109c: 48 01 c6 add rsi,rax // 109c: 48 01 c6 add rsi,rax
// 109f: 48 d1 fe sar rsi,1 // 109f: 48 d1 fe sar rsi,1
// 10a2: 74 14 je 10b8 <_start+0x98> // 10a2: 74 14 je 10b8 <_start+0x98>
// 10a4: 48 8b 05 2d 2f 00 00 mov rax,QWORD PTR [rip+0x2f2d] # 3fd8 <_ITM_registerTMCloneTable@Base> // 10a4: 48 8b 05 2d 2f 00 00 mov rax,QWORD PTR [rip+0x2f2d] # 3fd8 <_ITM_registerTMCloneTable@Base>
// 10ab: 48 85 c0 test rax,rax // 10ab: 48 85 c0 test rax,rax
// 10ae: 74 08 je 10b8 <_start+0x98> // 10ae: 74 08 je 10b8 <_start+0x98>
// 10b0: ff e0 jmp rax // 10b0: ff e0 jmp rax
// 10b2: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0] // 10b2: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
// 10b8: c3 ret // 10b8: c3 ret
// 10b9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0] // 10b9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data));
} }
@ -8836,26 +8839,26 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
.extra_bytes = 1, .extra_bytes = 1,
}; };
// 10c0: f3 0f 1e fa endbr64 // 10c0: f3 0f 1e fa endbr64
// 10c4: 80 3d 45 2f 00 00 00 cmp BYTE PTR [rip+0x2f45],0x0 # 4010 <__TMC_END__> // 10c4: 80 3d 45 2f 00 00 00 cmp BYTE PTR [rip+0x2f45],0x0 # 4010 <__TMC_END__>
// 10cb: 75 33 jne 1100 <_start+0xe0> // 10cb: 75 33 jne 1100 <_start+0xe0>
// 10cd: 55 push rbp // 10cd: 55 push rbp
// 10ce: 48 83 3d 0a 2f 00 00 cmp QWORD PTR [rip+0x2f0a],0x0 # 3fe0 <__cxa_finalize@GLIBC_2.2.5> // 10ce: 48 83 3d 0a 2f 00 00 cmp QWORD PTR [rip+0x2f0a],0x0 # 3fe0 <__cxa_finalize@GLIBC_2.2.5>
// 10d5: 00 // 10d5: 00
// 10d6: 48 89 e5 mov rbp,rsp // 10d6: 48 89 e5 mov rbp,rsp
// 10d9: 74 0d je 10e8 <_start+0xc8> // 10d9: 74 0d je 10e8 <_start+0xc8>
// 10db: 48 8b 3d 26 2f 00 00 mov rdi,QWORD PTR [rip+0x2f26] # 4008 <__dso_handle> // 10db: 48 8b 3d 26 2f 00 00 mov rdi,QWORD PTR [rip+0x2f26] # 4008 <__dso_handle>
// 10e2: ff 15 f8 2e 00 00 call QWORD PTR [rip+0x2ef8] # 3fe0 <__cxa_finalize@GLIBC_2.2.5> // 10e2: ff 15 f8 2e 00 00 call QWORD PTR [rip+0x2ef8] # 3fe0 <__cxa_finalize@GLIBC_2.2.5>
// 10e8: e8 63 ff ff ff call 1050 <_start+0x30> // 10e8: e8 63 ff ff ff call 1050 <_start+0x30>
// 10ed: c6 05 1c 2f 00 00 01 mov BYTE PTR [rip+0x2f1c],0x1 # 4010 <__TMC_END__> // 10ed: c6 05 1c 2f 00 00 01 mov BYTE PTR [rip+0x2f1c],0x1 # 4010 <__TMC_END__>
// 10f4: 5d pop rbp // 10f4: 5d pop rbp
// 10f5: c3 ret // 10f5: c3 ret
// 10f6: 66 2e 0f 1f 84 00 00 cs nop WORD PTR [rax+rax*1+0x0] // 10f6: 66 2e 0f 1f 84 00 00 cs nop WORD PTR [rax+rax*1+0x0]
// 10fd: 00 00 00 // 10fd: 00 00 00
// 1100: c3 ret // 1100: c3 ret
// 1101: 66 66 2e 0f 1f 84 00 data16 cs nop WORD PTR [rax+rax*1+0x0] // 1101: 66 66 2e 0f 1f 84 00 data16 cs nop WORD PTR [rax+rax*1+0x0]
// 1108: 00 00 00 00 // 1108: 00 00 00 00
// 110c: 0f 1f 40 00 nop DWORD PTR [rax+0x0] // 110c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data));
} }
@ -8868,9 +8871,9 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
0x0F, 0x1F, 0x00, 0x0F, 0x1F, 0x00,
}; };
// 1110: f3 0f 1e fa endbr64 // 1110: f3 0f 1e fa endbr64
// 1114: e9 67 ff ff ff jmp 1080 <_start+0x60> // 1114: e9 67 ff ff ff jmp 1080 <_start+0x60>
// 1119: 0f 1f 00 nop DWORD PTR [rax] // 1119: 0f 1f 00 nop DWORD PTR [rax]
memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data));
} }
@ -8920,10 +8923,10 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
0xC3, 0xC3,
}; };
// 1120: f3 0f 1e fa endbr64 // 1120: f3 0f 1e fa endbr64
// 1124: 48 83 ec 08 sub rsp,0x8 // 1124: 48 83 ec 08 sub rsp,0x8
// 1128: 48 83 c4 08 add rsp,0x8 // 1128: 48 83 c4 08 add rsp,0x8
// 112c: c3 ret // 112c: c3 ret
u32 size = sizeof(data); u32 size = sizeof(data);
memcpy(vb_add(&builder->file, size), data, size); memcpy(vb_add(&builder->file, size), data, size);
@ -10672,17 +10675,7 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
assert(dynamic_relocation_count == expected_dynamic_relocation_count); assert(dynamic_relocation_count == expected_dynamic_relocation_count);
{ return (String) { builder->file.pointer, builder->file.length };
auto fd = os_file_open(options.exe_path, (OSFileOpenFlags) {
.write = 1,
.truncate = 1,
.create = 1,
.executable = 1,
});
assert(os_file_descriptor_is_valid(fd));
os_file_write(fd, (String) { builder->file.pointer, builder->file.length });
os_file_close(fd);
}
} }
STRUCT(DOSHeader) STRUCT(DOSHeader)
@ -10909,7 +10902,7 @@ fn COFFSectionName coff_section_name(String name)
return result; return result;
} }
may_be_unused fn void write_pe(Thread* thread, ObjectOptions options) may_be_unused fn String write_pe(Thread* thread, ObjectOptions options)
{ {
VirtualBuffer(u8) file = {}; VirtualBuffer(u8) file = {};
auto* mz = "MZ"; auto* mz = "MZ";
@ -11138,36 +11131,7 @@ may_be_unused fn void write_pe(Thread* thread, ObjectOptions options)
unused(thread); unused(thread);
#endif #endif
{ return (String){ file.pointer, file.length };
auto fd = os_file_open(options.exe_path, (OSFileOpenFlags) {
.write = 1,
.truncate = 1,
.create = 1,
.executable = 1,
});
#if _WIN32
if (!os_file_descriptor_is_valid(fd))
{
auto err = GetLastError();
LPSTR lpMsgBuf;
DWORD bufSize = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
LANG_NEUTRAL, // Use default language
(LPSTR)&lpMsgBuf,
0,
NULL
);
unused(bufSize);
print("Error opening file \"{s}\": {cstr}\n", options.exe_path, lpMsgBuf);
fail();
}
#endif
assert(os_file_descriptor_is_valid(fd));
os_file_write(fd, (String) { file.pointer, file.length });
os_file_close(fd);
}
} }
fn void subsume_node_without_killing(Thread* thread, NodeIndex old_node_index, NodeIndex new_node_index) fn void subsume_node_without_killing(Thread* thread, NodeIndex old_node_index, NodeIndex new_node_index)
@ -13378,12 +13342,512 @@ fn u8 operand_equal(MachineOperand a, MachineOperand b)
return (a.id == MACHINE_OPERAND_GPR || a.id == MACHINE_OPERAND_XMM) ? a.register_value == b.register_value : 0; return (a.id == MACHINE_OPERAND_GPR || a.id == MACHINE_OPERAND_XMM) ? a.register_value == b.register_value : 0;
} }
may_be_unused fn void write_macho(Thread* restrict thread, const ObjectOptions * const restrict options, char** envp) typedef enum MachOCpuType : u32
{
MACHO_CPU_X86 = 7,
MACHO_CPU_ARM = 12,
MACHO_CPU_X86_64 = MACHO_CPU_X86 | 0x1000000,
MACHO_CPU_ARM64 = MACHO_CPU_ARM | 0x1000000,
MACHO_CPU_ANY = 0xffffffff,
} MachOCpuType;
typedef enum MachOFileType : u32
{
MACHO_FILE_OBJECT = 1,
MACHO_FILE_EXECUTABLE = 2,
MACHO_FILE_FVM_LIB = 3,
MACHO_FILE_CORE = 4,
MACHO_FILE_PRELOAD = 5,
MACHO_FILE_DYLIB = 6,
MACHO_FILE_DYLINKER = 7,
MACHO_FILE_BUNDLE = 8,
MACHO_FILE_DYLIB_STUB = 9,
MACHO_FILE_DSYM = 10,
MACHO_FILE_KEXT_BUNDLE = 11,
} MachOFileType;
STRUCT(MachOFlags)
{
u32 no_undefined:1;
u32 incremental_link:1;
u32 dyld_link:1;
u32 binary_data_load:1;
u32 prebound:1;
u32 split_segments:1;
u32 lazy_init:1;
u32 two_level:1;
u32 force_flat:1;
u32 no_multi_definitions:1;
u32 no_fix_prebinding:1;
u32 prebindable:1;
u32 all_mods_bound:1;
u32 sub_sections_via_symbols:1;
u32 canonical:1;
u32 weak_defines:1;
u32 binds_to_weak:1;
u32 allow_stack_execution:1;
u32 root_safe:1;
u32 setuid_safe:1;
u32 no_reexported_dylibs:1;
u32 pie:1;
u32 dead_strippable_dylib:1;
u32 has_tlv_descriptors:1;
u32 no_heap_execution:1;
u32 app_extension_safe:1;
u32 n_list_out_of_sync_with_dyldinof:1;
u32 simulator_support:1;
u32 padding:3;
u32 dyld_cache:1;
};
static_assert(sizeof(MachOFlags) == sizeof(u32));
STRUCT(MachOHeader)
{
u32 magic;
MachOCpuType cpu_type;
u32 sub_cpu_type:24;
u32 padding:7;
u32 lib64:1;
MachOFileType file_type;
u32 command_count;
u32 command_total_size;
MachOFlags flags;
u32 reserved;
};
static_assert(sizeof(MachOHeader) == 0x20);
typedef enum MachOLoadCommandId : u32
{
LC_SEGMENT = 0x00000001,
LC_SYMTAB = 0x00000002,
LC_SYMSEG = 0x00000003,
LC_THREAD = 0x00000004,
LC_UNIXTHREAD = 0x00000005,
LC_LOADFVMLIB = 0x00000006,
LC_IDFVMLIB = 0x00000007,
LC_IDENT = 0x00000008,
LC_FVMFILE = 0x00000009,
LC_PREPAGE = 0x0000000A,
LC_DYSYMTAB = 0x0000000B,
LC_LOAD_DYLIB = 0x0000000C,
LC_ID_DYLIB = 0x0000000D,
LC_LOAD_DYLINKER = 0x0000000E,
LC_ID_DYLINKER = 0x0000000F,
LC_PREBOUND_DYLIB = 0x00000010,
LC_ROUTINES = 0x00000011,
LC_SUB_FRAMEWORK = 0x00000012,
LC_SUB_UMBRELLA = 0x00000013,
LC_SUB_CLIENT = 0x00000014,
LC_SUB_LIBRARY = 0x00000015,
LC_TWOLEVEL_HINTS = 0x00000016,
LC_PREBIND_CKSUM = 0x00000017,
LC_LOAD_WEAK_DYLIB = 0x80000018,
LC_SEGMENT_64 = 0x00000019,
LC_ROUTINES_64 = 0x0000001A,
LC_UUID = 0x0000001B,
LC_RPATH = 0x8000001C,
LC_CODE_SIGNATURE = 0x0000001D,
LC_SEGMENT_SPLIT_INFO = 0x0000001E,
LC_REEXPORT_DYLIB = 0x8000001F,
LC_LAZY_LOAD_DYLIB = 0x00000020,
LC_ENCRYPTION_INFO = 0x00000021,
LC_DYLD_INFO = 0x00000022,
LC_DYLD_INFO_ONLY = 0x80000022,
LC_LOAD_UPWARD_DYLIB = 0x80000023,
LC_VERSION_MIN_MACOSX = 0x00000024,
LC_VERSION_MIN_IPHONEOS = 0x00000025,
LC_FUNCTION_STARTS = 0x00000026,
LC_DYLD_ENVIRONMENT = 0x00000027,
LC_MAIN = 0x80000028,
LC_DATA_IN_CODE = 0x00000029,
LC_SOURCE_VERSION = 0x0000002A,
LC_DYLIB_CODE_SIGN_DRS = 0x0000002B,
LC_ENCRYPTION_INFO_64 = 0x0000002C,
LC_LINKER_OPTION = 0x0000002D,
LC_LINKER_OPTIMIZATION_HINT = 0x0000002E,
LC_VERSION_MIN_TVOS = 0x0000002F,
LC_VERSION_MIN_WATCHOS = 0x00000030,
LC_NOTE = 0x00000031,
LC_BUILD_VERSION = 0x00000032,
LC_DYLD_EXPORTS_TRIE = 0x80000033,
LC_DYLD_CHAINED_FIXUPS = 0x80000034,
LC_FILESET_ENTRY = 0x80000035,
LC_ATOM_INFO = 0x00000036,
} MachOLoadCommandId;
STRUCT(MachOName16)
{
u8 name[16];
};
fn MachOName16 macho_name16(String string)
{
MachOName16 result = {};
assert(string.length <= array_length(result.name));
memcpy(result.name, string.pointer, string.length);
return result;
}
STRUCT(MachOSegment)
{
MachOName16 name;
u64 memory_address;
u64 memory_size;
u64 file_offset;
u64 file_size;
u32 max_protection;
u32 initial_protection;
u32 section_count;
u32 flags;
};
static_assert(sizeof(MachOSegment) == 64);
STRUCT(MachOCommand)
{
MachOLoadCommandId id;
u32 command_size;
};
static_assert(sizeof(MachOCommand) == 8);
STRUCT(MachOSection)
{
MachOName16 section_name;
MachOName16 segment_name;
u64 address;
u64 size;
u32 offset;
u32 alignment;
u32 relocation_offset;
u32 relocation_count;
u32 flags;
u8 reserved[12];
};
static_assert(sizeof(MachOSection) == 0x50);
#define vb_copy_struct(vb, s) *vb_add_struct(&file, typeof(s)) = s
may_be_unused fn String write_macho(Thread* restrict thread, ObjectOptions options)
{ {
unused(thread); unused(thread);
unused(options); unused(options);
unused(envp); VirtualBuffer(u8) file = {};
todo(); MachOHeader header = {
.magic = 0xfeedfacf,
.cpu_type = MACHO_CPU_ARM64,
.file_type = MACHO_FILE_EXECUTABLE,
.command_count = 15,
.command_total_size = 688,
.flags = {
.no_undefined = 1,
.dyld_link = 1,
.two_level = 1,
.pie = 1,
},
};
vb_copy_struct(&file, header);
MachOCommand page_zero_command = {
.id = LC_SEGMENT_64,
.command_size = sizeof(MachOCommand) + sizeof(MachOSegment),
};
vb_copy_struct(&file, page_zero_command);
MachOSegment page_zero_segment = {
.name = macho_name16(strlit("__PAGEZERO")),
.memory_size = GB(4),
};
vb_copy_struct(&file, page_zero_segment);
MachOCommand text_command = {
.id = LC_SEGMENT_64,
.command_size = 232,
};
vb_copy_struct(&file, text_command);
MachOSection text_section = {
.section_name = macho_name16(strlit("__text")),
.segment_name = macho_name16(strlit("__TEXT")),
.address = 0x100003fa0,
.size = 8,
.offset = 16288,
.alignment = 2,
.relocation_offset = 0,
.relocation_count = 0,
.flags = 0x80000400,
};
MachOSection unwind_info_section = {
.section_name = macho_name16(strlit("__unwind_info")),
.segment_name = macho_name16(strlit("__TEXT")),
.address = 0x100003fa8,
.size = 88,
.offset = 16296,
.alignment = 2,
.relocation_offset = 0,
.relocation_count = 0,
.flags = 0,
};
MachOSegment text_segment = {
.name = macho_name16(strlit("__TEXT")),
.memory_address = GB(4),
.memory_size = KB(16),
.file_offset = 0,
.file_size = KB(16),
.max_protection = 5,
.initial_protection = 5,
.section_count = 2,
.flags = 0,
};
vb_copy_struct(&file, text_segment);
assert(file.length == 0xb0);
vb_copy_struct(&file, text_section);
vb_align(&file, 0x10);
vb_copy_struct(&file, unwind_info_section);
MachOCommand linkedit_command = {
.id = LC_SEGMENT_64,
.command_size = sizeof(MachOCommand) + sizeof(MachOSegment),
};
vb_copy_struct(&file, linkedit_command);
MachOSegment linkedit_segment = {
.name = macho_name16(strlit("__LINKEDIT")),
.memory_address = 0x100004000,
.memory_size = KB(16),
.file_offset = KB(16),
.file_size = 688,
.max_protection = 1,
.initial_protection = 1,
.section_count = 0,
.flags = 0,
};
vb_copy_struct(&file, linkedit_segment);
MachOCommand chained_fixups_command = {
.id = LC_DYLD_CHAINED_FIXUPS,
.command_size = 16,
};
vb_copy_struct(&file, chained_fixups_command);
{
u8 blob[] = { 0x00, 0x40, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand exports_trie_command = {
.id = LC_DYLD_EXPORTS_TRIE,
.command_size = 16,
};
vb_copy_struct(&file, exports_trie_command);
{
u8 blob[] = { 0x38, 0x40, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand symtab_command = {
.id = LC_SYMTAB,
.command_size = 24,
};
vb_copy_struct(&file, symtab_command);
{
u8 blob[] = { 0x70, 0x40, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand dysymtab_command = {
.id = LC_DYSYMTAB,
.command_size = 80,
};
vb_copy_struct(&file, dysymtab_command);
{
u8 blob[] = {
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
vb_add_array(&file, blob);
}
MachOCommand load_dylinker_command = {
.id = LC_LOAD_DYLINKER,
.command_size = 32,
};
vb_copy_struct(&file, load_dylinker_command);
{
u8 blob[] = { 0x0C, 0x00, 0x00, 0x00, 0x2F, 0x75, 0x73, 0x72, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x64, 0x79, 0x6C, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand uuid_command = {
.id = LC_UUID,
.command_size = 24,
};
vb_copy_struct(&file, uuid_command);
{
u8 uuid[] = { 0x9C, 0x6F, 0xC9, 0x12, 0xED, 0x7F, 0x39, 0x3A, 0x99, 0xA7, 0x93, 0x4B, 0xF6, 0xD1, 0x4D, 0xA1, };
vb_add_array(&file, uuid);
}
MachOCommand build_version_command = {
.id = LC_BUILD_VERSION,
.command_size = 32,
};
vb_copy_struct(&file, build_version_command);
{
u8 blob[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x07, 0x5B, 0x04, };
vb_add_array(&file, blob);
}
MachOCommand source_version_command = {
.id = LC_SOURCE_VERSION,
.command_size = 16,
};
vb_copy_struct(&file, source_version_command);
{
u8 blob[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand main_command = {
.id = LC_MAIN,
.command_size = 24,
};
vb_copy_struct(&file, main_command);
{
u8 blob[] = { 0xA0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand function_starts_command = {
.id = LC_FUNCTION_STARTS,
.command_size = 16,
};
vb_copy_struct(&file, function_starts_command);
{
u8 blob[] = { 0x68, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand data_in_code_command = {
.id = LC_DATA_IN_CODE,
.command_size = 16,
};
vb_copy_struct(&file, data_in_code_command);
{
u8 blob[] = { 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
vb_add_array(&file, blob);
}
MachOCommand code_signature_command = {
.id = LC_CODE_SIGNATURE,
.command_size = 16,
};
vb_copy_struct(&file, code_signature_command);
{
u8 blob[] = {
0x90, 0x41, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
};
vb_add_array(&file, blob);
}
// Pad
unused(vb_add(&file, text_section.offset - file.length));
u8 text_section_content[] = { 0x00, 0x00, 0x80, 0x52, 0xC0, 0x03, 0x5F, 0xD6, };
vb_add_array(&file, text_section_content);
u8 unwind_info_section_content[] = {
0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA0, 0x3F, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
};
vb_add_array(&file, unwind_info_section_content);
vb_align(&file, 0x4000);
u8 linkedit_segment_content[] = {
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5F, 0x00, 0x12, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xA0, 0x7F, 0x00, 0x00, 0x02, 0x5F, 0x6D, 0x68, 0x5F,
0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5F, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x09,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x0D, 0x00, 0x00, 0xA0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x66, 0x00, 0x01, 0x00, 0xC1, 0x6A, 0x00, 0x67, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2E, 0x01, 0x00, 0x00, 0xA0, 0x3F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0xA0, 0x3F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x4E, 0x01, 0x00, 0x00, 0xA0, 0x3F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x00, 0xA0, 0x3F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x5F, 0x5F, 0x6D, 0x68, 0x5F, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5F, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x2F, 0x55, 0x73, 0x65,
0x72, 0x73, 0x2F, 0x64, 0x61, 0x76, 0x69, 0x64, 0x2F, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x61, 0x6C,
0x2F, 0x00, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x63, 0x6F, 0x73, 0x2E,
0x63, 0x00, 0x2F, 0x55, 0x73, 0x65, 0x72, 0x73, 0x2F, 0x64, 0x61, 0x76, 0x69, 0x64, 0x2F, 0x6D,
0x69, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x2F, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x5F, 0x6D,
0x61, 0x63, 0x6F, 0x73, 0x2E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0xDE, 0x0C, 0xC0, 0x00, 0x00, 0x01, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x14, 0xFA, 0xDE, 0x0C, 0x02, 0x00, 0x00, 0x01, 0x06, 0x00, 0x02, 0x04, 0x00,
0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x41, 0x90, 0x20, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6D, 0x69, 0x6E, 0x69,
0x6D, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x63, 0x6F, 0x73, 0x00, 0x29, 0x0B, 0x00, 0xDF, 0x14, 0xC1,
0xD7, 0x61, 0x76, 0xD6, 0xF1, 0xC4, 0x26, 0x31, 0xFC, 0xD7, 0x84, 0x22, 0x15, 0x80, 0xEB, 0xF4,
0x62, 0x35, 0xD2, 0xC9, 0xF0, 0xE4, 0xA7, 0x6B, 0x9E, 0x1D, 0xAD, 0x7F, 0xAC, 0xB2, 0x58, 0x6F,
0xC6, 0xE9, 0x66, 0xC0, 0x04, 0xD7, 0xD1, 0xD1, 0x6B, 0x02, 0x4F, 0x58, 0x05, 0xFF, 0x7C, 0xB4,
0x7C, 0x7A, 0x85, 0xDA, 0xBD, 0x8B, 0x48, 0x89, 0x2C, 0xA7, 0xAD, 0x7F, 0xAC, 0xB2, 0x58, 0x6F,
0xC6, 0xE9, 0x66, 0xC0, 0x04, 0xD7, 0xD1, 0xD1, 0x6B, 0x02, 0x4F, 0x58, 0x05, 0xFF, 0x7C, 0xB4,
0x7C, 0x7A, 0x85, 0xDA, 0xBD, 0x8B, 0x48, 0x89, 0x2C, 0xA7, 0xB2, 0x8A, 0x42, 0xCA, 0x3E, 0x6B,
0xB1, 0x77, 0x13, 0x4F, 0xAB, 0xB6, 0xBD, 0xE2, 0x2E, 0xFD, 0xD4, 0x30, 0x73, 0x08, 0x83, 0x9F,
0xEC, 0x51, 0x51, 0x2E, 0xCD, 0x15, 0xD0, 0xA2, 0x37, 0x03, 0x4F, 0x6C, 0xF0, 0xCF, 0x98, 0xAE,
0x46, 0xE9, 0x51, 0x8A, 0x78, 0xC3, 0x8A, 0x49, 0xF4, 0xA0, 0xBC, 0x62, 0x94, 0x68, 0xFD, 0xDE,
0xA6, 0x9A, 0x08, 0xAD, 0x02, 0xF7, 0x1C, 0xD4, 0x19, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
vb_add_array(&file, linkedit_segment_content);
#define CHECK 0
#if CHECK
auto foo = file_read(thread->arena, strlit("C:/Users/David/dev/minimal_macos/minimal_macos"));
assert(file.length == foo.length);
for (u32 i = 0; i < file.length; i += 1)
{
auto mine = file.pointer[i];
auto original = foo.pointer[i];
assert(mine == original);
}
#endif
return (String) { file.pointer, file.length };
} }
fn void code_generation(Thread* restrict thread, CodegenOptions options) fn void code_generation(Thread* restrict thread, CodegenOptions options)
@ -14179,21 +14643,54 @@ fn void code_generation(Thread* restrict thread, CodegenOptions options)
case COMPILER_BACKEND_MACHINE: case COMPILER_BACKEND_MACHINE:
{ {
auto code_slice = (Slice(u8)) { .pointer = code.pointer, .length = code.length, }; auto code_slice = (Slice(u8)) { .pointer = code.pointer, .length = code.length, };
auto object_options = (ObjectOptions) { auto options = (ObjectOptions) {
.object_path = object_path, .object_path = object_path,
.exe_path = exe_path, .exe_path = exe_path,
.code = code_slice, .code = code_slice,
.dynamic = 1, .dynamic = 1,
}; };
String executable =
#if _WIN32 #if _WIN32
write_pe(thread, object_options); write_pe(thread, options);
#elif defined(__APPLE__) #elif defined(__APPLE__)
write_macho(thread, object_options, envp); write_macho(thread, options);
#elif defined(__linux__) #elif defined(__linux__)
write_elf(thread, object_options); write_elf(thread, options);
#else #else
todo(); todo();
#endif #endif
{
auto fd = os_file_open(options.exe_path, (OSFileOpenFlags) {
.write = 1,
.truncate = 1,
.create = 1,
.executable = 1,
});
#if _WIN32
if (!os_file_descriptor_is_valid(fd))
{
auto err = GetLastError();
LPSTR lpMsgBuf;
DWORD bufSize = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
LANG_NEUTRAL, // Use default language
(LPSTR)&lpMsgBuf,
0,
NULL
);
unused(bufSize);
print("Error opening file \"{s}\": {cstr}\n", options.exe_path, lpMsgBuf);
fail();
}
#endif
assert(os_file_descriptor_is_valid(fd));
os_file_write(fd, (String) { executable.pointer, executable.length });
os_file_close(fd);
}
} break; } break;
} }
} }