| ... | ... | @@ -1,4 +1,37 @@ |
| 1 | | pub fn flush(macho_file: *MachO) !void { |
| 1 | pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 2 | const gpa = macho_file.base.comp.gpa; |
| 3 | |
| 4 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); |
| 5 | defer positionals.deinit(); |
| 6 | try positionals.ensureUnusedCapacity(comp.objects.len); |
| 7 | positionals.appendSliceAssumeCapacity(comp.objects); |
| 8 | |
| 9 | for (comp.c_object_table.keys()) |key| { |
| 10 | try positionals.append(.{ .path = key.status.success.object_path }); |
| 11 | } |
| 12 | |
| 13 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 14 | |
| 15 | for (positionals.items) |obj| { |
| 16 | macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 17 | error.MalformedObject, |
| 18 | error.MalformedArchive, |
| 19 | error.InvalidCpuArch, |
| 20 | error.InvalidTarget, |
| 21 | => continue, // already reported |
| 22 | error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}), |
| 23 | else => |e| try macho_file.reportParseError( |
| 24 | obj.path, |
| 25 | "unexpected error: parsing input file failed with error {s}", |
| 26 | .{@errorName(e)}, |
| 27 | ), |
| 28 | }; |
| 29 | } |
| 30 | |
| 31 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 32 | |
| 33 | try macho_file.addUndefinedGlobals(); |
| 34 | try macho_file.resolveSymbols(); |
| 2 | 35 | markExports(macho_file); |
| 3 | 36 | claimUnresolved(macho_file); |
| 4 | 37 | try initOutputSections(macho_file); |
| ... | ... | @@ -9,7 +42,7 @@ pub fn flush(macho_file: *MachO) !void { |
| 9 | 42 | { |
| 10 | 43 | // For relocatable, we only ever need a single segment so create it now. |
| 11 | 44 | const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC; |
| 12 | | try macho_file.segments.append(macho_file.base.allocator, .{ |
| 45 | try macho_file.segments.append(gpa, .{ |
| 13 | 46 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 14 | 47 | .segname = MachO.makeStaticString(""), |
| 15 | 48 | .maxprot = prot, |
| ... | ... | @@ -128,17 +161,20 @@ fn initOutputSections(macho_file: *MachO) !void { |
| 128 | 161 | } |
| 129 | 162 | |
| 130 | 163 | fn calcSectionSizes(macho_file: *MachO) !void { |
| 164 | const tracy = trace(@src()); |
| 165 | defer tracy.end(); |
| 166 | |
| 131 | 167 | const slice = macho_file.sections.slice(); |
| 132 | 168 | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { |
| 133 | 169 | if (atoms.items.len == 0) continue; |
| 134 | 170 | for (atoms.items) |atom_index| { |
| 135 | 171 | const atom = macho_file.getAtom(atom_index).?; |
| 136 | | const atom_alignment = try math.powi(u32, 2, atom.alignment); |
| 172 | const atom_alignment = atom.alignment.toByteUnits(1); |
| 137 | 173 | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 138 | 174 | const padding = offset - header.size; |
| 139 | 175 | atom.value = offset; |
| 140 | 176 | header.size += padding + atom.size; |
| 141 | | header.@"align" = @max(header.@"align", atom.alignment); |
| 177 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 142 | 178 | header.nreloc += atom.calcNumRelocs(macho_file); |
| 143 | 179 | } |
| 144 | 180 | } |
| ... | ... | @@ -218,8 +254,8 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 218 | 254 | const tracy = trace(@src()); |
| 219 | 255 | defer tracy.end(); |
| 220 | 256 | |
| 221 | | const gpa = macho_file.base.allocator; |
| 222 | | const cpu_arch = macho_file.options.cpu_arch.?; |
| 257 | const gpa = macho_file.base.comp.gpa; |
| 258 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 223 | 259 | const slice = macho_file.sections.slice(); |
| 224 | 260 | |
| 225 | 261 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { |
| ... | ... | @@ -247,14 +283,14 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 247 | 283 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 248 | 284 | |
| 249 | 285 | // TODO scattered writes? |
| 250 | | try macho_file.base.file.pwriteAll(code, header.offset); |
| 251 | | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 286 | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 287 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 252 | 288 | } |
| 253 | 289 | } |
| 254 | 290 | |
| 255 | 291 | fn writeCompactUnwind(macho_file: *MachO) !void { |
| 256 | 292 | const sect_index = macho_file.unwind_info_sect_index orelse return; |
| 257 | | const gpa = macho_file.base.allocator; |
| 293 | const gpa = macho_file.base.comp.gpa; |
| 258 | 294 | const header = macho_file.sections.items(.header)[sect_index]; |
| 259 | 295 | |
| 260 | 296 | const nrecs = @divExact(header.size, @sizeOf(macho.compact_unwind_entry)); |
| ... | ... | @@ -301,7 +337,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 301 | 337 | const atom = rec.getAtom(macho_file); |
| 302 | 338 | const addr = rec.getAtomAddress(macho_file); |
| 303 | 339 | out.rangeStart = addr; |
| 304 | | var reloc = addReloc(offset, macho_file.options.cpu_arch.?); |
| 340 | var reloc = addReloc(offset, macho_file.getTarget().cpu.arch); |
| 305 | 341 | reloc.r_symbolnum = atom.out_n_sect + 1; |
| 306 | 342 | relocs.appendAssumeCapacity(reloc); |
| 307 | 343 | } |
| ... | ... | @@ -309,7 +345,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 309 | 345 | // Personality function |
| 310 | 346 | if (rec.getPersonality(macho_file)) |sym| { |
| 311 | 347 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; |
| 312 | | var reloc = addReloc(offset + 16, macho_file.options.cpu_arch.?); |
| 348 | var reloc = addReloc(offset + 16, macho_file.getTarget().cpu.arch); |
| 313 | 349 | reloc.r_symbolnum = r_symbolnum; |
| 314 | 350 | reloc.r_extern = 1; |
| 315 | 351 | relocs.appendAssumeCapacity(reloc); |
| ... | ... | @@ -319,7 +355,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 319 | 355 | if (rec.getLsdaAtom(macho_file)) |atom| { |
| 320 | 356 | const addr = rec.getLsdaAddress(macho_file); |
| 321 | 357 | out.lsda = addr; |
| 322 | | var reloc = addReloc(offset + 24, macho_file.options.cpu_arch.?); |
| 358 | var reloc = addReloc(offset + 24, macho_file.getTarget().cpu.arch); |
| 323 | 359 | reloc.r_symbolnum = atom.out_n_sect + 1; |
| 324 | 360 | relocs.appendAssumeCapacity(reloc); |
| 325 | 361 | } |
| ... | ... | @@ -335,13 +371,13 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 335 | 371 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 336 | 372 | |
| 337 | 373 | // TODO scattered writes? |
| 338 | | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(entries.items), header.offset); |
| 339 | | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 374 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(entries.items), header.offset); |
| 375 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 340 | 376 | } |
| 341 | 377 | |
| 342 | 378 | fn writeEhFrame(macho_file: *MachO) !void { |
| 343 | 379 | const sect_index = macho_file.eh_frame_sect_index orelse return; |
| 344 | | const gpa = macho_file.base.allocator; |
| 380 | const gpa = macho_file.base.comp.gpa; |
| 345 | 381 | const header = macho_file.sections.items(.header)[sect_index]; |
| 346 | 382 | |
| 347 | 383 | const code = try gpa.alloc(u8, header.size); |
| ... | ... | @@ -356,12 +392,12 @@ fn writeEhFrame(macho_file: *MachO) !void { |
| 356 | 392 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 357 | 393 | |
| 358 | 394 | // TODO scattered writes? |
| 359 | | try macho_file.base.file.pwriteAll(code, header.offset); |
| 360 | | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 395 | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 396 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 361 | 397 | } |
| 362 | 398 | |
| 363 | 399 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |
| 364 | | const gpa = macho_file.base.allocator; |
| 400 | const gpa = macho_file.base.comp.gpa; |
| 365 | 401 | const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file); |
| 366 | 402 | const buffer = try gpa.alloc(u8, needed_size); |
| 367 | 403 | defer gpa.free(buffer); |
| ... | ... | @@ -390,19 +426,17 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |
| 390 | 426 | try writer.writeStruct(macho_file.dysymtab_cmd); |
| 391 | 427 | ncmds += 1; |
| 392 | 428 | |
| 393 | | if (macho_file.options.platform) |platform| { |
| 394 | | if (platform.isBuildVersionCompatible()) { |
| 395 | | try load_commands.writeBuildVersionLC(platform, macho_file.options.sdk_version, writer); |
| 396 | | ncmds += 1; |
| 397 | | } else { |
| 398 | | try load_commands.writeVersionMinLC(platform, macho_file.options.sdk_version, writer); |
| 399 | | ncmds += 1; |
| 400 | | } |
| 429 | if (macho_file.platform.isBuildVersionCompatible()) { |
| 430 | try load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer); |
| 431 | ncmds += 1; |
| 432 | } else { |
| 433 | try load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer); |
| 434 | ncmds += 1; |
| 401 | 435 | } |
| 402 | 436 | |
| 403 | 437 | assert(cwriter.bytes_written == needed_size); |
| 404 | 438 | |
| 405 | | try macho_file.base.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); |
| 439 | try macho_file.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); |
| 406 | 440 | |
| 407 | 441 | return .{ ncmds, buffer.len }; |
| 408 | 442 | } |
| ... | ... | @@ -419,7 +453,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 419 | 453 | header.flags |= macho.MH_SUBSECTIONS_VIA_SYMBOLS; |
| 420 | 454 | } |
| 421 | 455 | |
| 422 | | switch (macho_file.options.cpu_arch.?) { |
| 456 | switch (macho_file.getTarget().cpu.arch) { |
| 423 | 457 | .aarch64 => { |
| 424 | 458 | header.cputype = macho.CPU_TYPE_ARM64; |
| 425 | 459 | header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL; |
| ... | ... | @@ -434,19 +468,21 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 434 | 468 | header.ncmds = @intCast(ncmds); |
| 435 | 469 | header.sizeofcmds = @intCast(sizeofcmds); |
| 436 | 470 | |
| 437 | | try macho_file.base.file.pwriteAll(mem.asBytes(&header), 0); |
| 471 | try macho_file.base.file.?.pwriteAll(mem.asBytes(&header), 0); |
| 438 | 472 | } |
| 439 | 473 | |
| 440 | 474 | const assert = std.debug.assert; |
| 441 | 475 | const eh_frame = @import("eh_frame.zig"); |
| 476 | const link = @import("../../link.zig"); |
| 442 | 477 | const load_commands = @import("load_commands.zig"); |
| 443 | 478 | const macho = std.macho; |
| 444 | 479 | const math = std.math; |
| 445 | 480 | const mem = std.mem; |
| 446 | | const state_log = std.log.scoped(.state); |
| 481 | const state_log = std.log.scoped(.link_state); |
| 447 | 482 | const std = @import("std"); |
| 448 | | const trace = @import("../tracy.zig").trace; |
| 483 | const trace = @import("../../tracy.zig").trace; |
| 449 | 484 | |
| 450 | 485 | const Atom = @import("Atom.zig"); |
| 486 | const Compilation = @import("../../Compilation.zig"); |
| 451 | 487 | const MachO = @import("../MachO.zig"); |
| 452 | 488 | const Symbol = @import("Symbol.zig"); |