| ... | @@ -1,4 +1,37 @@ | ... | @@ -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 | markExports(macho_file); | 35 | markExports(macho_file); |
| 3 | claimUnresolved(macho_file); | 36 | claimUnresolved(macho_file); |
| 4 | try initOutputSections(macho_file); | 37 | try initOutputSections(macho_file); |
| ... | @@ -9,7 +42,7 @@ pub fn flush(macho_file: *MachO) !void { | ... | @@ -9,7 +42,7 @@ pub fn flush(macho_file: *MachO) !void { |
| 9 | { | 42 | { |
| 10 | // For relocatable, we only ever need a single segment so create it now. | 43 | // For relocatable, we only ever need a single segment so create it now. |
| 11 | const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC; | 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 | .cmdsize = @sizeOf(macho.segment_command_64), | 46 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 14 | .segname = MachO.makeStaticString(""), | 47 | .segname = MachO.makeStaticString(""), |
| 15 | .maxprot = prot, | 48 | .maxprot = prot, |
| ... | @@ -128,17 +161,20 @@ fn initOutputSections(macho_file: *MachO) !void { | ... | @@ -128,17 +161,20 @@ fn initOutputSections(macho_file: *MachO) !void { |
| 128 | } | 161 | } |
| 129 | | 162 | |
| 130 | fn calcSectionSizes(macho_file: *MachO) !void { | 163 | fn calcSectionSizes(macho_file: *MachO) !void { |
| | 164 | const tracy = trace(@src()); |
| | 165 | defer tracy.end(); |
| | 166 | |
| 131 | const slice = macho_file.sections.slice(); | 167 | const slice = macho_file.sections.slice(); |
| 132 | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { | 168 | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { |
| 133 | if (atoms.items.len == 0) continue; | 169 | if (atoms.items.len == 0) continue; |
| 134 | for (atoms.items) |atom_index| { | 170 | for (atoms.items) |atom_index| { |
| 135 | const atom = macho_file.getAtom(atom_index).?; | 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 | const offset = mem.alignForward(u64, header.size, atom_alignment); | 173 | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 138 | const padding = offset - header.size; | 174 | const padding = offset - header.size; |
| 139 | atom.value = offset; | 175 | atom.value = offset; |
| 140 | header.size += padding + atom.size; | 176 | header.size += padding + atom.size; |
| 141 | header.@"align" = @max(header.@"align", atom.alignment); | 177 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 142 | header.nreloc += atom.calcNumRelocs(macho_file); | 178 | header.nreloc += atom.calcNumRelocs(macho_file); |
| 143 | } | 179 | } |
| 144 | } | 180 | } |
| ... | @@ -218,8 +254,8 @@ fn writeAtoms(macho_file: *MachO) !void { | ... | @@ -218,8 +254,8 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 218 | const tracy = trace(@src()); | 254 | const tracy = trace(@src()); |
| 219 | defer tracy.end(); | 255 | defer tracy.end(); |
| 220 | | 256 | |
| 221 | const gpa = macho_file.base.allocator; | 257 | const gpa = macho_file.base.comp.gpa; |
| 222 | const cpu_arch = macho_file.options.cpu_arch.?; | 258 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 223 | const slice = macho_file.sections.slice(); | 259 | const slice = macho_file.sections.slice(); |
| 224 | | 260 | |
| 225 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { | 261 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { |
| ... | @@ -247,14 +283,14 @@ fn writeAtoms(macho_file: *MachO) !void { | ... | @@ -247,14 +283,14 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 247 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | 283 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 248 | | 284 | |
| 249 | // TODO scattered writes? | 285 | // TODO scattered writes? |
| 250 | try macho_file.base.file.pwriteAll(code, header.offset); | 286 | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 251 | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | 287 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 252 | } | 288 | } |
| 253 | } | 289 | } |
| 254 | | 290 | |
| 255 | fn writeCompactUnwind(macho_file: *MachO) !void { | 291 | fn writeCompactUnwind(macho_file: *MachO) !void { |
| 256 | const sect_index = macho_file.unwind_info_sect_index orelse return; | 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 | const header = macho_file.sections.items(.header)[sect_index]; | 294 | const header = macho_file.sections.items(.header)[sect_index]; |
| 259 | | 295 | |
| 260 | const nrecs = @divExact(header.size, @sizeOf(macho.compact_unwind_entry)); | 296 | const nrecs = @divExact(header.size, @sizeOf(macho.compact_unwind_entry)); |
| ... | @@ -301,7 +337,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { | ... | @@ -301,7 +337,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 301 | const atom = rec.getAtom(macho_file); | 337 | const atom = rec.getAtom(macho_file); |
| 302 | const addr = rec.getAtomAddress(macho_file); | 338 | const addr = rec.getAtomAddress(macho_file); |
| 303 | out.rangeStart = addr; | 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 | reloc.r_symbolnum = atom.out_n_sect + 1; | 341 | reloc.r_symbolnum = atom.out_n_sect + 1; |
| 306 | relocs.appendAssumeCapacity(reloc); | 342 | relocs.appendAssumeCapacity(reloc); |
| 307 | } | 343 | } |
| ... | @@ -309,7 +345,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { | ... | @@ -309,7 +345,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 309 | // Personality function | 345 | // Personality function |
| 310 | if (rec.getPersonality(macho_file)) |sym| { | 346 | if (rec.getPersonality(macho_file)) |sym| { |
| 311 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; | 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 | reloc.r_symbolnum = r_symbolnum; | 349 | reloc.r_symbolnum = r_symbolnum; |
| 314 | reloc.r_extern = 1; | 350 | reloc.r_extern = 1; |
| 315 | relocs.appendAssumeCapacity(reloc); | 351 | relocs.appendAssumeCapacity(reloc); |
| ... | @@ -319,7 +355,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { | ... | @@ -319,7 +355,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 319 | if (rec.getLsdaAtom(macho_file)) |atom| { | 355 | if (rec.getLsdaAtom(macho_file)) |atom| { |
| 320 | const addr = rec.getLsdaAddress(macho_file); | 356 | const addr = rec.getLsdaAddress(macho_file); |
| 321 | out.lsda = addr; | 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 | reloc.r_symbolnum = atom.out_n_sect + 1; | 359 | reloc.r_symbolnum = atom.out_n_sect + 1; |
| 324 | relocs.appendAssumeCapacity(reloc); | 360 | relocs.appendAssumeCapacity(reloc); |
| 325 | } | 361 | } |
| ... | @@ -335,13 +371,13 @@ fn writeCompactUnwind(macho_file: *MachO) !void { | ... | @@ -335,13 +371,13 @@ fn writeCompactUnwind(macho_file: *MachO) !void { |
| 335 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | 371 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 336 | | 372 | |
| 337 | // TODO scattered writes? | 373 | // TODO scattered writes? |
| 338 | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(entries.items), header.offset); | 374 | 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); | 375 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 340 | } | 376 | } |
| 341 | | 377 | |
| 342 | fn writeEhFrame(macho_file: *MachO) !void { | 378 | fn writeEhFrame(macho_file: *MachO) !void { |
| 343 | const sect_index = macho_file.eh_frame_sect_index orelse return; | 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 | const header = macho_file.sections.items(.header)[sect_index]; | 381 | const header = macho_file.sections.items(.header)[sect_index]; |
| 346 | | 382 | |
| 347 | const code = try gpa.alloc(u8, header.size); | 383 | const code = try gpa.alloc(u8, header.size); |
| ... | @@ -356,12 +392,12 @@ fn writeEhFrame(macho_file: *MachO) !void { | ... | @@ -356,12 +392,12 @@ fn writeEhFrame(macho_file: *MachO) !void { |
| 356 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | 392 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 357 | | 393 | |
| 358 | // TODO scattered writes? | 394 | // TODO scattered writes? |
| 359 | try macho_file.base.file.pwriteAll(code, header.offset); | 395 | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 360 | try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | 396 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 361 | } | 397 | } |
| 362 | | 398 | |
| 363 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { | 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 | const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file); | 401 | const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file); |
| 366 | const buffer = try gpa.alloc(u8, needed_size); | 402 | const buffer = try gpa.alloc(u8, needed_size); |
| 367 | defer gpa.free(buffer); | 403 | defer gpa.free(buffer); |
| ... | @@ -390,19 +426,17 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { | ... | @@ -390,19 +426,17 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |
| 390 | try writer.writeStruct(macho_file.dysymtab_cmd); | 426 | try writer.writeStruct(macho_file.dysymtab_cmd); |
| 391 | ncmds += 1; | 427 | ncmds += 1; |
| 392 | | 428 | |
| 393 | if (macho_file.options.platform) |platform| { | 429 | if (macho_file.platform.isBuildVersionCompatible()) { |
| 394 | if (platform.isBuildVersionCompatible()) { | 430 | try load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer); |
| 395 | try load_commands.writeBuildVersionLC(platform, macho_file.options.sdk_version, writer); | 431 | ncmds += 1; |
| 396 | ncmds += 1; | 432 | } else { |
| 397 | } else { | 433 | try load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer); |
| 398 | try load_commands.writeVersionMinLC(platform, macho_file.options.sdk_version, writer); | 434 | ncmds += 1; |
| 399 | ncmds += 1; | | |
| 400 | } | | |
| 401 | } | 435 | } |
| 402 | | 436 | |
| 403 | assert(cwriter.bytes_written == needed_size); | 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 | return .{ ncmds, buffer.len }; | 441 | return .{ ncmds, buffer.len }; |
| 408 | } | 442 | } |
| ... | @@ -419,7 +453,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { | ... | @@ -419,7 +453,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 419 | header.flags |= macho.MH_SUBSECTIONS_VIA_SYMBOLS; | 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 | .aarch64 => { | 457 | .aarch64 => { |
| 424 | header.cputype = macho.CPU_TYPE_ARM64; | 458 | header.cputype = macho.CPU_TYPE_ARM64; |
| 425 | header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL; | 459 | header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL; |
| ... | @@ -434,19 +468,21 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { | ... | @@ -434,19 +468,21 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 434 | header.ncmds = @intCast(ncmds); | 468 | header.ncmds = @intCast(ncmds); |
| 435 | header.sizeofcmds = @intCast(sizeofcmds); | 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 | const assert = std.debug.assert; | 474 | const assert = std.debug.assert; |
| 441 | const eh_frame = @import("eh_frame.zig"); | 475 | const eh_frame = @import("eh_frame.zig"); |
| | 476 | const link = @import("../../link.zig"); |
| 442 | const load_commands = @import("load_commands.zig"); | 477 | const load_commands = @import("load_commands.zig"); |
| 443 | const macho = std.macho; | 478 | const macho = std.macho; |
| 444 | const math = std.math; | 479 | const math = std.math; |
| 445 | const mem = std.mem; | 480 | const mem = std.mem; |
| 446 | const state_log = std.log.scoped(.state); | 481 | const state_log = std.log.scoped(.link_state); |
| 447 | const std = @import("std"); | 482 | const std = @import("std"); |
| 448 | const trace = @import("../tracy.zig").trace; | 483 | const trace = @import("../../tracy.zig").trace; |
| 449 | | 484 | |
| 450 | const Atom = @import("Atom.zig"); | 485 | const Atom = @import("Atom.zig"); |
| | 486 | const Compilation = @import("../../Compilation.zig"); |
| 451 | const MachO = @import("../MachO.zig"); | 487 | const MachO = @import("../MachO.zig"); |
| 452 | const Symbol = @import("Symbol.zig"); | 488 | const Symbol = @import("Symbol.zig"); |