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
.github/workflows
bootstrap

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

@ -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))
{
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.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_add_array(vb, arr) memcpy(vb_add(vb, sizeof(arr)), arr, sizeof(arr))
may_be_unused fn Hash32 hash32_fib_end(Hash32 hash)
{
auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32);

@ -365,11 +365,11 @@ typedef enum ElfProgramHeaderType : u32
PT_SHLIB = 5,
PT_PHDR = 6,
PT_TLS = 7,
PT_GNU_EH_FRAME = 0x6474e550, /* GCC .eh_frame_hdr segment */
PT_GNU_STACK = 0x6474e551, /* Indicates stack executability */
PT_GNU_RELRO = 0x6474e552, /* Read-only after relocation */
PT_GNU_PROPERTY = 0x6474e553, /* GNU property */
PT_GNU_SFRAME = 0x6474e554, /* SFrame segment. */
PT_GNU_EH_FRAME = 0x6474e550, /* GCC .eh_frame_hdr segment */
PT_GNU_STACK = 0x6474e551, /* Indicates stack executability */
PT_GNU_RELRO = 0x6474e552, /* Read-only after relocation */
PT_GNU_PROPERTY = 0x6474e553, /* GNU property */
PT_GNU_SFRAME = 0x6474e554, /* SFrame segment. */
} ElfProgramHeaderType;
STRUCT(ElfProgramHeaderFlags)
@ -7960,10 +7960,13 @@ STRUCT(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* restrict builder = &builder_stack;
// Initialization
@ -8595,14 +8598,14 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
0x48, 0x83, 0xC4, 0x08,
0xC3,
};
// 1000: f3 0f 1e fa endbr64
// 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>
// 100f: 48 85 c0 test rax,rax
// 1012: 74 02 je 1016 <_init+0x16>
// 1014: ff d0 call rax
// 1016: 48 83 c4 08 add rsp,0x8
// 101a: c3 ret
// 1000: f3 0f 1e fa endbr64
// 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>
// 100f: 48 85 c0 test rax,rax
// 1012: 74 02 je 1016 <_init+0x16>
// 1014: ff d0 call rax
// 1016: 48 83 c4 08 add rsp,0x8
// 101a: c3 ret
*vb_add(&symbol_relocations, 1) = (SymbolRelocation){
.name = strlit("__gmon_start__"),
@ -8679,19 +8682,19 @@ may_be_unused fn void write_elf(Thread* thread, ObjectOptions options)
.offset = offset + 0x1f + 2,
};
// 1020: f3 0f 1e fa endbr64
// 1024: 31 ed xor ebp,ebp
// 1026: 49 89 d1 mov r9,rdx
// 1029: 5e pop rsi
// 102a: 48 89 e2 mov rdx,rsp
// 102d: 48 83 e4 f0 and rsp,0xfffffffffffffff0
// 1031: 50 push rax
// 1032: 54 push rsp
// 1033: 45 31 c0 xor r8d,r8d
// 1036: 31 c9 xor ecx,ecx
// 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>
// 1045: f4 hlt
// 1020: f3 0f 1e fa endbr64
// 1024: 31 ed xor ebp,ebp
// 1026: 49 89 d1 mov r9,rdx
// 1029: 5e pop rsi
// 102a: 48 89 e2 mov rdx,rsp
// 102d: 48 83 e4 f0 and rsp,0xfffffffffffffff0
// 1031: 50 push rax
// 1032: 54 push rsp
// 1033: 45 31 c0 xor r8d,r8d
// 1036: 31 c9 xor ecx,ecx
// 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>
// 1045: f4 hlt
_start_size = 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,
};
// 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__>
// 105e: 48 39 f8 cmp rax,rdi
// 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>
// 106a: 48 85 c0 test rax,rax
// 106d: 74 09 je 1078 <_start+0x58>
// 106f: ff e0 jmp rax
// 1071: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
// 1078: c3 ret
// 1079: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
// 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__>
// 105e: 48 39 f8 cmp rax,rdi
// 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>
// 106a: 48 85 c0 test rax,rax
// 106d: 74 09 je 1078 <_start+0x58>
// 106f: ff e0 jmp rax
// 1071: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
// 1078: c3 ret
// 1079: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
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,
};
// 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__>
// 108e: 48 29 fe sub rsi,rdi
// 1091: 48 89 f0 mov rax,rsi
// 1094: 48 c1 ee 3f shr rsi,0x3f
// 1098: 48 c1 f8 03 sar rax,0x3
// 109c: 48 01 c6 add rsi,rax
// 109f: 48 d1 fe sar rsi,1
// 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>
// 10ab: 48 85 c0 test rax,rax
// 10ae: 74 08 je 10b8 <_start+0x98>
// 10b0: ff e0 jmp rax
// 10b2: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
// 10b8: c3 ret
// 10b9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
// 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__>
// 108e: 48 29 fe sub rsi,rdi
// 1091: 48 89 f0 mov rax,rsi
// 1094: 48 c1 ee 3f shr rsi,0x3f
// 1098: 48 c1 f8 03 sar rax,0x3
// 109c: 48 01 c6 add rsi,rax
// 109f: 48 d1 fe sar rsi,1
// 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>
// 10ab: 48 85 c0 test rax,rax
// 10ae: 74 08 je 10b8 <_start+0x98>
// 10b0: ff e0 jmp rax
// 10b2: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
// 10b8: c3 ret
// 10b9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
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,
};
// 10c0: f3 0f 1e fa endbr64
// 10c4: 80 3d 45 2f 00 00 00 cmp BYTE PTR [rip+0x2f45],0x0 # 4010 <__TMC_END__>
// 10cb: 75 33 jne 1100 <_start+0xe0>
// 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>
// 10d5: 00
// 10d6: 48 89 e5 mov rbp,rsp
// 10d9: 74 0d je 10e8 <_start+0xc8>
// 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>
// 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__>
// 10f4: 5d pop rbp
// 10f5: c3 ret
// 10f6: 66 2e 0f 1f 84 00 00 cs nop WORD PTR [rax+rax*1+0x0]
// 10fd: 00 00 00
// 1100: c3 ret
// 1101: 66 66 2e 0f 1f 84 00 data16 cs nop WORD PTR [rax+rax*1+0x0]
// 1108: 00 00 00 00
// 110c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
// 10c0: f3 0f 1e fa endbr64
// 10c4: 80 3d 45 2f 00 00 00 cmp BYTE PTR [rip+0x2f45],0x0 # 4010 <__TMC_END__>
// 10cb: 75 33 jne 1100 <_start+0xe0>
// 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>
// 10d5: 00
// 10d6: 48 89 e5 mov rbp,rsp
// 10d9: 74 0d je 10e8 <_start+0xc8>
// 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>
// 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__>
// 10f4: 5d pop rbp
// 10f5: c3 ret
// 10f6: 66 2e 0f 1f 84 00 00 cs nop WORD PTR [rax+rax*1+0x0]
// 10fd: 00 00 00
// 1100: c3 ret
// 1101: 66 66 2e 0f 1f 84 00 data16 cs nop WORD PTR [rax+rax*1+0x0]
// 1108: 00 00 00 00
// 110c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
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,
};
// 1110: f3 0f 1e fa endbr64
// 1114: e9 67 ff ff ff jmp 1080 <_start+0x60>
// 1119: 0f 1f 00 nop DWORD PTR [rax]
// 1110: f3 0f 1e fa endbr64
// 1114: e9 67 ff ff ff jmp 1080 <_start+0x60>
// 1119: 0f 1f 00 nop DWORD PTR [rax]
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,
};
// 1120: f3 0f 1e fa endbr64
// 1124: 48 83 ec 08 sub rsp,0x8
// 1128: 48 83 c4 08 add rsp,0x8
// 112c: c3 ret
// 1120: f3 0f 1e fa endbr64
// 1124: 48 83 ec 08 sub rsp,0x8
// 1128: 48 83 c4 08 add rsp,0x8
// 112c: c3 ret
u32 size = sizeof(data);
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);
{
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);
}
return (String) { builder->file.pointer, builder->file.length };
}
STRUCT(DOSHeader)
@ -10909,7 +10902,7 @@ fn COFFSectionName coff_section_name(String name)
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 = {};
auto* mz = "MZ";
@ -11138,36 +11131,7 @@ may_be_unused fn void write_pe(Thread* thread, ObjectOptions options)
unused(thread);
#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) { file.pointer, file.length });
os_file_close(fd);
}
return (String){ file.pointer, file.length };
}
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;
}
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(options);
unused(envp);
todo();
VirtualBuffer(u8) file = {};
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)
@ -14179,21 +14643,54 @@ fn void code_generation(Thread* restrict thread, CodegenOptions options)
case COMPILER_BACKEND_MACHINE:
{
auto code_slice = (Slice(u8)) { .pointer = code.pointer, .length = code.length, };
auto object_options = (ObjectOptions) {
auto options = (ObjectOptions) {
.object_path = object_path,
.exe_path = exe_path,
.code = code_slice,
.dynamic = 1,
};
String executable =
#if _WIN32
write_pe(thread, object_options);
write_pe(thread, options);
#elif defined(__APPLE__)
write_macho(thread, object_options, envp);
write_macho(thread, options);
#elif defined(__linux__)
write_elf(thread, object_options);
write_elf(thread, options);
#else
todo();
#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;
}
}