| ... | @@ -27,6 +27,10 @@ const LoadCommand = union(enum) { | ... | @@ -27,6 +27,10 @@ const LoadCommand = union(enum) { |
| 27 | LinkeditData: macho.linkedit_data_command, | 27 | LinkeditData: macho.linkedit_data_command, |
| 28 | Symtab: macho.symtab_command, | 28 | Symtab: macho.symtab_command, |
| 29 | Dysymtab: macho.dysymtab_command, | 29 | Dysymtab: macho.dysymtab_command, |
| | 30 | DyldInfo: macho.dyld_info_command, |
| | 31 | Dylinker: macho.dylinker_command, |
| | 32 | Dylib: macho.dylib_command, |
| | 33 | EntryPoint: macho.entry_point_command, |
| 30 | | 34 | |
| 31 | pub fn cmdsize(self: LoadCommand) u32 { | 35 | pub fn cmdsize(self: LoadCommand) u32 { |
| 32 | return switch (self) { | 36 | return switch (self) { |
| ... | @@ -34,6 +38,10 @@ const LoadCommand = union(enum) { | ... | @@ -34,6 +38,10 @@ const LoadCommand = union(enum) { |
| 34 | .LinkeditData => |x| x.cmdsize, | 38 | .LinkeditData => |x| x.cmdsize, |
| 35 | .Symtab => |x| x.cmdsize, | 39 | .Symtab => |x| x.cmdsize, |
| 36 | .Dysymtab => |x| x.cmdsize, | 40 | .Dysymtab => |x| x.cmdsize, |
| | 41 | .DyldInfo => |x| x.cmdsize, |
| | 42 | .Dylinker => |x| x.cmdsize, |
| | 43 | .Dylib => |x| x.cmdsize, |
| | 44 | .EntryPoint => |x| x.cmdsize, |
| 37 | }; | 45 | }; |
| 38 | } | 46 | } |
| 39 | | 47 | |
| ... | @@ -43,6 +51,10 @@ const LoadCommand = union(enum) { | ... | @@ -43,6 +51,10 @@ const LoadCommand = union(enum) { |
| 43 | .LinkeditData => |cmd| writeGeneric(cmd, file, offset), | 51 | .LinkeditData => |cmd| writeGeneric(cmd, file, offset), |
| 44 | .Symtab => |cmd| writeGeneric(cmd, file, offset), | 52 | .Symtab => |cmd| writeGeneric(cmd, file, offset), |
| 45 | .Dysymtab => |cmd| writeGeneric(cmd, file, offset), | 53 | .Dysymtab => |cmd| writeGeneric(cmd, file, offset), |
| | 54 | .DyldInfo => |cmd| writeGeneric(cmd, file, offset), |
| | 55 | .Dylinker => |cmd| writeGeneric(cmd, file, offset), |
| | 56 | .Dylib => |cmd| writeGeneric(cmd, file, offset), |
| | 57 | .EntryPoint => |cmd| writeGeneric(cmd, file, offset), |
| 46 | }; | 58 | }; |
| 47 | } | 59 | } |
| 48 | | 60 | |
| ... | @@ -56,30 +68,52 @@ base: File, | ... | @@ -56,30 +68,52 @@ base: File, |
| 56 | | 68 | |
| 57 | /// Table of all load commands | 69 | /// Table of all load commands |
| 58 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 70 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 59 | segment_cmd_index: ?u16 = null, | 71 | /// __PAGEZERO segment |
| | 72 | pagezero_segment_cmd_index: ?u16 = null, |
| | 73 | /// __TEXT segment |
| | 74 | text_segment_cmd_index: ?u16 = null, |
| | 75 | /// __DATA segment |
| | 76 | data_segment_cmd_index: ?u16 = null, |
| | 77 | /// __LINKEDIT segment |
| | 78 | linkedit_segment_cmd_index: ?u16 = null, |
| | 79 | /// Dyld info |
| | 80 | dyld_info_cmd_index: ?u16 = null, |
| | 81 | /// Symbol table |
| 60 | symtab_cmd_index: ?u16 = null, | 82 | symtab_cmd_index: ?u16 = null, |
| | 83 | /// Dynamic symbol table |
| 61 | dysymtab_cmd_index: ?u16 = null, | 84 | dysymtab_cmd_index: ?u16 = null, |
| | 85 | /// Path to dyld linker |
| | 86 | dylinker_cmd_index: ?u16 = null, |
| | 87 | /// Path to libSystem |
| | 88 | libsystem_cmd_index: ?u16 = null, |
| | 89 | /// Data-in-code section of __LINKEDIT segment |
| 62 | data_in_code_cmd_index: ?u16 = null, | 90 | data_in_code_cmd_index: ?u16 = null, |
| | 91 | /// Address to entry point function |
| | 92 | function_starts_cmd_index: ?u16 = null, |
| | 93 | /// Main/entry point |
| | 94 | /// Specifies offset wrt __TEXT segment start address to the main entry point |
| | 95 | /// of the binary. |
| | 96 | main_cmd_index: ?u16 = null, |
| 63 | | 97 | |
| 64 | /// Table of all sections | 98 | /// Table of all sections |
| 65 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, | 99 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, |
| 66 | | 100 | |
| 67 | /// __TEXT segment sections | 101 | /// __TEXT,__text section |
| 68 | text_section_index: ?u16 = null, | 102 | text_section_index: ?u16 = null, |
| 69 | cstring_section_index: ?u16 = null, | | |
| 70 | const_text_section_index: ?u16 = null, | | |
| 71 | stubs_section_index: ?u16 = null, | | |
| 72 | stub_helper_section_index: ?u16 = null, | | |
| 73 | | 103 | |
| 74 | /// __DATA segment sections | 104 | /// __DATA,__got section |
| 75 | got_section_index: ?u16 = null, | 105 | got_section_index: ?u16 = null, |
| 76 | const_data_section_index: ?u16 = null, | | |
| 77 | | 106 | |
| 78 | entry_addr: ?u64 = null, | 107 | entry_addr: ?u64 = null, |
| 79 | | 108 | |
| 80 | /// Table of all symbols used. | 109 | /// Table of all local symbols |
| 81 | /// Internally references string table for names (which are optional). | 110 | /// Internally references string table for names (which are optional). |
| 82 | symbol_table: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 111 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| | 112 | /// Table of all defined global symbols |
| | 113 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| | 114 | /// Table of all undefined symbols |
| | 115 | undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| | 116 | dyld_stub_binder_index: ?u16 = null, |
| 83 | | 117 | |
| 84 | /// Table of symbol names aka the string table. | 118 | /// Table of symbol names aka the string table. |
| 85 | string_table: std.ArrayListUnmanaged(u8) = .{}, | 119 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| ... | @@ -115,19 +149,27 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System"; | ... | @@ -115,19 +149,27 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System"; |
| 115 | const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib"; | 149 | const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib"; |
| 116 | | 150 | |
| 117 | pub const TextBlock = struct { | 151 | pub const TextBlock = struct { |
| 118 | /// Index into the symbol table | 152 | /// Each decl always gets a local symbol with the fully qualified name. |
| 119 | symbol_table_index: ?u32, | 153 | /// The vaddr and size are found here directly. |
| | 154 | /// The file offset is found by computing the vaddr offset from the section vaddr |
| | 155 | /// the symbol references, and adding that to the file offset of the section. |
| | 156 | /// If this field is 0, it means the codegen size = 0 and there is no symbol or |
| | 157 | /// offset table entry. |
| | 158 | local_sym_index: u32, |
| 120 | /// Index into offset table | 159 | /// Index into offset table |
| 121 | offset_table_index: ?u32, | 160 | /// This field is undefined for symbols with size = 0. |
| | 161 | offset_table_index: u32, |
| 122 | /// Size of this text block | 162 | /// Size of this text block |
| | 163 | /// Unlike in Elf, we need to store the size of this symbol as part of |
| | 164 | /// the TextBlock since macho.nlist_64 lacks this information. |
| 123 | size: u64, | 165 | size: u64, |
| 124 | /// Points to the previous and next neighbours | 166 | /// Points to the previous and next neighbours |
| 125 | prev: ?*TextBlock, | 167 | prev: ?*TextBlock, |
| 126 | next: ?*TextBlock, | 168 | next: ?*TextBlock, |
| 127 | | 169 | |
| 128 | pub const empty = TextBlock{ | 170 | pub const empty = TextBlock{ |
| 129 | .symbol_table_index = null, | 171 | .local_sym_index = 0, |
| 130 | .offset_table_index = null, | 172 | .offset_table_index = undefined, |
| 131 | .size = 0, | 173 | .size = 0, |
| 132 | .prev = null, | 174 | .prev = null, |
| 133 | .next = null, | 175 | .next = null, |
| ... | @@ -156,6 +198,15 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -156,6 +198,15 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 156 | | 198 | |
| 157 | self.base.file = file; | 199 | self.base.file = file; |
| 158 | | 200 | |
| | 201 | // Index 0 is always a null symbol. |
| | 202 | try self.local_symbols.append(allocator, .{ |
| | 203 | .n_strx = 0, |
| | 204 | .n_type = 0, |
| | 205 | .n_sect = 0, |
| | 206 | .n_desc = 0, |
| | 207 | .n_value = 0, |
| | 208 | }); |
| | 209 | |
| 159 | switch (options.output_mode) { | 210 | switch (options.output_mode) { |
| 160 | .Exe => {}, | 211 | .Exe => {}, |
| 161 | .Obj => {}, | 212 | .Obj => {}, |
| ... | @@ -196,88 +247,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -196,88 +247,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 196 | const tracy = trace(@src()); | 247 | const tracy = trace(@src()); |
| 197 | defer tracy.end(); | 248 | defer tracy.end(); |
| 198 | | 249 | |
| | 250 | // Unfortunately these have to be buffered and done at the end because MachO does not allow |
| | 251 | // mixing local, global and undefined symbols within a symbol table. |
| | 252 | try self.writeAllGlobalSymbols(); |
| | 253 | try self.writeAllUndefSymbols(); |
| | 254 | |
| | 255 | try self.writeStringTable(); |
| | 256 | |
| 199 | switch (self.base.options.output_mode) { | 257 | switch (self.base.options.output_mode) { |
| 200 | .Exe => { | 258 | .Exe => { |
| 201 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); | 259 | if (self.entry_addr) |addr| { |
| 202 | { | 260 | // Write export trie. |
| 203 | // Specify path to dynamic linker dyld | 261 | try self.writeExportTrie(); |
| 204 | const cmdsize = commandSize(@sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH)); | 262 | |
| 205 | const load_dylinker = [1]macho.dylinker_command{ | 263 | // Update LC_MAIN with entry offset |
| 206 | .{ | 264 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 207 | .cmd = macho.LC_LOAD_DYLINKER, | 265 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| 208 | .cmdsize = cmdsize, | 266 | main_cmd.entryoff = addr - text_segment.vmaddr; |
| 209 | .name = @sizeOf(macho.dylinker_command), | | |
| 210 | }, | | |
| 211 | }; | | |
| 212 | | | |
| 213 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylinker[0..1]), last_cmd_offset); | | |
| 214 | | | |
| 215 | const file_offset = last_cmd_offset + @sizeOf(macho.dylinker_command); | | |
| 216 | try self.addPadding(cmdsize - @sizeOf(macho.dylinker_command), file_offset); | | |
| 217 | | | |
| 218 | try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), file_offset); | | |
| 219 | last_cmd_offset += cmdsize; | | |
| 220 | } | 267 | } |
| 221 | | 268 | |
| 222 | { | 269 | { |
| 223 | // Link against libSystem | 270 | // Update dynamic symbol table. |
| 224 | const cmdsize = commandSize(@sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH)); | 271 | const nlocals = @intCast(u32, self.local_symbols.items.len); |
| 225 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. | 272 | const nglobals = @intCast(u32, self.global_symbols.items.len); |
| 226 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0. | 273 | const nundefs = @intCast(u32, self.undef_symbols.items.len); |
| 227 | const min_version = 0x10000; | 274 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 228 | const dylib = .{ | 275 | dysymtab.nlocalsym = nlocals; |
| 229 | .name = @sizeOf(macho.dylib_command), | 276 | dysymtab.iextdefsym = nlocals; |
| 230 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files | 277 | dysymtab.nextdefsym = nglobals; |
| 231 | .current_version = min_version, | 278 | dysymtab.iundefsym = nlocals + nglobals; |
| 232 | .compatibility_version = min_version, | 279 | dysymtab.nundefsym = nundefs; |
| 233 | }; | | |
| 234 | const load_dylib = [1]macho.dylib_command{ | | |
| 235 | .{ | | |
| 236 | .cmd = macho.LC_LOAD_DYLIB, | | |
| 237 | .cmdsize = cmdsize, | | |
| 238 | .dylib = dylib, | | |
| 239 | }, | | |
| 240 | }; | | |
| 241 | | | |
| 242 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylib[0..1]), last_cmd_offset); | | |
| 243 | | | |
| 244 | const file_offset = last_cmd_offset + @sizeOf(macho.dylib_command); | | |
| 245 | try self.addPadding(cmdsize - @sizeOf(macho.dylib_command), file_offset); | | |
| 246 | | | |
| 247 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), file_offset); | | |
| 248 | last_cmd_offset += cmdsize; | | |
| 249 | } | 280 | } |
| 250 | }, | | |
| 251 | .Obj => { | | |
| 252 | { | 281 | { |
| 253 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 282 | // Write path to dyld loader. |
| 254 | symtab.nsyms = @intCast(u32, self.symbol_table.items.len); | 283 | var off: usize = @sizeOf(macho.mach_header_64); |
| 255 | const allocated_size = self.allocatedSize(symtab.stroff); | 284 | for (self.load_commands.items) |cmd| { |
| 256 | const needed_size = self.string_table.items.len; | 285 | if (cmd == .Dylinker) break; |
| 257 | log.debug("allocated_size = 0x{x}, needed_size = 0x{x}\n", .{ allocated_size, needed_size }); | 286 | off += cmd.cmdsize(); |
| 258 | | | |
| 259 | if (needed_size > allocated_size) { | | |
| 260 | symtab.strsize = 0; | | |
| 261 | symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1)); | | |
| 262 | } | 287 | } |
| 263 | symtab.strsize = @intCast(u32, needed_size); | 288 | const cmd = &self.load_commands.items[self.dylinker_cmd_index.?].Dylinker; |
| 264 | | 289 | off += cmd.name; |
| 265 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); | 290 | const padding = cmd.cmdsize - @sizeOf(macho.dylinker_command); |
| 266 | | 291 | log.debug("writing LC_LOAD_DYLINKER padding of size {} at 0x{x}\n", .{ padding, off }); |
| 267 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); | 292 | try self.addPadding(padding, off); |
| | 293 | log.debug("writing LC_LOAD_DYLINKER path to dyld at 0x{x}\n", .{off}); |
| | 294 | try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), off); |
| 268 | } | 295 | } |
| 269 | | 296 | { |
| 270 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); | 297 | // Write path to libSystem. |
| 271 | for (self.load_commands.items) |cmd| { | 298 | var off: usize = @sizeOf(macho.mach_header_64); |
| 272 | try cmd.write(&self.base.file.?, last_cmd_offset); | 299 | for (self.load_commands.items) |cmd| { |
| 273 | last_cmd_offset += cmd.cmdsize(); | 300 | if (cmd == .Dylib) break; |
| | 301 | off += cmd.cmdsize(); |
| | 302 | } |
| | 303 | const cmd = &self.load_commands.items[self.libsystem_cmd_index.?].Dylib; |
| | 304 | off += cmd.dylib.name; |
| | 305 | const padding = cmd.cmdsize - @sizeOf(macho.dylib_command); |
| | 306 | log.debug("writing LC_LOAD_DYLIB padding of size {} at 0x{x}\n", .{ padding, off }); |
| | 307 | try self.addPadding(padding, off); |
| | 308 | log.debug("writing LC_LOAD_DYLIB path to libSystem at 0x{x}\n", .{off}); |
| | 309 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); |
| 274 | } | 310 | } |
| 275 | const off = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); | | |
| 276 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items), off); | | |
| 277 | }, | 311 | }, |
| | 312 | .Obj => {}, |
| 278 | .Lib => return error.TODOImplementWritingLibFiles, | 313 | .Lib => return error.TODOImplementWritingLibFiles, |
| 279 | } | 314 | } |
| 280 | | 315 | |
| | 316 | if (self.cmd_table_dirty) try self.writeCmdHeaders(); |
| | 317 | |
| | 318 | { |
| | 319 | // Update symbol table. |
| | 320 | const nlocals = @intCast(u32, self.local_symbols.items.len); |
| | 321 | const nglobals = @intCast(u32, self.global_symbols.items.len); |
| | 322 | const nundefs = @intCast(u32, self.undef_symbols.items.len); |
| | 323 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 324 | symtab.nsyms = nlocals + nglobals + nundefs; |
| | 325 | } |
| | 326 | |
| 281 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | 327 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 282 | log.debug("flushing. no_entry_point_found = true\n", .{}); | 328 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 283 | self.error_flags.no_entry_point_found = true; | 329 | self.error_flags.no_entry_point_found = true; |
| ... | @@ -669,32 +715,34 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { | ... | @@ -669,32 +715,34 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { |
| 669 | pub fn deinit(self: *MachO) void { | 715 | pub fn deinit(self: *MachO) void { |
| 670 | self.offset_table.deinit(self.base.allocator); | 716 | self.offset_table.deinit(self.base.allocator); |
| 671 | self.string_table.deinit(self.base.allocator); | 717 | self.string_table.deinit(self.base.allocator); |
| 672 | self.symbol_table.deinit(self.base.allocator); | 718 | self.undef_symbols.deinit(self.base.allocator); |
| | 719 | self.global_symbols.deinit(self.base.allocator); |
| | 720 | self.local_symbols.deinit(self.base.allocator); |
| 673 | self.sections.deinit(self.base.allocator); | 721 | self.sections.deinit(self.base.allocator); |
| 674 | self.load_commands.deinit(self.base.allocator); | 722 | self.load_commands.deinit(self.base.allocator); |
| 675 | } | 723 | } |
| 676 | | 724 | |
| 677 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | 725 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 678 | if (decl.link.macho.symbol_table_index) |_| return; | 726 | if (decl.link.macho.local_sym_index != 0) return; |
| 679 | | 727 | |
| 680 | try self.symbol_table.ensureCapacity(self.base.allocator, self.symbol_table.items.len + 1); | 728 | try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); |
| 681 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); | 729 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); |
| 682 | | 730 | |
| 683 | log.debug("allocating symbol index {} for {}\n", .{ self.symbol_table.items.len, decl.name }); | 731 | log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); |
| 684 | decl.link.macho.symbol_table_index = @intCast(u32, self.symbol_table.items.len); | 732 | decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len); |
| 685 | _ = self.symbol_table.addOneAssumeCapacity(); | 733 | _ = self.local_symbols.addOneAssumeCapacity(); |
| 686 | | 734 | |
| 687 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); | 735 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); |
| 688 | _ = self.offset_table.addOneAssumeCapacity(); | 736 | _ = self.offset_table.addOneAssumeCapacity(); |
| 689 | | 737 | |
| 690 | self.symbol_table.items[decl.link.macho.symbol_table_index.?] = .{ | 738 | self.local_symbols.items[decl.link.macho.local_sym_index] = .{ |
| 691 | .n_strx = 0, | 739 | .n_strx = 0, |
| 692 | .n_type = 0, | 740 | .n_type = 0, |
| 693 | .n_sect = 0, | 741 | .n_sect = 0, |
| 694 | .n_desc = 0, | 742 | .n_desc = 0, |
| 695 | .n_value = 0, | 743 | .n_value = 0, |
| 696 | }; | 744 | }; |
| 697 | self.offset_table.items[decl.link.macho.offset_table_index.?] = 0; | 745 | self.offset_table.items[decl.link.macho.offset_table_index] = 0; |
| 698 | } | 746 | } |
| 699 | | 747 | |
| 700 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | 748 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| ... | @@ -716,16 +764,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -716,16 +764,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 716 | return; | 764 | return; |
| 717 | }, | 765 | }, |
| 718 | }; | 766 | }; |
| 719 | log.debug("generated code {}\n", .{code}); | | |
| 720 | | 767 | |
| 721 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 768 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 722 | const symbol = &self.symbol_table.items[decl.link.macho.symbol_table_index.?]; | 769 | const symbol = &self.local_symbols.items[decl.link.macho.local_sym_index]; |
| 723 | | 770 | |
| 724 | const decl_name = mem.spanZ(decl.name); | 771 | const decl_name = mem.spanZ(decl.name); |
| 725 | const name_str_index = try self.makeString(decl_name); | 772 | const name_str_index = try self.makeString(decl_name); |
| 726 | const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment); | 773 | const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment); |
| 727 | log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, addr }); | 774 | log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, addr }); |
| 728 | log.debug("updated text section {}\n", .{self.sections.items[self.text_section_index.?]}); | | |
| 729 | | 775 | |
| 730 | symbol.* = .{ | 776 | symbol.* = .{ |
| 731 | .n_strx = name_str_index, | 777 | .n_strx = name_str_index, |
| ... | @@ -734,18 +780,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -734,18 +780,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 734 | .n_desc = 0, | 780 | .n_desc = 0, |
| 735 | .n_value = addr, | 781 | .n_value = addr, |
| 736 | }; | 782 | }; |
| | 783 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; |
| 737 | | 784 | |
| 738 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. | 785 | try self.writeSymbol(decl.link.macho.local_sym_index); |
| 739 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; | 786 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 740 | try self.updateDeclExports(module, decl, decl_exports); | | |
| 741 | try self.writeSymbol(decl.link.macho.symbol_table_index.?); | | |
| 742 | | 787 | |
| 743 | const text_section = self.sections.items[self.text_section_index.?]; | 788 | const text_section = self.sections.items[self.text_section_index.?]; |
| 744 | const section_offset = symbol.n_value - text_section.addr; | 789 | const section_offset = symbol.n_value - text_section.addr; |
| 745 | const file_offset = text_section.offset + section_offset; | 790 | const file_offset = text_section.offset + section_offset; |
| 746 | log.debug("file_offset 0x{x}\n", .{file_offset}); | | |
| 747 | | 791 | |
| 748 | try self.base.file.?.pwriteAll(code, file_offset); | 792 | try self.base.file.?.pwriteAll(code, file_offset); |
| | 793 | |
| | 794 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. |
| | 795 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; |
| | 796 | try self.updateDeclExports(module, decl, decl_exports); |
| 749 | } | 797 | } |
| 750 | | 798 | |
| 751 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} | 799 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} |
| ... | @@ -759,34 +807,89 @@ pub fn updateDeclExports( | ... | @@ -759,34 +807,89 @@ pub fn updateDeclExports( |
| 759 | const tracy = trace(@src()); | 807 | const tracy = trace(@src()); |
| 760 | defer tracy.end(); | 808 | defer tracy.end(); |
| 761 | | 809 | |
| 762 | if (decl.link.macho.symbol_table_index == null) return; | 810 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); |
| 763 | | 811 | if (decl.link.macho.local_sym_index == 0) return; |
| 764 | const decl_sym = &self.symbol_table.items[decl.link.macho.symbol_table_index.?]; | 812 | const decl_sym = &self.local_symbols.items[decl.link.macho.local_sym_index]; |
| 765 | // TODO implement | 813 | |
| 766 | if (exports.len == 0) return; | 814 | for (exports) |exp| { |
| 767 | | 815 | if (exp.options.section) |section_name| { |
| 768 | const exp = exports[0]; | 816 | if (!mem.eql(u8, section_name, "__text")) { |
| 769 | self.entry_addr = decl_sym.n_value; | 817 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); |
| 770 | decl_sym.n_type |= macho.N_EXT; | 818 | module.failed_exports.putAssumeCapacityNoClobber( |
| 771 | exp.link.sym_index = 0; | 819 | exp, |
| | 820 | try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), |
| | 821 | ); |
| | 822 | continue; |
| | 823 | } |
| | 824 | } |
| | 825 | const n_desc = switch (exp.options.linkage) { |
| | 826 | .Internal => macho.REFERENCE_FLAG_PRIVATE_DEFINED, |
| | 827 | .Strong => blk: { |
| | 828 | if (mem.eql(u8, exp.options.name, "_start")) { |
| | 829 | self.entry_addr = decl_sym.n_value; |
| | 830 | } |
| | 831 | break :blk macho.REFERENCE_FLAG_DEFINED; |
| | 832 | }, |
| | 833 | .Weak => macho.N_WEAK_REF, |
| | 834 | .LinkOnce => { |
| | 835 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); |
| | 836 | module.failed_exports.putAssumeCapacityNoClobber( |
| | 837 | exp, |
| | 838 | try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), |
| | 839 | ); |
| | 840 | continue; |
| | 841 | }, |
| | 842 | }; |
| | 843 | const n_type = decl_sym.n_type | macho.N_EXT; |
| | 844 | if (exp.link.sym_index) |i| { |
| | 845 | const sym = &self.global_symbols.items[i]; |
| | 846 | sym.* = .{ |
| | 847 | .n_strx = try self.updateString(sym.n_strx, exp.options.name), |
| | 848 | .n_type = n_type, |
| | 849 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, |
| | 850 | .n_desc = n_desc, |
| | 851 | .n_value = decl_sym.n_value, |
| | 852 | }; |
| | 853 | } else { |
| | 854 | const name_str_index = try self.makeString(exp.options.name); |
| | 855 | _ = self.global_symbols.addOneAssumeCapacity(); |
| | 856 | const i = self.global_symbols.items.len - 1; |
| | 857 | self.global_symbols.items[i] = .{ |
| | 858 | .n_strx = name_str_index, |
| | 859 | .n_type = n_type, |
| | 860 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, |
| | 861 | .n_desc = n_desc, |
| | 862 | .n_value = decl_sym.n_value, |
| | 863 | }; |
| | 864 | |
| | 865 | exp.link.sym_index = @intCast(u32, i); |
| | 866 | } |
| | 867 | } |
| 772 | } | 868 | } |
| 773 | | 869 | |
| 774 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} | 870 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} |
| 775 | | 871 | |
| 776 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | 872 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 777 | return self.symbol_table.items[decl.link.macho.symbol_table_index.?].n_value; | 873 | assert(decl.link.macho.local_sym_index != 0); |
| | 874 | return self.local_symbols.items[decl.link.macho.local_sym_index].n_value; |
| 778 | } | 875 | } |
| 779 | | 876 | |
| 780 | pub fn populateMissingMetadata(self: *MachO) !void { | 877 | pub fn populateMissingMetadata(self: *MachO) !void { |
| 781 | if (self.segment_cmd_index == null) { | 878 | switch (self.base.options.output_mode) { |
| 782 | self.segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 879 | .Exe => {}, |
| | 880 | .Obj => return error.TODOImplementWritingObjFiles, |
| | 881 | .Lib => return error.TODOImplementWritingLibFiles, |
| | 882 | } |
| | 883 | |
| | 884 | if (self.pagezero_segment_cmd_index == null) { |
| | 885 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 783 | try self.load_commands.append(self.base.allocator, .{ | 886 | try self.load_commands.append(self.base.allocator, .{ |
| 784 | .Segment = .{ | 887 | .Segment = .{ |
| 785 | .cmd = macho.LC_SEGMENT_64, | 888 | .cmd = macho.LC_SEGMENT_64, |
| 786 | .cmdsize = @sizeOf(macho.segment_command_64), | 889 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 787 | .segname = makeStaticString(""), | 890 | .segname = makeStaticString("__PAGEZERO"), |
| 788 | .vmaddr = 0, | 891 | .vmaddr = 0, |
| 789 | .vmsize = 0, | 892 | .vmsize = 0x100000000, // size always set to 4GB |
| 790 | .fileoff = 0, | 893 | .fileoff = 0, |
| 791 | .filesize = 0, | 894 | .filesize = 0, |
| 792 | .maxprot = 0, | 895 | .maxprot = 0, |
| ... | @@ -797,28 +900,34 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -797,28 +900,34 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 797 | }); | 900 | }); |
| 798 | self.cmd_table_dirty = true; | 901 | self.cmd_table_dirty = true; |
| 799 | } | 902 | } |
| 800 | if (self.symtab_cmd_index == null) { | 903 | if (self.text_segment_cmd_index == null) { |
| 801 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 904 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 905 | const prot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE; |
| 802 | try self.load_commands.append(self.base.allocator, .{ | 906 | try self.load_commands.append(self.base.allocator, .{ |
| 803 | .Symtab = .{ | 907 | .Segment = .{ |
| 804 | .cmd = macho.LC_SYMTAB, | 908 | .cmd = macho.LC_SEGMENT_64, |
| 805 | .cmdsize = @sizeOf(macho.symtab_command), | 909 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 806 | .symoff = 0, | 910 | .segname = makeStaticString("__TEXT"), |
| 807 | .nsyms = 0, | 911 | .vmaddr = 0x100000000, // always starts at 4GB |
| 808 | .stroff = 0, | 912 | .vmsize = 0, |
| 809 | .strsize = 0, | 913 | .fileoff = 0, |
| | 914 | .filesize = 0, |
| | 915 | .maxprot = prot, |
| | 916 | .initprot = prot, |
| | 917 | .nsects = 0, |
| | 918 | .flags = 0, |
| 810 | }, | 919 | }, |
| 811 | }); | 920 | }); |
| 812 | self.cmd_table_dirty = true; | 921 | self.cmd_table_dirty = true; |
| 813 | } | 922 | } |
| 814 | if (self.text_section_index == null) { | 923 | if (self.text_section_index == null) { |
| 815 | self.text_section_index = @intCast(u16, self.sections.items.len); | 924 | self.text_section_index = @intCast(u16, self.sections.items.len); |
| 816 | const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment; | 925 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 817 | segment.cmdsize += @sizeOf(macho.section_64); | 926 | text_segment.cmdsize += @sizeOf(macho.section_64); |
| 818 | segment.nsects += 1; | 927 | text_segment.nsects += 1; |
| 819 | | 928 | |
| 820 | const file_size = self.base.options.program_code_size_hint; | 929 | const file_size = mem.alignForwardGeneric(u64, self.base.options.program_code_size_hint, 0x1000); |
| 821 | const off = @intCast(u32, self.findFreeSpace(file_size, 1)); | 930 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); // TODO maybe findFreeSpace should return u32 directly? |
| 822 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 931 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 823 | | 932 | |
| 824 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 933 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| ... | @@ -826,10 +935,10 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -826,10 +935,10 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 826 | try self.sections.append(self.base.allocator, .{ | 935 | try self.sections.append(self.base.allocator, .{ |
| 827 | .sectname = makeStaticString("__text"), | 936 | .sectname = makeStaticString("__text"), |
| 828 | .segname = makeStaticString("__TEXT"), | 937 | .segname = makeStaticString("__TEXT"), |
| 829 | .addr = 0, | 938 | .addr = text_segment.vmaddr + off, |
| 830 | .size = file_size, | 939 | .size = file_size, |
| 831 | .offset = off, | 940 | .offset = off, |
| 832 | .@"align" = 0x1000, | 941 | .@"align" = 12, // 2^12 = 4096 |
| 833 | .reloff = 0, | 942 | .reloff = 0, |
| 834 | .nreloc = 0, | 943 | .nreloc = 0, |
| 835 | .flags = flags, | 944 | .flags = flags, |
| ... | @@ -838,43 +947,256 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -838,43 +947,256 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 838 | .reserved3 = 0, | 947 | .reserved3 = 0, |
| 839 | }); | 948 | }); |
| 840 | | 949 | |
| 841 | segment.vmsize += file_size; | 950 | text_segment.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section. |
| 842 | segment.filesize += file_size; | 951 | text_segment.filesize = file_size + off; |
| 843 | segment.fileoff = off; | 952 | } |
| | 953 | if (self.data_segment_cmd_index == null) { |
| | 954 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 955 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 956 | const prot = macho.VM_PROT_READ | macho.VM_PROT_WRITE; |
| | 957 | try self.load_commands.append(self.base.allocator, .{ |
| | 958 | .Segment = .{ |
| | 959 | .cmd = macho.LC_SEGMENT_64, |
| | 960 | .cmdsize = @sizeOf(macho.segment_command_64), |
| | 961 | .segname = makeStaticString("__DATA"), |
| | 962 | .vmaddr = text_segment.vmaddr + text_segment.vmsize, |
| | 963 | .vmsize = 0, |
| | 964 | .fileoff = 0, |
| | 965 | .filesize = 0, |
| | 966 | .maxprot = prot, |
| | 967 | .initprot = prot, |
| | 968 | .nsects = 0, |
| | 969 | .flags = 0, |
| | 970 | }, |
| | 971 | }); |
| | 972 | self.cmd_table_dirty = true; |
| | 973 | } |
| | 974 | if (self.got_section_index == null) { |
| | 975 | self.got_section_index = @intCast(u16, self.sections.items.len); |
| | 976 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 977 | data_segment.cmdsize += @sizeOf(macho.section_64); |
| | 978 | data_segment.nsects += 1; |
| | 979 | |
| | 980 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| | 981 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| | 982 | |
| | 983 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| | 984 | |
| | 985 | try self.sections.append(self.base.allocator, .{ |
| | 986 | .sectname = makeStaticString("__got"), |
| | 987 | .segname = makeStaticString("__DATA"), |
| | 988 | .addr = data_segment.vmaddr, |
| | 989 | .size = file_size, |
| | 990 | .offset = off, |
| | 991 | .@"align" = 3, // 2^3 = 8 |
| | 992 | .reloff = 0, |
| | 993 | .nreloc = 0, |
| | 994 | .flags = macho.S_REGULAR, |
| | 995 | .reserved1 = 0, |
| | 996 | .reserved2 = 0, |
| | 997 | .reserved3 = 0, |
| | 998 | }); |
| 844 | | 999 | |
| 845 | log.debug("initial text section {}\n", .{self.sections.items[self.text_section_index.?]}); | 1000 | const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000); |
| | 1001 | data_segment.vmsize = segment_size; |
| | 1002 | data_segment.filesize = segment_size; |
| | 1003 | data_segment.fileoff = off; |
| | 1004 | } |
| | 1005 | if (self.linkedit_segment_cmd_index == null) { |
| | 1006 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1007 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 1008 | const prot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| | 1009 | try self.load_commands.append(self.base.allocator, .{ |
| | 1010 | .Segment = .{ |
| | 1011 | .cmd = macho.LC_SEGMENT_64, |
| | 1012 | .cmdsize = @sizeOf(macho.segment_command_64), |
| | 1013 | .segname = makeStaticString("__LINKEDIT"), |
| | 1014 | .vmaddr = data_segment.vmaddr + data_segment.vmsize, |
| | 1015 | .vmsize = 0, |
| | 1016 | .fileoff = 0, |
| | 1017 | .filesize = 0, |
| | 1018 | .maxprot = prot, |
| | 1019 | .initprot = prot, |
| | 1020 | .nsects = 0, |
| | 1021 | .flags = 0, |
| | 1022 | }, |
| | 1023 | }); |
| | 1024 | self.cmd_table_dirty = true; |
| | 1025 | } |
| | 1026 | if (self.dyld_info_cmd_index == null) { |
| | 1027 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1028 | try self.load_commands.append(self.base.allocator, .{ |
| | 1029 | .DyldInfo = .{ |
| | 1030 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| | 1031 | .cmdsize = @sizeOf(macho.dyld_info_command), |
| | 1032 | .rebase_off = 0, |
| | 1033 | .rebase_size = 0, |
| | 1034 | .bind_off = 0, |
| | 1035 | .bind_size = 0, |
| | 1036 | .weak_bind_off = 0, |
| | 1037 | .weak_bind_size = 0, |
| | 1038 | .lazy_bind_off = 0, |
| | 1039 | .lazy_bind_size = 0, |
| | 1040 | .export_off = 0, |
| | 1041 | .export_size = 0, |
| | 1042 | }, |
| | 1043 | }); |
| | 1044 | self.cmd_table_dirty = true; |
| | 1045 | } |
| | 1046 | if (self.symtab_cmd_index == null) { |
| | 1047 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1048 | try self.load_commands.append(self.base.allocator, .{ |
| | 1049 | .Symtab = .{ |
| | 1050 | .cmd = macho.LC_SYMTAB, |
| | 1051 | .cmdsize = @sizeOf(macho.symtab_command), |
| | 1052 | .symoff = 0, |
| | 1053 | .nsyms = 0, |
| | 1054 | .stroff = 0, |
| | 1055 | .strsize = 0, |
| | 1056 | }, |
| | 1057 | }); |
| | 1058 | self.cmd_table_dirty = true; |
| | 1059 | } |
| | 1060 | if (self.dysymtab_cmd_index == null) { |
| | 1061 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1062 | try self.load_commands.append(self.base.allocator, .{ |
| | 1063 | .Dysymtab = .{ |
| | 1064 | .cmd = macho.LC_DYSYMTAB, |
| | 1065 | .cmdsize = @sizeOf(macho.dysymtab_command), |
| | 1066 | .ilocalsym = 0, |
| | 1067 | .nlocalsym = 0, |
| | 1068 | .iextdefsym = 0, |
| | 1069 | .nextdefsym = 0, |
| | 1070 | .iundefsym = 0, |
| | 1071 | .nundefsym = 0, |
| | 1072 | .tocoff = 0, |
| | 1073 | .ntoc = 0, |
| | 1074 | .modtaboff = 0, |
| | 1075 | .nmodtab = 0, |
| | 1076 | .extrefsymoff = 0, |
| | 1077 | .nextrefsyms = 0, |
| | 1078 | .indirectsymoff = 0, |
| | 1079 | .nindirectsyms = 0, |
| | 1080 | .extreloff = 0, |
| | 1081 | .nextrel = 0, |
| | 1082 | .locreloff = 0, |
| | 1083 | .nlocrel = 0, |
| | 1084 | }, |
| | 1085 | }); |
| | 1086 | self.cmd_table_dirty = true; |
| | 1087 | } |
| | 1088 | if (self.dylinker_cmd_index == null) { |
| | 1089 | self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1090 | const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH), @sizeOf(u64)); |
| | 1091 | try self.load_commands.append(self.base.allocator, .{ |
| | 1092 | .Dylinker = .{ |
| | 1093 | .cmd = macho.LC_LOAD_DYLINKER, |
| | 1094 | .cmdsize = @intCast(u32, cmdsize), |
| | 1095 | .name = @sizeOf(macho.dylinker_command), |
| | 1096 | }, |
| | 1097 | }); |
| | 1098 | self.cmd_table_dirty = true; |
| | 1099 | } |
| | 1100 | if (self.libsystem_cmd_index == null) { |
| | 1101 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1102 | const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64)); |
| | 1103 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. |
| | 1104 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0. |
| | 1105 | const min_version = 0x10000; |
| | 1106 | const dylib = .{ |
| | 1107 | .name = @sizeOf(macho.dylib_command), |
| | 1108 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files |
| | 1109 | .current_version = min_version, |
| | 1110 | .compatibility_version = min_version, |
| | 1111 | }; |
| | 1112 | try self.load_commands.append(self.base.allocator, .{ |
| | 1113 | .Dylib = .{ |
| | 1114 | .cmd = macho.LC_LOAD_DYLIB, |
| | 1115 | .cmdsize = @intCast(u32, cmdsize), |
| | 1116 | .dylib = dylib, |
| | 1117 | }, |
| | 1118 | }); |
| | 1119 | self.cmd_table_dirty = true; |
| | 1120 | } |
| | 1121 | if (self.main_cmd_index == null) { |
| | 1122 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1123 | try self.load_commands.append(self.base.allocator, .{ |
| | 1124 | .EntryPoint = .{ |
| | 1125 | .cmd = macho.LC_MAIN, |
| | 1126 | .cmdsize = @sizeOf(macho.entry_point_command), |
| | 1127 | .entryoff = 0x0, |
| | 1128 | .stacksize = 0, |
| | 1129 | }, |
| | 1130 | }); |
| | 1131 | self.cmd_table_dirty = true; |
| | 1132 | } |
| | 1133 | { |
| | 1134 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1135 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| | 1136 | if (dyld_info.export_off == 0) { |
| | 1137 | const nsyms = self.base.options.symbol_count_hint; |
| | 1138 | const file_size = @sizeOf(u64) * nsyms; |
| | 1139 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| | 1140 | log.debug("found export trie free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| | 1141 | dyld_info.export_off = off; |
| | 1142 | dyld_info.export_size = @intCast(u32, file_size); |
| | 1143 | |
| | 1144 | const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000); |
| | 1145 | linkedit.vmsize += segment_size; |
| | 1146 | linkedit.fileoff = off; |
| | 1147 | } |
| 846 | } | 1148 | } |
| 847 | { | 1149 | { |
| | 1150 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 848 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1151 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 849 | if (symtab.symoff == 0) { | 1152 | if (symtab.symoff == 0) { |
| 850 | const p_align = @sizeOf(macho.nlist_64); | | |
| 851 | const nsyms = self.base.options.symbol_count_hint; | 1153 | const nsyms = self.base.options.symbol_count_hint; |
| 852 | const file_size = p_align * nsyms; | 1154 | const file_size = @sizeOf(macho.nlist_64) * nsyms; |
| 853 | const off = @intCast(u32, self.findFreeSpace(file_size, p_align)); | 1155 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| 854 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1156 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 855 | symtab.symoff = off; | 1157 | symtab.symoff = off; |
| 856 | symtab.nsyms = @intCast(u32, nsyms); | 1158 | symtab.nsyms = @intCast(u32, nsyms); |
| | 1159 | |
| | 1160 | const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000); |
| | 1161 | linkedit.vmsize += segment_size; |
| 857 | } | 1162 | } |
| 858 | if (symtab.stroff == 0) { | 1163 | if (symtab.stroff == 0) { |
| 859 | try self.string_table.append(self.base.allocator, 0); | 1164 | try self.string_table.append(self.base.allocator, 0); |
| 860 | const file_size = @intCast(u32, self.string_table.items.len); | 1165 | const file_size = @intCast(u32, self.string_table.items.len); |
| 861 | const off = @intCast(u32, self.findFreeSpace(file_size, 1)); | 1166 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| 862 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1167 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 863 | symtab.stroff = off; | 1168 | symtab.stroff = off; |
| 864 | symtab.strsize = file_size; | 1169 | symtab.strsize = file_size; |
| | 1170 | |
| | 1171 | const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000); |
| | 1172 | linkedit.vmsize += segment_size; |
| 865 | } | 1173 | } |
| 866 | } | 1174 | } |
| | 1175 | if (self.dyld_stub_binder_index == null) { |
| | 1176 | self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); |
| | 1177 | const name = try self.makeString("dyld_stub_binder"); |
| | 1178 | try self.undef_symbols.append(self.base.allocator, .{ |
| | 1179 | .n_strx = name, |
| | 1180 | .n_type = macho.N_UNDF | macho.N_EXT, |
| | 1181 | .n_sect = 0, |
| | 1182 | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, |
| | 1183 | .n_value = 0, |
| | 1184 | }); |
| | 1185 | } |
| 867 | } | 1186 | } |
| 868 | | 1187 | |
| 869 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 1188 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 870 | const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment; | | |
| 871 | const text_section = &self.sections.items[self.text_section_index.?]; | 1189 | const text_section = &self.sections.items[self.text_section_index.?]; |
| 872 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; | 1190 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; |
| 873 | | 1191 | |
| 874 | var block_placement: ?*TextBlock = null; | 1192 | var block_placement: ?*TextBlock = null; |
| 875 | const addr = blk: { | 1193 | const addr = blk: { |
| 876 | if (self.last_text_block) |last| { | 1194 | if (self.last_text_block) |last| { |
| 877 | const last_symbol = self.symbol_table.items[last.symbol_table_index.?]; | 1195 | const last_symbol = self.local_symbols.items[last.local_sym_index]; |
| | 1196 | // TODO pad out with NOPs and reenable |
| | 1197 | // const ideal_capacity = last.size * alloc_num / alloc_den; |
| | 1198 | // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity; |
| | 1199 | // const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment); |
| 878 | const end_addr = last_symbol.n_value + last.size; | 1200 | const end_addr = last_symbol.n_value + last.size; |
| 879 | const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment); | 1201 | const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment); |
| 880 | block_placement = last; | 1202 | block_placement = last; |
| ... | @@ -883,22 +1205,15 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -883,22 +1205,15 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 883 | break :blk text_section.addr; | 1205 | break :blk text_section.addr; |
| 884 | } | 1206 | } |
| 885 | }; | 1207 | }; |
| 886 | log.debug("computed symbol address 0x{x}\n", .{addr}); | | |
| 887 | | 1208 | |
| 888 | const expand_text_section = block_placement == null or block_placement.?.next == null; | 1209 | const expand_text_section = block_placement == null or block_placement.?.next == null; |
| 889 | if (expand_text_section) { | 1210 | if (expand_text_section) { |
| 890 | const text_capacity = self.allocatedSize(text_section.offset); | 1211 | const text_capacity = self.allocatedSize(text_section.offset); |
| 891 | const needed_size = (addr + new_block_size) - text_section.addr; | 1212 | const needed_size = (addr + new_block_size) - text_section.addr; |
| 892 | log.debug("text capacity 0x{x}, needed size 0x{x}\n", .{ text_capacity, needed_size }); | | |
| 893 | assert(needed_size <= text_capacity); // TODO handle growth | 1213 | assert(needed_size <= text_capacity); // TODO handle growth |
| 894 | | 1214 | |
| 895 | self.last_text_block = text_block; | 1215 | self.last_text_block = text_block; |
| 896 | text_section.size = needed_size; | 1216 | text_section.size = needed_size; // TODO temp until we pad out with NOPs |
| 897 | segment.vmsize = needed_size; | | |
| 898 | segment.filesize = needed_size; | | |
| 899 | if (alignment < text_section.@"align") { | | |
| 900 | text_section.@"align" = @intCast(u32, alignment); | | |
| 901 | } | | |
| 902 | } | 1217 | } |
| 903 | text_block.size = new_block_size; | 1218 | text_block.size = new_block_size; |
| 904 | | 1219 | |
| ... | @@ -936,16 +1251,17 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 { | ... | @@ -936,16 +1251,17 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 { |
| 936 | return @intCast(u32, result); | 1251 | return @intCast(u32, result); |
| 937 | } | 1252 | } |
| 938 | | 1253 | |
| 939 | fn alignSize(comptime Int: type, min_size: anytype, alignment: Int) Int { | 1254 | fn getString(self: *MachO, str_off: u32) []const u8 { |
| 940 | const size = @intCast(Int, min_size); | 1255 | assert(str_off < self.string_table.items.len); |
| 941 | if (size % alignment == 0) return size; | 1256 | return mem.spanZ(@ptrCast([*:0]const u8, self.string_table.items.ptr + str_off)); |
| 942 | | | |
| 943 | const div = size / alignment; | | |
| 944 | return (div + 1) * alignment; | | |
| 945 | } | 1257 | } |
| 946 | | 1258 | |
| 947 | fn commandSize(min_size: anytype) u32 { | 1259 | fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { |
| 948 | return alignSize(u32, min_size, @sizeOf(u64)); | 1260 | const existing_name = self.getString(old_str_off); |
| | 1261 | if (mem.eql(u8, existing_name, new_name)) { |
| | 1262 | return old_str_off; |
| | 1263 | } |
| | 1264 | return self.makeString(new_name); |
| 949 | } | 1265 | } |
| 950 | | 1266 | |
| 951 | fn addPadding(self: *MachO, size: u64, file_offset: u64) !void { | 1267 | fn addPadding(self: *MachO, size: u64, file_offset: u64) !void { |
| ... | @@ -961,11 +1277,8 @@ fn addPadding(self: *MachO, size: u64, file_offset: u64) !void { | ... | @@ -961,11 +1277,8 @@ fn addPadding(self: *MachO, size: u64, file_offset: u64) !void { |
| 961 | | 1277 | |
| 962 | fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | 1278 | fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 963 | const hdr_size: u64 = @sizeOf(macho.mach_header_64); | 1279 | const hdr_size: u64 = @sizeOf(macho.mach_header_64); |
| 964 | if (start < hdr_size) | 1280 | if (start < hdr_size) return hdr_size; |
| 965 | return hdr_size; | | |
| 966 | | | |
| 967 | const end = start + satMul(size, alloc_num) / alloc_den; | 1281 | const end = start + satMul(size, alloc_num) / alloc_den; |
| 968 | | | |
| 969 | { | 1282 | { |
| 970 | const off = @sizeOf(macho.mach_header_64); | 1283 | const off = @sizeOf(macho.mach_header_64); |
| 971 | var tight_size: u64 = 0; | 1284 | var tight_size: u64 = 0; |
| ... | @@ -978,7 +1291,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | ... | @@ -978,7 +1291,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 978 | return test_end; | 1291 | return test_end; |
| 979 | } | 1292 | } |
| 980 | } | 1293 | } |
| 981 | | | |
| 982 | for (self.sections.items) |section| { | 1294 | for (self.sections.items) |section| { |
| 983 | const increased_size = satMul(section.size, alloc_num) / alloc_den; | 1295 | const increased_size = satMul(section.size, alloc_num) / alloc_den; |
| 984 | const test_end = section.offset + increased_size; | 1296 | const test_end = section.offset + increased_size; |
| ... | @@ -986,7 +1298,15 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | ... | @@ -986,7 +1298,15 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 986 | return test_end; | 1298 | return test_end; |
| 987 | } | 1299 | } |
| 988 | } | 1300 | } |
| 989 | | 1301 | if (self.dyld_info_cmd_index) |dyld_info_index| { |
| | 1302 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo; |
| | 1303 | const tight_size = dyld_info.export_size; |
| | 1304 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; |
| | 1305 | const test_end = dyld_info.export_off + increased_size; |
| | 1306 | if (end > dyld_info.export_off and start < test_end) { |
| | 1307 | return test_end; |
| | 1308 | } |
| | 1309 | } |
| 990 | if (self.symtab_cmd_index) |symtab_index| { | 1310 | if (self.symtab_cmd_index) |symtab_index| { |
| 991 | const symtab = self.load_commands.items[symtab_index].Symtab; | 1311 | const symtab = self.load_commands.items[symtab_index].Symtab; |
| 992 | { | 1312 | { |
| ... | @@ -1005,7 +1325,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | ... | @@ -1005,7 +1325,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 1005 | } | 1325 | } |
| 1006 | } | 1326 | } |
| 1007 | } | 1327 | } |
| 1008 | | | |
| 1009 | return null; | 1328 | return null; |
| 1010 | } | 1329 | } |
| 1011 | | 1330 | |
| ... | @@ -1021,6 +1340,10 @@ fn allocatedSize(self: *MachO, start: u64) u64 { | ... | @@ -1021,6 +1340,10 @@ fn allocatedSize(self: *MachO, start: u64) u64 { |
| 1021 | if (section.offset <= start) continue; | 1340 | if (section.offset <= start) continue; |
| 1022 | if (section.offset < min_pos) min_pos = section.offset; | 1341 | if (section.offset < min_pos) min_pos = section.offset; |
| 1023 | } | 1342 | } |
| | 1343 | if (self.dyld_info_cmd_index) |dyld_info_index| { |
| | 1344 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo; |
| | 1345 | if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off; |
| | 1346 | } |
| 1024 | if (self.symtab_cmd_index) |symtab_index| { | 1347 | if (self.symtab_cmd_index) |symtab_index| { |
| 1025 | const symtab = self.load_commands.items[symtab_index].Symtab; | 1348 | const symtab = self.load_commands.items[symtab_index].Symtab; |
| 1026 | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff; | 1349 | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff; |
| ... | @@ -1042,12 +1365,133 @@ fn writeSymbol(self: *MachO, index: usize) !void { | ... | @@ -1042,12 +1365,133 @@ fn writeSymbol(self: *MachO, index: usize) !void { |
| 1042 | defer tracy.end(); | 1365 | defer tracy.end(); |
| 1043 | | 1366 | |
| 1044 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1367 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1045 | const sym = [1]macho.nlist_64{self.symbol_table.items[index]}; | 1368 | const sym = [1]macho.nlist_64{self.local_symbols.items[index]}; |
| 1046 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; | 1369 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 1047 | log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off }); | 1370 | log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off }); |
| 1048 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | 1371 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); |
| 1049 | } | 1372 | } |
| 1050 | | 1373 | |
| | 1374 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| | 1375 | const sect = &self.sections.items[self.got_section_index.?]; |
| | 1376 | const endian = self.base.options.target.cpu.arch.endian(); |
| | 1377 | var buf: [@sizeOf(u64)]u8 = undefined; |
| | 1378 | mem.writeInt(u64, &buf, self.offset_table.items[index], endian); |
| | 1379 | const off = sect.offset + @sizeOf(u64) * index; |
| | 1380 | log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off }); |
| | 1381 | try self.base.file.?.pwriteAll(&buf, off); |
| | 1382 | } |
| | 1383 | |
| | 1384 | fn writeAllGlobalSymbols(self: *MachO) !void { |
| | 1385 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 1386 | const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64); |
| | 1387 | const file_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); |
| | 1388 | log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off }); |
| | 1389 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), off); |
| | 1390 | } |
| | 1391 | |
| | 1392 | fn writeAllUndefSymbols(self: *MachO) !void { |
| | 1393 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 1394 | const nlocals = self.local_symbols.items.len; |
| | 1395 | const nglobals = self.global_symbols.items.len; |
| | 1396 | const off = symtab.symoff + (nlocals + nglobals) * @sizeOf(macho.nlist_64); |
| | 1397 | const file_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64); |
| | 1398 | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off }); |
| | 1399 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), off); |
| | 1400 | } |
| | 1401 | |
| | 1402 | fn writeExportTrie(self: *MachO) !void { |
| | 1403 | assert(self.entry_addr != null); |
| | 1404 | |
| | 1405 | // TODO implement mechanism for generating a prefix tree of the exported symbols |
| | 1406 | // single branch export trie |
| | 1407 | var buf = [_]u8{0} ** 24; |
| | 1408 | buf[0] = 0; // root node |
| | 1409 | buf[1] = 1; // 1 branch from root |
| | 1410 | mem.copy(u8, buf[2..], "_start"); |
| | 1411 | buf[8] = 0; |
| | 1412 | buf[9] = 9 + 1; |
| | 1413 | |
| | 1414 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 1415 | const addr = self.entry_addr.? - text_segment.vmaddr; |
| | 1416 | const written = try std.debug.leb.writeULEB128Mem(buf[12..], addr); |
| | 1417 | buf[10] = @intCast(u8, written) + 1; |
| | 1418 | buf[11] = 0; |
| | 1419 | |
| | 1420 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| | 1421 | try self.base.file.?.pwriteAll(buf[0..], dyld_info.export_off); |
| | 1422 | } |
| | 1423 | |
| | 1424 | fn writeStringTable(self: *MachO) !void { |
| | 1425 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 1426 | const allocated_size = self.allocatedSize(symtab.stroff); |
| | 1427 | const needed_size = self.string_table.items.len; |
| | 1428 | |
| | 1429 | if (needed_size > allocated_size) { |
| | 1430 | symtab.strsize = 0; |
| | 1431 | symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1)); |
| | 1432 | } |
| | 1433 | symtab.strsize = @intCast(u32, needed_size); |
| | 1434 | |
| | 1435 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| | 1436 | |
| | 1437 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); |
| | 1438 | |
| | 1439 | // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of |
| | 1440 | // doing dynamic updates like this. |
| | 1441 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1442 | linkedit.filesize = symtab.stroff + symtab.strsize - linkedit.fileoff; |
| | 1443 | } |
| | 1444 | |
| | 1445 | fn writeCmdHeaders(self: *MachO) !void { |
| | 1446 | assert(self.cmd_table_dirty); |
| | 1447 | |
| | 1448 | // Write all load command headers first. |
| | 1449 | // Since command sizes are up-to-date and accurate, we will correctly |
| | 1450 | // leave space for any section headers that any of the segment load |
| | 1451 | // commands might consist of. |
| | 1452 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); |
| | 1453 | for (self.load_commands.items) |cmd| { |
| | 1454 | try cmd.write(&self.base.file.?, last_cmd_offset); |
| | 1455 | last_cmd_offset += cmd.cmdsize(); |
| | 1456 | } |
| | 1457 | { |
| | 1458 | // write __text section header |
| | 1459 | const off = if (self.text_segment_cmd_index) |text_segment_index| blk: { |
| | 1460 | var i: usize = 0; |
| | 1461 | var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); |
| | 1462 | while (i < text_segment_index) : (i += 1) { |
| | 1463 | cmdsize += self.load_commands.items[i].cmdsize(); |
| | 1464 | } |
| | 1465 | break :blk cmdsize; |
| | 1466 | } else { |
| | 1467 | // If we've landed in here, we are building a MachO object file, so we have |
| | 1468 | // only one, noname segment to append this section header to. |
| | 1469 | return error.TODOImplementWritingObjFiles; |
| | 1470 | }; |
| | 1471 | const idx = self.text_section_index.?; |
| | 1472 | log.debug("writing text section {} at 0x{x}\n", .{ self.sections.items[idx .. idx + 1], off }); |
| | 1473 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off); |
| | 1474 | } |
| | 1475 | { |
| | 1476 | // write __got section header |
| | 1477 | const off = if (self.data_segment_cmd_index) |data_segment_index| blk: { |
| | 1478 | var i: usize = 0; |
| | 1479 | var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); |
| | 1480 | while (i < data_segment_index) : (i += 1) { |
| | 1481 | cmdsize += self.load_commands.items[i].cmdsize(); |
| | 1482 | } |
| | 1483 | break :blk cmdsize; |
| | 1484 | } else { |
| | 1485 | // If we've landed in here, we are building a MachO object file, so we have |
| | 1486 | // only one, noname segment to append this section header to. |
| | 1487 | return error.TODOImplementWritingObjFiles; |
| | 1488 | }; |
| | 1489 | const idx = self.got_section_index.?; |
| | 1490 | log.debug("writing got section {} at 0x{x}\n", .{ self.sections.items[idx .. idx + 1], off }); |
| | 1491 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off); |
| | 1492 | } |
| | 1493 | } |
| | 1494 | |
| 1051 | /// Writes Mach-O file header. | 1495 | /// Writes Mach-O file header. |
| 1052 | /// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping | 1496 | /// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping |
| 1053 | /// variables. | 1497 | /// variables. |