| ... | @@ -58,46 +58,20 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u | ... | @@ -58,46 +58,20 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u |
| 58 | try macho_file.addAtomsToSections(); | 58 | try macho_file.addAtomsToSections(); |
| 59 | try calcSectionSizes(macho_file); | 59 | try calcSectionSizes(macho_file); |
| 60 | | 60 | |
| 61 | { | 61 | try createSegment(macho_file); |
| 62 | // For relocatable, we only ever need a single segment so create it now. | 62 | try allocateSectionsVM(macho_file); |
| 63 | const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC; | 63 | try allocateSectionsFile(macho_file); |
| 64 | try macho_file.segments.append(gpa, .{ | 64 | allocateSegment(macho_file); |
| 65 | .cmdsize = @sizeOf(macho.segment_command_64), | | |
| 66 | .segname = MachO.makeStaticString(""), | | |
| 67 | .maxprot = prot, | | |
| 68 | .initprot = prot, | | |
| 69 | }); | | |
| 70 | const seg = &macho_file.segments.items[0]; | | |
| 71 | seg.nsects = @intCast(macho_file.sections.items(.header).len); | | |
| 72 | seg.cmdsize += seg.nsects * @sizeOf(macho.section_64); | | |
| 73 | } | | |
| 74 | | | |
| 75 | var off = try allocateSections(macho_file); | | |
| 76 | | | |
| 77 | { | | |
| 78 | // Allocate the single segment. | | |
| 79 | assert(macho_file.segments.items.len == 1); | | |
| 80 | const seg = &macho_file.segments.items[0]; | | |
| 81 | var vmaddr: u64 = 0; | | |
| 82 | var fileoff: u64 = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); | | |
| 83 | seg.vmaddr = vmaddr; | | |
| 84 | seg.fileoff = fileoff; | | |
| 85 | | | |
| 86 | for (macho_file.sections.items(.header)) |header| { | | |
| 87 | vmaddr = header.addr + header.size; | | |
| 88 | if (!header.isZerofill()) { | | |
| 89 | fileoff = header.offset + header.size; | | |
| 90 | } | | |
| 91 | } | | |
| 92 | | | |
| 93 | seg.vmsize = vmaddr - seg.vmaddr; | | |
| 94 | seg.filesize = fileoff - seg.fileoff; | | |
| 95 | } | | |
| 96 | | | |
| 97 | macho_file.allocateAtoms(); | 65 | macho_file.allocateAtoms(); |
| 98 | | 66 | |
| 99 | state_log.debug("{}", .{macho_file.dumpState()}); | 67 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 100 | | 68 | |
| | 69 | var off = off: { |
| | 70 | const seg = macho_file.segments.items[0]; |
| | 71 | const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow; |
| | 72 | break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info)); |
| | 73 | }; |
| | 74 | off = allocateSectionsRelocs(macho_file, off); |
| 101 | try macho_file.calcSymtabSize(); | 75 | try macho_file.calcSymtabSize(); |
| 102 | try writeAtoms(macho_file); | 76 | try writeAtoms(macho_file); |
| 103 | try writeCompactUnwind(macho_file); | 77 | try writeCompactUnwind(macho_file); |
| ... | @@ -250,8 +224,7 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { | ... | @@ -250,8 +224,7 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { |
| 250 | sect.@"align" = 3; | 224 | sect.@"align" = 3; |
| 251 | } | 225 | } |
| 252 | | 226 | |
| 253 | fn allocateSections(macho_file: *MachO) !u32 { | 227 | fn allocateSectionsVM(macho_file: *MachO) !void { |
| 254 | var fileoff = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); | | |
| 255 | var vmaddr: u64 = 0; | 228 | var vmaddr: u64 = 0; |
| 256 | const slice = macho_file.sections.slice(); | 229 | const slice = macho_file.sections.slice(); |
| 257 | | 230 | |
| ... | @@ -260,20 +233,96 @@ fn allocateSections(macho_file: *MachO) !u32 { | ... | @@ -260,20 +233,96 @@ fn allocateSections(macho_file: *MachO) !u32 { |
| 260 | vmaddr = mem.alignForward(u64, vmaddr, alignment); | 233 | vmaddr = mem.alignForward(u64, vmaddr, alignment); |
| 261 | header.addr = vmaddr; | 234 | header.addr = vmaddr; |
| 262 | vmaddr += header.size; | 235 | vmaddr += header.size; |
| | 236 | } |
| | 237 | } |
| 263 | | 238 | |
| | 239 | fn allocateSectionsFile(macho_file: *MachO) !void { |
| | 240 | var fileoff = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); |
| | 241 | const slice = macho_file.sections.slice(); |
| | 242 | |
| | 243 | const last_index = for (slice.items(.header), 0..) |header, i| { |
| | 244 | if (mem.indexOf(u8, header.segName(), "ZIG")) |_| break i; |
| | 245 | } else slice.items(.header).len; |
| | 246 | |
| | 247 | // TODO: I actually think for relocatable we can just use findFreeSpace |
| | 248 | // all the way since there is a single segment involved anyhow. |
| | 249 | for (slice.items(.header)[0..last_index]) |*header| { |
| | 250 | if (header.isZerofill()) continue; |
| | 251 | const alignment = try math.powi(u32, 2, header.@"align"); |
| | 252 | fileoff = mem.alignForward(u32, fileoff, alignment); |
| | 253 | header.offset = fileoff; |
| | 254 | fileoff += @intCast(header.size); |
| | 255 | } |
| | 256 | |
| | 257 | for (slice.items(.header)[last_index..]) |*header| { |
| | 258 | if (header.isZerofill()) continue; |
| | 259 | if (header.offset < fileoff) { |
| | 260 | const existing_size = header.size; |
| | 261 | header.size = 0; |
| | 262 | |
| | 263 | // Must move the entire section. |
| | 264 | const alignment = try math.powi(u32, 2, header.@"align"); |
| | 265 | const new_offset = macho_file.findFreeSpace(existing_size, alignment); |
| | 266 | |
| | 267 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ |
| | 268 | header.segName(), |
| | 269 | header.sectName(), |
| | 270 | new_offset, |
| | 271 | new_offset + existing_size, |
| | 272 | }); |
| | 273 | |
| | 274 | try macho_file.copyRangeAll(header.offset, new_offset, existing_size); |
| | 275 | |
| | 276 | header.offset = @intCast(new_offset); |
| | 277 | header.size = existing_size; |
| | 278 | } |
| | 279 | } |
| | 280 | } |
| | 281 | |
| | 282 | fn createSegment(macho_file: *MachO) !void { |
| | 283 | const gpa = macho_file.base.comp.gpa; |
| | 284 | |
| | 285 | // For relocatable, we only ever need a single segment so create it now. |
| | 286 | const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC; |
| | 287 | try macho_file.segments.append(gpa, .{ |
| | 288 | .cmdsize = @sizeOf(macho.segment_command_64), |
| | 289 | .segname = MachO.makeStaticString(""), |
| | 290 | .maxprot = prot, |
| | 291 | .initprot = prot, |
| | 292 | }); |
| | 293 | const seg = &macho_file.segments.items[0]; |
| | 294 | seg.nsects = @intCast(macho_file.sections.items(.header).len); |
| | 295 | seg.cmdsize += seg.nsects * @sizeOf(macho.section_64); |
| | 296 | } |
| | 297 | |
| | 298 | fn allocateSegment(macho_file: *MachO) void { |
| | 299 | // Allocate the single segment. |
| | 300 | const seg = &macho_file.segments.items[0]; |
| | 301 | var vmaddr: u64 = 0; |
| | 302 | var fileoff: u64 = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); |
| | 303 | seg.vmaddr = vmaddr; |
| | 304 | seg.fileoff = fileoff; |
| | 305 | |
| | 306 | for (macho_file.sections.items(.header)) |header| { |
| | 307 | vmaddr = @max(vmaddr, header.addr + header.size); |
| 264 | if (!header.isZerofill()) { | 308 | if (!header.isZerofill()) { |
| 265 | fileoff = mem.alignForward(u32, fileoff, alignment); | 309 | fileoff = @max(fileoff, header.offset + header.size); |
| 266 | header.offset = fileoff; | | |
| 267 | fileoff += @intCast(header.size); | | |
| 268 | } | 310 | } |
| | 311 | std.debug.print("fileoff={x},vmaddr={x}\n", .{ fileoff, vmaddr }); |
| 269 | } | 312 | } |
| 270 | | 313 | |
| | 314 | seg.vmsize = vmaddr - seg.vmaddr; |
| | 315 | seg.filesize = fileoff - seg.fileoff; |
| | 316 | } |
| | 317 | |
| | 318 | fn allocateSectionsRelocs(macho_file: *MachO, off: u32) u32 { |
| | 319 | var fileoff = off; |
| | 320 | const slice = macho_file.sections.slice(); |
| 271 | for (slice.items(.header)) |*header| { | 321 | for (slice.items(.header)) |*header| { |
| 272 | if (header.nreloc == 0) continue; | 322 | if (header.nreloc == 0) continue; |
| 273 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); | 323 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); |
| 274 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); | 324 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); |
| 275 | } | 325 | } |
| 276 | | | |
| 277 | return fileoff; | 326 | return fileoff; |
| 278 | } | 327 | } |
| 279 | | 328 | |
| ... | @@ -511,6 +560,7 @@ const assert = std.debug.assert; | ... | @@ -511,6 +560,7 @@ const assert = std.debug.assert; |
| 511 | const eh_frame = @import("eh_frame.zig"); | 560 | const eh_frame = @import("eh_frame.zig"); |
| 512 | const link = @import("../../link.zig"); | 561 | const link = @import("../../link.zig"); |
| 513 | const load_commands = @import("load_commands.zig"); | 562 | const load_commands = @import("load_commands.zig"); |
| | 563 | const log = std.log.scoped(.link); |
| 514 | const macho = std.macho; | 564 | const macho = std.macho; |
| 515 | const math = std.math; | 565 | const math = std.math; |
| 516 | const mem = std.mem; | 566 | const mem = std.mem; |