| author | |
| committer | |
| log | 9bf97b8494524074b1d3cfe71cd08aae335ba576 |
| tree | 531e0ecdc83b766752696417bf35f8a411cb9f7b |
| parent | 5b803aecfb302718b67c465adfdaaef500ab8c68 |
| parent | ca86dc61ddf1f2dd96f78e217ade71f04604d144 |
| signature |
macho: emit relocatable with self-hosted x86_64 backend11 files changed, 467 insertions(+), 184 deletions(-)
src/link/MachO.zig+224-68| ... | @@ -285,8 +285,7 @@ pub fn createEmpty( | ... | @@ -285,8 +285,7 @@ pub fn createEmpty( |
| 285 | }; | 285 | }; |
| 286 | try self.d_sym.?.initMetadata(self); | 286 | try self.d_sym.?.initMetadata(self); |
| 287 | } else { | 287 | } else { |
| 288 | try self.reportUnexpectedError("TODO: implement generating and emitting __DWARF in .o file", .{}); | 288 | @panic("TODO: implement generating and emitting __DWARF in .o file"); |
| 289 | return error.Unexpected; | ||
| 290 | }, | 289 | }, |
| 291 | .code_view => unreachable, | 290 | .code_view => unreachable, |
| 292 | } | 291 | } |
| ... | @@ -597,7 +596,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -597,7 +596,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 597 | 596 | ||
| 598 | try self.allocateSections(); | 597 | try self.allocateSections(); |
| 599 | self.allocateSegments(); | 598 | self.allocateSegments(); |
| 600 | self.allocateAtoms(); | ||
| 601 | self.allocateSyntheticSymbols(); | 599 | self.allocateSyntheticSymbols(); |
| 602 | try self.allocateLinkeditSegment(); | 600 | try self.allocateLinkeditSegment(); |
| 603 | 601 | ||
| ... | @@ -615,7 +613,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -615,7 +613,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 615 | if (!atom.flags.alive) continue; | 613 | if (!atom.flags.alive) continue; |
| 616 | const sect = &self.sections.items(.header)[atom.out_n_sect]; | 614 | const sect = &self.sections.items(.header)[atom.out_n_sect]; |
| 617 | if (sect.isZerofill()) continue; | 615 | if (sect.isZerofill()) continue; |
| 618 | if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately | 616 | if (!self.isZigSection(atom.out_n_sect)) continue; // Non-Zig sections are handled separately |
| 617 | if (atom.getRelocs(self).len == 0) continue; | ||
| 619 | // TODO: we will resolve and write ZigObject's TLS data twice: | 618 | // TODO: we will resolve and write ZigObject's TLS data twice: |
| 620 | // once here, and once in writeAtoms | 619 | // once here, and once in writeAtoms |
| 621 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | 620 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| ... | @@ -636,7 +635,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -636,7 +635,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 636 | return error.FlushFailure; | 635 | return error.FlushFailure; |
| 637 | }, | 636 | }, |
| 638 | }; | 637 | }; |
| 639 | const file_offset = sect.offset + atom.value - sect.addr; | 638 | const file_offset = sect.offset + atom.value; |
| 640 | atom.resolveRelocs(self, code) catch |err| switch (err) { | 639 | atom.resolveRelocs(self, code) catch |err| switch (err) { |
| 641 | error.ResolveFailed => has_resolve_error = true, | 640 | error.ResolveFailed => has_resolve_error = true, |
| 642 | else => |e| { | 641 | else => |e| { |
| ... | @@ -2025,7 +2024,7 @@ pub fn sortSections(self: *MachO) !void { | ... | @@ -2025,7 +2024,7 @@ pub fn sortSections(self: *MachO) !void { |
| 2025 | 2024 | ||
| 2026 | for (zo.symtab.items(.nlist)) |*sym| { | 2025 | for (zo.symtab.items(.nlist)) |*sym| { |
| 2027 | if (sym.sect()) { | 2026 | if (sym.sect()) { |
| 2028 | sym.n_sect = backlinks[sym.n_sect]; | 2027 | sym.n_sect = backlinks[sym.n_sect - 1] + 1; |
| 2029 | } | 2028 | } |
| 2030 | } | 2029 | } |
| 2031 | 2030 | ||
| ... | @@ -2232,11 +2231,11 @@ fn initSegments(self: *MachO) !void { | ... | @@ -2232,11 +2231,11 @@ fn initSegments(self: *MachO) !void { |
| 2232 | log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_size}); | 2231 | log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_size}); |
| 2233 | log.warn(" rounding down to 0x{x}", .{aligned_pagezero_size}); | 2232 | log.warn(" rounding down to 0x{x}", .{aligned_pagezero_size}); |
| 2234 | } | 2233 | } |
| 2235 | _ = try self.addSegment("__PAGEZERO", .{ .vmsize = aligned_pagezero_size }); | 2234 | self.pagezero_seg_index = try self.addSegment("__PAGEZERO", .{ .vmsize = aligned_pagezero_size }); |
| 2236 | } | 2235 | } |
| 2237 | 2236 | ||
| 2238 | // __TEXT segment is non-optional | 2237 | // __TEXT segment is non-optional |
| 2239 | _ = try self.addSegment("__TEXT", .{ .prot = getSegmentProt("__TEXT") }); | 2238 | self.text_seg_index = try self.addSegment("__TEXT", .{ .prot = getSegmentProt("__TEXT") }); |
| 2240 | 2239 | ||
| 2241 | // Next, create segments required by sections | 2240 | // Next, create segments required by sections |
| 2242 | for (slice.items(.header)) |header| { | 2241 | for (slice.items(.header)) |header| { |
| ... | @@ -2248,15 +2247,57 @@ fn initSegments(self: *MachO) !void { | ... | @@ -2248,15 +2247,57 @@ fn initSegments(self: *MachO) !void { |
| 2248 | } | 2247 | } |
| 2249 | 2248 | ||
| 2250 | // Add __LINKEDIT | 2249 | // Add __LINKEDIT |
| 2251 | _ = try self.addSegment("__LINKEDIT", .{ .prot = getSegmentProt("__LINKEDIT") }); | 2250 | self.linkedit_seg_index = try self.addSegment("__LINKEDIT", .{ .prot = getSegmentProt("__LINKEDIT") }); |
| 2252 | 2251 | ||
| 2253 | // Sort segments | 2252 | // Sort segments |
| 2254 | const sortFn = struct { | 2253 | const Entry = struct { |
| 2255 | fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool { | 2254 | index: u8, |
| 2256 | return segmentLessThan(ctx, lhs.segName(), rhs.segName()); | 2255 | |
| 2256 | pub fn lessThan(macho_file: *MachO, lhs: @This(), rhs: @This()) bool { | ||
| 2257 | return segmentLessThan( | ||
| 2258 | {}, | ||
| 2259 | macho_file.segments.items[lhs.index].segName(), | ||
| 2260 | macho_file.segments.items[rhs.index].segName(), | ||
| 2261 | ); | ||
| 2257 | } | 2262 | } |
| 2258 | }.sortFn; | 2263 | }; |
| 2259 | mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn); | 2264 | |
| 2265 | var entries = try std.ArrayList(Entry).initCapacity(gpa, self.segments.items.len); | ||
| 2266 | defer entries.deinit(); | ||
| 2267 | for (0..self.segments.items.len) |index| { | ||
| 2268 | entries.appendAssumeCapacity(.{ .index = @intCast(index) }); | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | mem.sort(Entry, entries.items, self, Entry.lessThan); | ||
| 2272 | |||
| 2273 | const backlinks = try gpa.alloc(u8, entries.items.len); | ||
| 2274 | defer gpa.free(backlinks); | ||
| 2275 | for (entries.items, 0..) |entry, i| { | ||
| 2276 | backlinks[entry.index] = @intCast(i); | ||
| 2277 | } | ||
| 2278 | |||
| 2279 | const segments = try self.segments.toOwnedSlice(gpa); | ||
| 2280 | defer gpa.free(segments); | ||
| 2281 | |||
| 2282 | try self.segments.ensureTotalCapacityPrecise(gpa, segments.len); | ||
| 2283 | for (entries.items) |sorted| { | ||
| 2284 | self.segments.appendAssumeCapacity(segments[sorted.index]); | ||
| 2285 | } | ||
| 2286 | |||
| 2287 | for (&[_]*?u8{ | ||
| 2288 | &self.pagezero_seg_index, | ||
| 2289 | &self.text_seg_index, | ||
| 2290 | &self.linkedit_seg_index, | ||
| 2291 | &self.zig_text_seg_index, | ||
| 2292 | &self.zig_got_seg_index, | ||
| 2293 | &self.zig_const_seg_index, | ||
| 2294 | &self.zig_data_seg_index, | ||
| 2295 | &self.zig_bss_seg_index, | ||
| 2296 | }) |maybe_index| { | ||
| 2297 | if (maybe_index.*) |*index| { | ||
| 2298 | index.* = backlinks[index.*]; | ||
| 2299 | } | ||
| 2300 | } | ||
| 2260 | 2301 | ||
| 2261 | // Attach sections to segments | 2302 | // Attach sections to segments |
| 2262 | for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| { | 2303 | for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| { |
| ... | @@ -2277,15 +2318,6 @@ fn initSegments(self: *MachO) !void { | ... | @@ -2277,15 +2318,6 @@ fn initSegments(self: *MachO) !void { |
| 2277 | segment.nsects += 1; | 2318 | segment.nsects += 1; |
| 2278 | seg_id.* = segment_id; | 2319 | seg_id.* = segment_id; |
| 2279 | } | 2320 | } |
| 2280 | |||
| 2281 | self.pagezero_seg_index = self.getSegmentByName("__PAGEZERO"); | ||
| 2282 | self.text_seg_index = self.getSegmentByName("__TEXT").?; | ||
| 2283 | self.linkedit_seg_index = self.getSegmentByName("__LINKEDIT").?; | ||
| 2284 | self.zig_text_seg_index = self.getSegmentByName("__TEXT_ZIG"); | ||
| 2285 | self.zig_got_seg_index = self.getSegmentByName("__GOT_ZIG"); | ||
| 2286 | self.zig_const_seg_index = self.getSegmentByName("__CONST_ZIG"); | ||
| 2287 | self.zig_data_seg_index = self.getSegmentByName("__DATA_ZIG"); | ||
| 2288 | self.zig_bss_seg_index = self.getSegmentByName("__BSS_ZIG"); | ||
| 2289 | } | 2321 | } |
| 2290 | 2322 | ||
| 2291 | fn allocateSections(self: *MachO) !void { | 2323 | fn allocateSections(self: *MachO) !void { |
| ... | @@ -2300,8 +2332,8 @@ fn allocateSections(self: *MachO) !void { | ... | @@ -2300,8 +2332,8 @@ fn allocateSections(self: *MachO) !void { |
| 2300 | 2332 | ||
| 2301 | const page_size = self.getPageSize(); | 2333 | const page_size = self.getPageSize(); |
| 2302 | const slice = self.sections.slice(); | 2334 | const slice = self.sections.slice(); |
| 2303 | const last_index = for (slice.items(.header), 0..) |header, i| { | 2335 | const last_index = for (0..slice.items(.header).len) |i| { |
| 2304 | if (mem.indexOf(u8, header.segName(), "ZIG")) |_| break i; | 2336 | if (self.isZigSection(@intCast(i))) break i; |
| 2305 | } else slice.items(.header).len; | 2337 | } else slice.items(.header).len; |
| 2306 | 2338 | ||
| 2307 | for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| { | 2339 | for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| { |
| ... | @@ -2354,8 +2386,8 @@ fn allocateSections(self: *MachO) !void { | ... | @@ -2354,8 +2386,8 @@ fn allocateSections(self: *MachO) !void { |
| 2354 | /// We allocate segments in a separate step to also consider segments that have no sections. | 2386 | /// We allocate segments in a separate step to also consider segments that have no sections. |
| 2355 | fn allocateSegments(self: *MachO) void { | 2387 | fn allocateSegments(self: *MachO) void { |
| 2356 | const first_index = if (self.pagezero_seg_index) |index| index + 1 else 0; | 2388 | const first_index = if (self.pagezero_seg_index) |index| index + 1 else 0; |
| 2357 | const last_index = for (self.segments.items, 0..) |seg, i| { | 2389 | const last_index = for (0..self.segments.items.len) |i| { |
| 2358 | if (mem.indexOf(u8, seg.segName(), "ZIG")) |_| break i; | 2390 | if (self.isZigSegment(@intCast(i))) break i; |
| 2359 | } else self.segments.items.len; | 2391 | } else self.segments.items.len; |
| 2360 | 2392 | ||
| 2361 | var vmaddr: u64 = if (self.pagezero_seg_index) |index| | 2393 | var vmaddr: u64 = if (self.pagezero_seg_index) |index| |
| ... | @@ -2392,23 +2424,6 @@ fn allocateSegments(self: *MachO) void { | ... | @@ -2392,23 +2424,6 @@ fn allocateSegments(self: *MachO) void { |
| 2392 | } | 2424 | } |
| 2393 | } | 2425 | } |
| 2394 | 2426 | ||
| 2395 | pub fn allocateAtoms(self: *MachO) void { | ||
| 2396 | const slice = self.sections.slice(); | ||
| 2397 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { | ||
| 2398 | if (atoms.items.len == 0) continue; | ||
| 2399 | for (atoms.items) |atom_index| { | ||
| 2400 | const atom = self.getAtom(atom_index).?; | ||
| 2401 | assert(atom.flags.alive); | ||
| 2402 | atom.value += header.addr; | ||
| 2403 | } | ||
| 2404 | } | ||
| 2405 | |||
| 2406 | for (self.thunks.items) |*thunk| { | ||
| 2407 | const header = self.sections.items(.header)[thunk.out_n_sect]; | ||
| 2408 | thunk.value += header.addr; | ||
| 2409 | } | ||
| 2410 | } | ||
| 2411 | |||
| 2412 | fn allocateSyntheticSymbols(self: *MachO) void { | 2427 | fn allocateSyntheticSymbols(self: *MachO) void { |
| 2413 | const text_seg = self.getTextSegment(); | 2428 | const text_seg = self.getTextSegment(); |
| 2414 | 2429 | ||
| ... | @@ -2603,7 +2618,7 @@ fn writeAtoms(self: *MachO) !void { | ... | @@ -2603,7 +2618,7 @@ fn writeAtoms(self: *MachO) !void { |
| 2603 | for (atoms.items) |atom_index| { | 2618 | for (atoms.items) |atom_index| { |
| 2604 | const atom = self.getAtom(atom_index).?; | 2619 | const atom = self.getAtom(atom_index).?; |
| 2605 | assert(atom.flags.alive); | 2620 | assert(atom.flags.alive); |
| 2606 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; | 2621 | const off = math.cast(usize, atom.value) orelse return error.Overflow; |
| 2607 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | 2622 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 2608 | try atom.getData(self, buffer[off..][0..atom_size]); | 2623 | try atom.getData(self, buffer[off..][0..atom_size]); |
| 2609 | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { | 2624 | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { |
| ... | @@ -2617,7 +2632,7 @@ fn writeAtoms(self: *MachO) !void { | ... | @@ -2617,7 +2632,7 @@ fn writeAtoms(self: *MachO) !void { |
| 2617 | 2632 | ||
| 2618 | for (self.thunks.items) |thunk| { | 2633 | for (self.thunks.items) |thunk| { |
| 2619 | const header = slice.items(.header)[thunk.out_n_sect]; | 2634 | const header = slice.items(.header)[thunk.out_n_sect]; |
| 2620 | const offset = thunk.value - header.addr + header.offset; | 2635 | const offset = thunk.value + header.offset; |
| 2621 | const buffer = try gpa.alloc(u8, thunk.size()); | 2636 | const buffer = try gpa.alloc(u8, thunk.size()); |
| 2622 | defer gpa.free(buffer); | 2637 | defer gpa.free(buffer); |
| 2623 | var stream = std.io.fixedBufferStream(buffer); | 2638 | var stream = std.io.fixedBufferStream(buffer); |
| ... | @@ -2825,7 +2840,7 @@ pub fn writeDataInCode(self: *MachO, base_address: u64, off: u32) !u32 { | ... | @@ -2825,7 +2840,7 @@ pub fn writeDataInCode(self: *MachO, base_address: u64, off: u32) !u32 { |
| 2825 | 2840 | ||
| 2826 | if (atom.flags.alive) for (in_dices[start_dice..next_dice]) |dice| { | 2841 | if (atom.flags.alive) for (in_dices[start_dice..next_dice]) |dice| { |
| 2827 | dices.appendAssumeCapacity(.{ | 2842 | dices.appendAssumeCapacity(.{ |
| 2828 | .offset = @intCast(atom.value + dice.offset - start_off - base_address), | 2843 | .offset = @intCast(atom.getAddress(self) + dice.offset - start_off - base_address), |
| 2829 | .length = dice.length, | 2844 | .length = dice.length, |
| 2830 | .kind = dice.kind, | 2845 | .kind = dice.kind, |
| 2831 | }); | 2846 | }); |
| ... | @@ -3276,6 +3291,34 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | ... | @@ -3276,6 +3291,34 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 3276 | return null; | 3291 | return null; |
| 3277 | } | 3292 | } |
| 3278 | 3293 | ||
| 3294 | fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 { | ||
| 3295 | // Conservatively commit one page size as reserved space for the headers as we | ||
| 3296 | // expect it to grow and everything else be moved in flush anyhow. | ||
| 3297 | const header_size = self.getPageSize(); | ||
| 3298 | if (start < header_size) | ||
| 3299 | return header_size; | ||
| 3300 | |||
| 3301 | const end = start + padToIdeal(size); | ||
| 3302 | |||
| 3303 | for (self.sections.items(.header)) |header| { | ||
| 3304 | const increased_size = padToIdeal(header.size); | ||
| 3305 | const test_end = header.addr + increased_size; | ||
| 3306 | if (end > header.addr and start < test_end) { | ||
| 3307 | return test_end; | ||
| 3308 | } | ||
| 3309 | } | ||
| 3310 | |||
| 3311 | for (self.segments.items) |seg| { | ||
| 3312 | const increased_size = padToIdeal(seg.vmsize); | ||
| 3313 | const test_end = seg.vmaddr +| increased_size; | ||
| 3314 | if (end > seg.vmaddr and start < test_end) { | ||
| 3315 | return test_end; | ||
| 3316 | } | ||
| 3317 | } | ||
| 3318 | |||
| 3319 | return null; | ||
| 3320 | } | ||
| 3321 | |||
| 3279 | fn allocatedSize(self: *MachO, start: u64) u64 { | 3322 | fn allocatedSize(self: *MachO, start: u64) u64 { |
| 3280 | if (start == 0) return 0; | 3323 | if (start == 0) return 0; |
| 3281 | var min_pos: u64 = std.math.maxInt(u64); | 3324 | var min_pos: u64 = std.math.maxInt(u64); |
| ... | @@ -3290,7 +3333,7 @@ fn allocatedSize(self: *MachO, start: u64) u64 { | ... | @@ -3290,7 +3333,7 @@ fn allocatedSize(self: *MachO, start: u64) u64 { |
| 3290 | return min_pos - start; | 3333 | return min_pos - start; |
| 3291 | } | 3334 | } |
| 3292 | 3335 | ||
| 3293 | fn allocatedVirtualSize(self: *MachO, start: u64) u64 { | 3336 | fn allocatedSizeVirtual(self: *MachO, start: u64) u64 { |
| 3294 | if (start == 0) return 0; | 3337 | if (start == 0) return 0; |
| 3295 | var min_pos: u64 = std.math.maxInt(u64); | 3338 | var min_pos: u64 = std.math.maxInt(u64); |
| 3296 | for (self.segments.items) |seg| { | 3339 | for (self.segments.items) |seg| { |
| ... | @@ -3300,7 +3343,7 @@ fn allocatedVirtualSize(self: *MachO, start: u64) u64 { | ... | @@ -3300,7 +3343,7 @@ fn allocatedVirtualSize(self: *MachO, start: u64) u64 { |
| 3300 | return min_pos - start; | 3343 | return min_pos - start; |
| 3301 | } | 3344 | } |
| 3302 | 3345 | ||
| 3303 | fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { | 3346 | pub fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { |
| 3304 | var start: u64 = 0; | 3347 | var start: u64 = 0; |
| 3305 | while (self.detectAllocCollision(start, object_size)) |item_end| { | 3348 | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| 3306 | start = mem.alignForward(u64, item_end, min_alignment); | 3349 | start = mem.alignForward(u64, item_end, min_alignment); |
| ... | @@ -3308,18 +3351,30 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { | ... | @@ -3308,18 +3351,30 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { |
| 3308 | return start; | 3351 | return start; |
| 3309 | } | 3352 | } |
| 3310 | 3353 | ||
| 3354 | pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32) u64 { | ||
| 3355 | var start: u64 = 0; | ||
| 3356 | while (self.detectAllocCollisionVirtual(start, object_size)) |item_end| { | ||
| 3357 | start = mem.alignForward(u64, item_end, min_alignment); | ||
| 3358 | } | ||
| 3359 | return start; | ||
| 3360 | } | ||
| 3361 | |||
| 3362 | pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { | ||
| 3363 | const file = self.base.file.?; | ||
| 3364 | const amt = try file.copyRangeAll(old_offset, file, new_offset, size); | ||
| 3365 | if (amt != size) return error.InputOutput; | ||
| 3366 | } | ||
| 3367 | |||
| 3311 | /// Like File.copyRangeAll but also ensures the source region is zeroed out after copy. | 3368 | /// Like File.copyRangeAll but also ensures the source region is zeroed out after copy. |
| 3312 | /// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader. | 3369 | /// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader. |
| 3313 | fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { | 3370 | fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { |
| 3314 | const gpa = self.base.comp.gpa; | 3371 | const gpa = self.base.comp.gpa; |
| 3315 | const file = self.base.file.?; | 3372 | try self.copyRangeAll(old_offset, new_offset, size); |
| 3316 | const amt = try file.copyRangeAll(old_offset, file, new_offset, size); | ||
| 3317 | if (amt != size) return error.InputOutput; | ||
| 3318 | const size_u = math.cast(usize, size) orelse return error.Overflow; | 3373 | const size_u = math.cast(usize, size) orelse return error.Overflow; |
| 3319 | const zeroes = try gpa.alloc(u8, size_u); | 3374 | const zeroes = try gpa.alloc(u8, size_u); |
| 3320 | defer gpa.free(zeroes); | 3375 | defer gpa.free(zeroes); |
| 3321 | @memset(zeroes, 0); | 3376 | @memset(zeroes, 0); |
| 3322 | try file.pwriteAll(zeroes, old_offset); | 3377 | try self.base.file.?.pwriteAll(zeroes, old_offset); |
| 3323 | } | 3378 | } |
| 3324 | 3379 | ||
| 3325 | const InitMetadataOptions = struct { | 3380 | const InitMetadataOptions = struct { |
| ... | @@ -3391,8 +3446,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { | ... | @@ -3391,8 +3446,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3391 | .prot = macho.PROT.READ | macho.PROT.WRITE, | 3446 | .prot = macho.PROT.READ | macho.PROT.WRITE, |
| 3392 | }); | 3447 | }); |
| 3393 | } | 3448 | } |
| 3394 | } else { | ||
| 3395 | @panic("TODO initMetadata when relocatable"); | ||
| 3396 | } | 3449 | } |
| 3397 | 3450 | ||
| 3398 | const appendSect = struct { | 3451 | const appendSect = struct { |
| ... | @@ -3406,6 +3459,19 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { | ... | @@ -3406,6 +3459,19 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3406 | } | 3459 | } |
| 3407 | }.appendSect; | 3460 | }.appendSect; |
| 3408 | 3461 | ||
| 3462 | const allocSect = struct { | ||
| 3463 | fn allocSect(macho_file: *MachO, sect_id: u8, size: u64) !void { | ||
| 3464 | const sect = &macho_file.sections.items(.header)[sect_id]; | ||
| 3465 | const alignment = try math.powi(u32, 2, sect.@"align"); | ||
| 3466 | if (!sect.isZerofill()) { | ||
| 3467 | sect.offset = math.cast(u32, macho_file.findFreeSpace(size, alignment)) orelse | ||
| 3468 | return error.Overflow; | ||
| 3469 | } | ||
| 3470 | sect.addr = macho_file.findFreeSpaceVirtual(size, alignment); | ||
| 3471 | sect.size = size; | ||
| 3472 | } | ||
| 3473 | }.allocSect; | ||
| 3474 | |||
| 3409 | { | 3475 | { |
| 3410 | self.zig_text_sect_index = try self.addSection("__TEXT_ZIG", "__text_zig", .{ | 3476 | self.zig_text_sect_index = try self.addSection("__TEXT_ZIG", "__text_zig", .{ |
| 3411 | .alignment = switch (self.getTarget().cpu.arch) { | 3477 | .alignment = switch (self.getTarget().cpu.arch) { |
| ... | @@ -3415,7 +3481,11 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { | ... | @@ -3415,7 +3481,11 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3415 | }, | 3481 | }, |
| 3416 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 3482 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 3417 | }); | 3483 | }); |
| 3418 | appendSect(self, self.zig_text_sect_index.?, self.zig_text_seg_index.?); | 3484 | if (self.base.isRelocatable()) { |
| 3485 | try allocSect(self, self.zig_text_sect_index.?, options.program_code_size_hint); | ||
| 3486 | } else { | ||
| 3487 | appendSect(self, self.zig_text_sect_index.?, self.zig_text_seg_index.?); | ||
| 3488 | } | ||
| 3419 | } | 3489 | } |
| 3420 | 3490 | ||
| 3421 | if (!self.base.isRelocatable()) { | 3491 | if (!self.base.isRelocatable()) { |
| ... | @@ -3427,33 +3497,52 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { | ... | @@ -3427,33 +3497,52 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3427 | 3497 | ||
| 3428 | { | 3498 | { |
| 3429 | self.zig_const_sect_index = try self.addSection("__CONST_ZIG", "__const_zig", .{}); | 3499 | self.zig_const_sect_index = try self.addSection("__CONST_ZIG", "__const_zig", .{}); |
| 3430 | appendSect(self, self.zig_const_sect_index.?, self.zig_const_seg_index.?); | 3500 | if (self.base.isRelocatable()) { |
| 3501 | try allocSect(self, self.zig_const_sect_index.?, 1024); | ||
| 3502 | } else { | ||
| 3503 | appendSect(self, self.zig_const_sect_index.?, self.zig_const_seg_index.?); | ||
| 3504 | } | ||
| 3431 | } | 3505 | } |
| 3432 | 3506 | ||
| 3433 | { | 3507 | { |
| 3434 | self.zig_data_sect_index = try self.addSection("__DATA_ZIG", "__data_zig", .{}); | 3508 | self.zig_data_sect_index = try self.addSection("__DATA_ZIG", "__data_zig", .{}); |
| 3435 | appendSect(self, self.zig_data_sect_index.?, self.zig_data_seg_index.?); | 3509 | if (self.base.isRelocatable()) { |
| 3510 | try allocSect(self, self.zig_data_sect_index.?, 1024); | ||
| 3511 | } else { | ||
| 3512 | appendSect(self, self.zig_data_sect_index.?, self.zig_data_seg_index.?); | ||
| 3513 | } | ||
| 3436 | } | 3514 | } |
| 3437 | 3515 | ||
| 3438 | { | 3516 | { |
| 3439 | self.zig_bss_sect_index = try self.addSection("__BSS_ZIG", "__bss_zig", .{ | 3517 | self.zig_bss_sect_index = try self.addSection("__BSS_ZIG", "__bss_zig", .{ |
| 3440 | .flags = macho.S_ZEROFILL, | 3518 | .flags = macho.S_ZEROFILL, |
| 3441 | }); | 3519 | }); |
| 3442 | appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?); | 3520 | if (self.base.isRelocatable()) { |
| 3521 | try allocSect(self, self.zig_bss_sect_index.?, 1024); | ||
| 3522 | } else { | ||
| 3523 | appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?); | ||
| 3524 | } | ||
| 3443 | } | 3525 | } |
| 3444 | } | 3526 | } |
| 3445 | 3527 | ||
| 3446 | pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { | 3528 | pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3529 | if (self.base.isRelocatable()) { | ||
| 3530 | try self.growSectionRelocatable(sect_index, needed_size); | ||
| 3531 | } else { | ||
| 3532 | try self.growSectionNonRelocatable(sect_index, needed_size); | ||
| 3533 | } | ||
| 3534 | } | ||
| 3535 | |||
| 3536 | fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void { | ||
| 3447 | const sect = &self.sections.items(.header)[sect_index]; | 3537 | const sect = &self.sections.items(.header)[sect_index]; |
| 3448 | const seg_id = self.sections.items(.segment_id)[sect_index]; | ||
| 3449 | const seg = &self.segments.items[seg_id]; | ||
| 3450 | 3538 | ||
| 3451 | if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) { | 3539 | if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) { |
| 3452 | const existing_size = sect.size; | 3540 | const existing_size = sect.size; |
| 3453 | sect.size = 0; | 3541 | sect.size = 0; |
| 3454 | 3542 | ||
| 3455 | // Must move the entire section. | 3543 | // Must move the entire section. |
| 3456 | const new_offset = self.findFreeSpace(needed_size, self.getPageSize()); | 3544 | const alignment = self.getPageSize(); |
| 3545 | const new_offset = self.findFreeSpace(needed_size, alignment); | ||
| 3457 | 3546 | ||
| 3458 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ | 3547 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ |
| 3459 | sect.segName(), | 3548 | sect.segName(), |
| ... | @@ -3465,15 +3554,19 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { | ... | @@ -3465,15 +3554,19 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3465 | try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); | 3554 | try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); |
| 3466 | 3555 | ||
| 3467 | sect.offset = @intCast(new_offset); | 3556 | sect.offset = @intCast(new_offset); |
| 3468 | seg.fileoff = new_offset; | ||
| 3469 | } | 3557 | } |
| 3470 | 3558 | ||
| 3471 | sect.size = needed_size; | 3559 | sect.size = needed_size; |
| 3560 | |||
| 3561 | const seg_id = self.sections.items(.segment_id)[sect_index]; | ||
| 3562 | const seg = &self.segments.items[seg_id]; | ||
| 3563 | seg.fileoff = sect.offset; | ||
| 3564 | |||
| 3472 | if (!sect.isZerofill()) { | 3565 | if (!sect.isZerofill()) { |
| 3473 | seg.filesize = needed_size; | 3566 | seg.filesize = needed_size; |
| 3474 | } | 3567 | } |
| 3475 | 3568 | ||
| 3476 | const mem_capacity = self.allocatedVirtualSize(seg.vmaddr); | 3569 | const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr); |
| 3477 | if (needed_size > mem_capacity) { | 3570 | if (needed_size > mem_capacity) { |
| 3478 | var err = try self.addErrorWithNotes(2); | 3571 | var err = try self.addErrorWithNotes(2); |
| 3479 | try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{ | 3572 | try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{ |
| ... | @@ -3487,6 +3580,36 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { | ... | @@ -3487,6 +3580,36 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3487 | seg.vmsize = needed_size; | 3580 | seg.vmsize = needed_size; |
| 3488 | } | 3581 | } |
| 3489 | 3582 | ||
| 3583 | fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void { | ||
| 3584 | const sect = &self.sections.items(.header)[sect_index]; | ||
| 3585 | |||
| 3586 | if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) { | ||
| 3587 | const existing_size = sect.size; | ||
| 3588 | sect.size = 0; | ||
| 3589 | |||
| 3590 | // Must move the entire section. | ||
| 3591 | const alignment = try math.powi(u32, 2, sect.@"align"); | ||
| 3592 | const new_offset = self.findFreeSpace(needed_size, alignment); | ||
| 3593 | const new_addr = self.findFreeSpaceVirtual(needed_size, alignment); | ||
| 3594 | |||
| 3595 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ | ||
| 3596 | sect.segName(), | ||
| 3597 | sect.sectName(), | ||
| 3598 | new_offset, | ||
| 3599 | new_offset + existing_size, | ||
| 3600 | new_addr, | ||
| 3601 | new_addr + existing_size, | ||
| 3602 | }); | ||
| 3603 | |||
| 3604 | try self.copyRangeAll(sect.offset, new_offset, existing_size); | ||
| 3605 | |||
| 3606 | sect.offset = @intCast(new_offset); | ||
| 3607 | sect.addr = new_addr; | ||
| 3608 | } | ||
| 3609 | |||
| 3610 | sect.size = needed_size; | ||
| 3611 | } | ||
| 3612 | |||
| 3490 | pub fn getTarget(self: MachO) std.Target { | 3613 | pub fn getTarget(self: MachO) std.Target { |
| 3491 | return self.base.comp.root_mod.resolved_target.result; | 3614 | return self.base.comp.root_mod.resolved_target.result; |
| 3492 | } | 3615 | } |
| ... | @@ -3532,6 +3655,36 @@ inline fn requiresThunks(self: MachO) bool { | ... | @@ -3532,6 +3655,36 @@ inline fn requiresThunks(self: MachO) bool { |
| 3532 | return self.getTarget().cpu.arch == .aarch64; | 3655 | return self.getTarget().cpu.arch == .aarch64; |
| 3533 | } | 3656 | } |
| 3534 | 3657 | ||
| 3658 | pub fn isZigSegment(self: MachO, seg_id: u8) bool { | ||
| 3659 | inline for (&[_]?u8{ | ||
| 3660 | self.zig_text_seg_index, | ||
| 3661 | self.zig_got_seg_index, | ||
| 3662 | self.zig_const_seg_index, | ||
| 3663 | self.zig_data_seg_index, | ||
| 3664 | self.zig_bss_seg_index, | ||
| 3665 | }) |maybe_index| { | ||
| 3666 | if (maybe_index) |index| { | ||
| 3667 | if (index == seg_id) return true; | ||
| 3668 | } | ||
| 3669 | } | ||
| 3670 | return false; | ||
| 3671 | } | ||
| 3672 | |||
| 3673 | pub fn isZigSection(self: MachO, sect_id: u8) bool { | ||
| 3674 | inline for (&[_]?u8{ | ||
| 3675 | self.zig_text_sect_index, | ||
| 3676 | self.zig_got_sect_index, | ||
| 3677 | self.zig_const_sect_index, | ||
| 3678 | self.zig_data_sect_index, | ||
| 3679 | self.zig_bss_sect_index, | ||
| 3680 | }) |maybe_index| { | ||
| 3681 | if (maybe_index) |index| { | ||
| 3682 | if (index == sect_id) return true; | ||
| 3683 | } | ||
| 3684 | } | ||
| 3685 | return false; | ||
| 3686 | } | ||
| 3687 | |||
| 3535 | pub fn addSegment(self: *MachO, name: []const u8, opts: struct { | 3688 | pub fn addSegment(self: *MachO, name: []const u8, opts: struct { |
| 3536 | vmaddr: u64 = 0, | 3689 | vmaddr: u64 = 0, |
| 3537 | vmsize: u64 = 0, | 3690 | vmsize: u64 = 0, |
| ... | @@ -4033,10 +4186,13 @@ fn formatSections( | ... | @@ -4033,10 +4186,13 @@ fn formatSections( |
| 4033 | _ = unused_fmt_string; | 4186 | _ = unused_fmt_string; |
| 4034 | const slice = self.sections.slice(); | 4187 | const slice = self.sections.slice(); |
| 4035 | for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| { | 4188 | for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| { |
| 4036 | try writer.print("sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x})\n", .{ | 4189 | try writer.print( |
| 4037 | i, seg_id, header.segName(), header.sectName(), header.offset, header.addr, | 4190 | "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n", |
| 4038 | header.@"align", header.size, | 4191 | .{ |
| 4039 | }); | 4192 | i, seg_id, header.segName(), header.sectName(), header.addr, header.offset, |
| 4193 | header.@"align", header.size, header.reloff, header.nreloc, | ||
| 4194 | }, | ||
| 4195 | ); | ||
| 4040 | } | 4196 | } |
| 4041 | } | 4197 | } |
| 4042 | 4198 |
src/link/MachO/Atom.zig+39-34| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | /// Address allocated for this Atom. | 1 | /// Address offset allocated for this Atom wrt to its section start address. |
| 2 | value: u64 = 0, | 2 | value: u64 = 0, |
| 3 | 3 | ||
| 4 | /// Name of this Atom. | 4 | /// Name of this Atom. |
| ... | @@ -84,6 +84,11 @@ pub fn getInputAddress(self: Atom, macho_file: *MachO) u64 { | ... | @@ -84,6 +84,11 @@ pub fn getInputAddress(self: Atom, macho_file: *MachO) u64 { |
| 84 | return self.getInputSection(macho_file).addr + self.off; | 84 | return self.getInputSection(macho_file).addr + self.off; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | pub fn getAddress(self: Atom, macho_file: *MachO) u64 { | ||
| 88 | const header = macho_file.sections.items(.header)[self.out_n_sect]; | ||
| 89 | return header.addr + self.value; | ||
| 90 | } | ||
| 91 | |||
| 87 | pub fn getPriority(self: Atom, macho_file: *MachO) u64 { | 92 | pub fn getPriority(self: Atom, macho_file: *MachO) u64 { |
| 88 | const file = self.getFile(macho_file); | 93 | const file = self.getFile(macho_file); |
| 89 | return (@as(u64, @intCast(file.getIndex())) << 32) | @as(u64, @intCast(self.n_sect)); | 94 | return (@as(u64, @intCast(file.getIndex())) << 32) | @as(u64, @intCast(self.n_sect)); |
| ... | @@ -114,9 +119,12 @@ pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { | ... | @@ -114,9 +119,12 @@ pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { |
| 114 | 119 | ||
| 115 | pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { | 120 | pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 116 | const segname, const sectname, const flags = blk: { | 121 | const segname, const sectname, const flags = blk: { |
| 122 | const segname = sect.segName(); | ||
| 123 | const sectname = sect.sectName(); | ||
| 124 | |||
| 117 | if (sect.isCode()) break :blk .{ | 125 | if (sect.isCode()) break :blk .{ |
| 118 | "__TEXT", | 126 | "__TEXT", |
| 119 | sect.sectName(), | 127 | sectname, |
| 120 | macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 128 | macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 121 | }; | 129 | }; |
| 122 | 130 | ||
| ... | @@ -127,34 +135,29 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { | ... | @@ -127,34 +135,29 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 127 | => break :blk .{ "__TEXT", "__const", macho.S_REGULAR }, | 135 | => break :blk .{ "__TEXT", "__const", macho.S_REGULAR }, |
| 128 | 136 | ||
| 129 | macho.S_CSTRING_LITERALS => { | 137 | macho.S_CSTRING_LITERALS => { |
| 130 | if (mem.startsWith(u8, sect.sectName(), "__objc")) break :blk .{ | 138 | if (mem.startsWith(u8, sectname, "__objc")) break :blk .{ |
| 131 | sect.segName(), sect.sectName(), macho.S_REGULAR, | 139 | segname, sectname, macho.S_REGULAR, |
| 132 | }; | 140 | }; |
| 133 | break :blk .{ "__TEXT", "__cstring", macho.S_CSTRING_LITERALS }; | 141 | break :blk .{ "__TEXT", "__cstring", macho.S_CSTRING_LITERALS }; |
| 134 | }, | 142 | }, |
| 135 | 143 | ||
| 136 | macho.S_MOD_INIT_FUNC_POINTERS, | 144 | macho.S_MOD_INIT_FUNC_POINTERS, |
| 137 | macho.S_MOD_TERM_FUNC_POINTERS, | 145 | macho.S_MOD_TERM_FUNC_POINTERS, |
| 138 | => break :blk .{ "__DATA_CONST", sect.sectName(), sect.flags }, | ||
| 139 | |||
| 140 | macho.S_LITERAL_POINTERS, | 146 | macho.S_LITERAL_POINTERS, |
| 147 | => break :blk .{ "__DATA_CONST", sectname, sect.flags }, | ||
| 148 | |||
| 141 | macho.S_ZEROFILL, | 149 | macho.S_ZEROFILL, |
| 142 | macho.S_GB_ZEROFILL, | 150 | macho.S_GB_ZEROFILL, |
| 143 | macho.S_THREAD_LOCAL_VARIABLES, | 151 | macho.S_THREAD_LOCAL_VARIABLES, |
| 144 | macho.S_THREAD_LOCAL_VARIABLE_POINTERS, | 152 | macho.S_THREAD_LOCAL_VARIABLE_POINTERS, |
| 145 | macho.S_THREAD_LOCAL_REGULAR, | 153 | macho.S_THREAD_LOCAL_REGULAR, |
| 146 | macho.S_THREAD_LOCAL_ZEROFILL, | 154 | macho.S_THREAD_LOCAL_ZEROFILL, |
| 147 | => break :blk .{ sect.segName(), sect.sectName(), sect.flags }, | 155 | => break :blk .{ "__DATA", sectname, sect.flags }, |
| 148 | 156 | ||
| 149 | macho.S_COALESCED => break :blk .{ | 157 | // TODO: do we need this check here? |
| 150 | sect.segName(), | 158 | macho.S_COALESCED => break :blk .{ segname, sectname, macho.S_REGULAR }, |
| 151 | sect.sectName(), | ||
| 152 | macho.S_REGULAR, | ||
| 153 | }, | ||
| 154 | 159 | ||
| 155 | macho.S_REGULAR => { | 160 | macho.S_REGULAR => { |
| 156 | const segname = sect.segName(); | ||
| 157 | const sectname = sect.sectName(); | ||
| 158 | if (mem.eql(u8, segname, "__DATA")) { | 161 | if (mem.eql(u8, segname, "__DATA")) { |
| 159 | if (mem.eql(u8, sectname, "__const") or | 162 | if (mem.eql(u8, sectname, "__const") or |
| 160 | mem.eql(u8, sectname, "__cfstring") or | 163 | mem.eql(u8, sectname, "__cfstring") or |
| ... | @@ -168,7 +171,7 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { | ... | @@ -168,7 +171,7 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 168 | break :blk .{ segname, sectname, sect.flags }; | 171 | break :blk .{ segname, sectname, sect.flags }; |
| 169 | }, | 172 | }, |
| 170 | 173 | ||
| 171 | else => break :blk .{ sect.segName(), sect.sectName(), sect.flags }, | 174 | else => break :blk .{ segname, sectname, sect.flags }, |
| 172 | } | 175 | } |
| 173 | }; | 176 | }; |
| 174 | const osec = macho_file.getSectionByName(segname, sectname) orelse try macho_file.addSection( | 177 | const osec = macho_file.getSectionByName(segname, sectname) orelse try macho_file.addSection( |
| ... | @@ -189,14 +192,17 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { | ... | @@ -189,14 +192,17 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 189 | /// File offset relocation happens transparently, so it is not included in | 192 | /// File offset relocation happens transparently, so it is not included in |
| 190 | /// this calculation. | 193 | /// this calculation. |
| 191 | pub fn capacity(self: Atom, macho_file: *MachO) u64 { | 194 | pub fn capacity(self: Atom, macho_file: *MachO) u64 { |
| 192 | const next_value = if (macho_file.getAtom(self.next_index)) |next| next.value else std.math.maxInt(u32); | 195 | const next_addr = if (macho_file.getAtom(self.next_index)) |next| |
| 193 | return next_value - self.value; | 196 | next.getAddress(macho_file) |
| 197 | else | ||
| 198 | std.math.maxInt(u32); | ||
| 199 | return next_addr - self.getAddress(macho_file); | ||
| 194 | } | 200 | } |
| 195 | 201 | ||
| 196 | pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { | 202 | pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { |
| 197 | // No need to keep a free list node for the last block. | 203 | // No need to keep a free list node for the last block. |
| 198 | const next = macho_file.getAtom(self.next_index) orelse return false; | 204 | const next = macho_file.getAtom(self.next_index) orelse return false; |
| 199 | const cap = next.value - self.value; | 205 | const cap = next.getAddress(macho_file) - self.getAddress(macho_file); |
| 200 | const ideal_cap = MachO.padToIdeal(self.size); | 206 | const ideal_cap = MachO.padToIdeal(self.size); |
| 201 | if (cap <= ideal_cap) return false; | 207 | if (cap <= ideal_cap) return false; |
| 202 | const surplus = cap - ideal_cap; | 208 | const surplus = cap - ideal_cap; |
| ... | @@ -263,15 +269,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { | ... | @@ -263,15 +269,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 263 | atom_placement = last.atom_index; | 269 | atom_placement = last.atom_index; |
| 264 | break :blk new_start_vaddr; | 270 | break :blk new_start_vaddr; |
| 265 | } else { | 271 | } else { |
| 266 | break :blk sect.addr; | 272 | break :blk 0; |
| 267 | } | 273 | } |
| 268 | }; | 274 | }; |
| 269 | 275 | ||
| 270 | log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{ | 276 | log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{ |
| 271 | self.atom_index, | 277 | self.atom_index, |
| 272 | self.getName(macho_file), | 278 | self.getName(macho_file), |
| 273 | self.value, | 279 | self.getAddress(macho_file), |
| 274 | self.value + self.size, | 280 | self.getAddress(macho_file) + self.size, |
| 275 | }); | 281 | }); |
| 276 | 282 | ||
| 277 | const expand_section = if (atom_placement) |placement_index| | 283 | const expand_section = if (atom_placement) |placement_index| |
| ... | @@ -279,7 +285,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { | ... | @@ -279,7 +285,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 279 | else | 285 | else |
| 280 | true; | 286 | true; |
| 281 | if (expand_section) { | 287 | if (expand_section) { |
| 282 | const needed_size = (self.value + self.size) - sect.addr; | 288 | const needed_size = self.value + self.size; |
| 283 | try macho_file.growSection(self.out_n_sect, needed_size); | 289 | try macho_file.growSection(self.out_n_sect, needed_size); |
| 284 | last_atom_index.* = self.atom_index; | 290 | last_atom_index.* = self.atom_index; |
| 285 | 291 | ||
| ... | @@ -544,7 +550,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -544,7 +550,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 544 | const name = self.getName(macho_file); | 550 | const name = self.getName(macho_file); |
| 545 | const relocs = self.getRelocs(macho_file); | 551 | const relocs = self.getRelocs(macho_file); |
| 546 | 552 | ||
| 547 | relocs_log.debug("{x}: {s}", .{ self.value, name }); | 553 | relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), name }); |
| 548 | 554 | ||
| 549 | var has_error = false; | 555 | var has_error = false; |
| 550 | var stream = std.io.fixedBufferStream(buffer); | 556 | var stream = std.io.fixedBufferStream(buffer); |
| ... | @@ -569,7 +575,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -569,7 +575,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 569 | try macho_file.reportParseError2( | 575 | try macho_file.reportParseError2( |
| 570 | file.getIndex(), | 576 | file.getIndex(), |
| 571 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {s}, target {s}", | 577 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {s}, target {s}", |
| 572 | .{ name, self.value, rel.offset, @tagName(rel.type), target }, | 578 | .{ name, self.getAddress(macho_file), rel.offset, @tagName(rel.type), target }, |
| 573 | ); | 579 | ); |
| 574 | has_error = true; | 580 | has_error = true; |
| 575 | }, | 581 | }, |
| ... | @@ -604,7 +610,7 @@ fn resolveRelocInner( | ... | @@ -604,7 +610,7 @@ fn resolveRelocInner( |
| 604 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; | 610 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; |
| 605 | const seg_id = macho_file.sections.items(.segment_id)[self.out_n_sect]; | 611 | const seg_id = macho_file.sections.items(.segment_id)[self.out_n_sect]; |
| 606 | const seg = macho_file.segments.items[seg_id]; | 612 | const seg = macho_file.segments.items[seg_id]; |
| 607 | const P = @as(i64, @intCast(self.value)) + @as(i64, @intCast(rel_offset)); | 613 | const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); |
| 608 | const A = rel.addend + rel.getRelocAddend(cpu_arch); | 614 | const A = rel.addend + rel.getRelocAddend(cpu_arch); |
| 609 | const S: i64 = @intCast(rel.getTargetAddress(macho_file)); | 615 | const S: i64 = @intCast(rel.getTargetAddress(macho_file)); |
| 610 | const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); | 616 | const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); |
| ... | @@ -690,7 +696,7 @@ fn resolveRelocInner( | ... | @@ -690,7 +696,7 @@ fn resolveRelocInner( |
| 690 | .aarch64 => { | 696 | .aarch64 => { |
| 691 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { | 697 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { |
| 692 | const thunk = self.getThunk(macho_file); | 698 | const thunk = self.getThunk(macho_file); |
| 693 | const S_: i64 = @intCast(thunk.getAddress(rel.target)); | 699 | const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file)); |
| 694 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; | 700 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 695 | }; | 701 | }; |
| 696 | var inst = aarch64.Instruction{ | 702 | var inst = aarch64.Instruction{ |
| ... | @@ -919,7 +925,7 @@ const x86_64 = struct { | ... | @@ -919,7 +925,7 @@ const x86_64 = struct { |
| 919 | var err = try macho_file.addErrorWithNotes(2); | 925 | var err = try macho_file.addErrorWithNotes(2); |
| 920 | try err.addMsg(macho_file, "{s}: 0x{x}: 0x{x}: failed to relax relocation of type {s}", .{ | 926 | try err.addMsg(macho_file, "{s}: 0x{x}: 0x{x}: failed to relax relocation of type {s}", .{ |
| 921 | self.getName(macho_file), | 927 | self.getName(macho_file), |
| 922 | self.value, | 928 | self.getAddress(macho_file), |
| 923 | rel.offset, | 929 | rel.offset, |
| 924 | @tagName(rel.type), | 930 | @tagName(rel.type), |
| 925 | }); | 931 | }); |
| ... | @@ -990,12 +996,11 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra | ... | @@ -990,12 +996,11 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 990 | 996 | ||
| 991 | const cpu_arch = macho_file.getTarget().cpu.arch; | 997 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 992 | const relocs = self.getRelocs(macho_file); | 998 | const relocs = self.getRelocs(macho_file); |
| 993 | const sect = macho_file.sections.items(.header)[self.out_n_sect]; | ||
| 994 | var stream = std.io.fixedBufferStream(code); | 999 | var stream = std.io.fixedBufferStream(code); |
| 995 | 1000 | ||
| 996 | for (relocs) |rel| { | 1001 | for (relocs) |rel| { |
| 997 | const rel_offset = rel.offset - self.off; | 1002 | const rel_offset = rel.offset - self.off; |
| 998 | const r_address: i32 = math.cast(i32, self.value + rel_offset - sect.addr) orelse return error.Overflow; | 1003 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; |
| 999 | const r_symbolnum = r_symbolnum: { | 1004 | const r_symbolnum = r_symbolnum: { |
| 1000 | const r_symbolnum: u32 = switch (rel.tag) { | 1005 | const r_symbolnum: u32 = switch (rel.tag) { |
| 1001 | .local => rel.getTargetAtom(macho_file).out_n_sect + 1, | 1006 | .local => rel.getTargetAtom(macho_file).out_n_sect + 1, |
| ... | @@ -1062,7 +1067,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra | ... | @@ -1062,7 +1067,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1062 | .x86_64 => { | 1067 | .x86_64 => { |
| 1063 | if (rel.meta.pcrel) { | 1068 | if (rel.meta.pcrel) { |
| 1064 | if (rel.tag == .local) { | 1069 | if (rel.tag == .local) { |
| 1065 | addend -= @as(i64, @intCast(self.value + rel_offset)); | 1070 | addend -= @as(i64, @intCast(self.getAddress(macho_file) + rel_offset)); |
| 1066 | } else { | 1071 | } else { |
| 1067 | addend += 4; | 1072 | addend += 4; |
| 1068 | } | 1073 | } |
| ... | @@ -1143,10 +1148,10 @@ fn format2( | ... | @@ -1143,10 +1148,10 @@ fn format2( |
| 1143 | _ = unused_fmt_string; | 1148 | _ = unused_fmt_string; |
| 1144 | const atom = ctx.atom; | 1149 | const atom = ctx.atom; |
| 1145 | const macho_file = ctx.macho_file; | 1150 | const macho_file = ctx.macho_file; |
| 1146 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : thunk({d})", .{ | 1151 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ |
| 1147 | atom.atom_index, atom.getName(macho_file), atom.value, | 1152 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), |
| 1148 | atom.out_n_sect, atom.alignment, atom.size, | 1153 | atom.out_n_sect, atom.alignment, atom.size, |
| 1149 | atom.thunk_index, | 1154 | atom.getRelocs(macho_file).len, atom.thunk_index, |
| 1150 | }); | 1155 | }); |
| 1151 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); | 1156 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); |
| 1152 | if (atom.unwind_records.len > 0) { | 1157 | if (atom.unwind_records.len > 0) { |
src/link/MachO/Relocation.zig+1-1| ... | @@ -22,7 +22,7 @@ pub fn getTargetAtom(rel: Relocation, macho_file: *MachO) *Atom { | ... | @@ -22,7 +22,7 @@ pub fn getTargetAtom(rel: Relocation, macho_file: *MachO) *Atom { |
| 22 | 22 | ||
| 23 | pub fn getTargetAddress(rel: Relocation, macho_file: *MachO) u64 { | 23 | pub fn getTargetAddress(rel: Relocation, macho_file: *MachO) u64 { |
| 24 | return switch (rel.tag) { | 24 | return switch (rel.tag) { |
| 25 | .local => rel.getTargetAtom(macho_file).value, | 25 | .local => rel.getTargetAtom(macho_file).getAddress(macho_file), |
| 26 | .@"extern" => rel.getTargetSymbol(macho_file).getAddress(.{}, macho_file), | 26 | .@"extern" => rel.getTargetSymbol(macho_file).getAddress(.{}, macho_file), |
| 27 | }; | 27 | }; |
| 28 | } | 28 | } |
src/link/MachO/Symbol.zig+2-2| ... | @@ -118,7 +118,7 @@ pub fn getAddress(symbol: Symbol, opts: struct { | ... | @@ -118,7 +118,7 @@ pub fn getAddress(symbol: Symbol, opts: struct { |
| 118 | return symbol.getObjcStubsAddress(macho_file); | 118 | return symbol.getObjcStubsAddress(macho_file); |
| 119 | } | 119 | } |
| 120 | } | 120 | } |
| 121 | if (symbol.getAtom(macho_file)) |atom| return atom.value + symbol.value; | 121 | if (symbol.getAtom(macho_file)) |atom| return atom.getAddress(macho_file) + symbol.value; |
| 122 | return symbol.value; | 122 | return symbol.value; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| ... | @@ -145,7 +145,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { | ... | @@ -145,7 +145,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 145 | const extra = symbol.getExtra(macho_file).?; | 145 | const extra = symbol.getExtra(macho_file).?; |
| 146 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | 146 | const atom = macho_file.getAtom(extra.objc_selrefs).?; |
| 147 | assert(atom.flags.alive); | 147 | assert(atom.flags.alive); |
| 148 | return atom.value; | 148 | return atom.getAddress(macho_file); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { | 151 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { |
src/link/MachO/UnwindInfo.zig+2-2| ... | @@ -490,12 +490,12 @@ pub const Record = struct { | ... | @@ -490,12 +490,12 @@ pub const Record = struct { |
| 490 | 490 | ||
| 491 | pub fn getAtomAddress(rec: Record, macho_file: *MachO) u64 { | 491 | pub fn getAtomAddress(rec: Record, macho_file: *MachO) u64 { |
| 492 | const atom = rec.getAtom(macho_file); | 492 | const atom = rec.getAtom(macho_file); |
| 493 | return atom.value + rec.atom_offset; | 493 | return atom.getAddress(macho_file) + rec.atom_offset; |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | pub fn getLsdaAddress(rec: Record, macho_file: *MachO) u64 { | 496 | pub fn getLsdaAddress(rec: Record, macho_file: *MachO) u64 { |
| 497 | const lsda = rec.getLsdaAtom(macho_file) orelse return 0; | 497 | const lsda = rec.getLsdaAtom(macho_file) orelse return 0; |
| 498 | return lsda.value + rec.lsda_offset; | 498 | return lsda.getAddress(macho_file) + rec.lsda_offset; |
| 499 | } | 499 | } |
| 500 | 500 | ||
| 501 | pub fn format( | 501 | pub fn format( |
src/link/MachO/ZigObject.zig+7-5| ... | @@ -154,7 +154,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 | ... | @@ -154,7 +154,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 154 | @memset(buffer, 0); | 154 | @memset(buffer, 0); |
| 155 | }, | 155 | }, |
| 156 | else => { | 156 | else => { |
| 157 | const file_offset = sect.offset + atom.value - sect.addr; | 157 | const file_offset = sect.offset + atom.value; |
| 158 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); | 158 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); |
| 159 | if (amt != buffer.len) return error.InputOutput; | 159 | if (amt != buffer.len) return error.InputOutput; |
| 160 | }, | 160 | }, |
| ... | @@ -196,8 +196,10 @@ pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void { | ... | @@ -196,8 +196,10 @@ pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void { |
| 196 | const atom = macho_file.getAtom(atom_index).?; | 196 | const atom = macho_file.getAtom(atom_index).?; |
| 197 | break :blk nlist.n_value - atom.getInputAddress(macho_file); | 197 | break :blk nlist.n_value - atom.getInputAddress(macho_file); |
| 198 | } else nlist.n_value; | 198 | } else nlist.n_value; |
| 199 | const out_n_sect = if (nlist.sect()) macho_file.getAtom(atom_index).?.out_n_sect else 0; | ||
| 199 | symbol.value = value; | 200 | symbol.value = value; |
| 200 | symbol.atom = atom_index; | 201 | symbol.atom = atom_index; |
| 202 | symbol.out_n_sect = out_n_sect; | ||
| 201 | symbol.nlist_idx = nlist_idx; | 203 | symbol.nlist_idx = nlist_idx; |
| 202 | symbol.file = self.index; | 204 | symbol.file = self.index; |
| 203 | symbol.flags.weak = nlist.weakDef(); | 205 | symbol.flags.weak = nlist.weakDef(); |
| ... | @@ -715,7 +717,7 @@ fn updateDeclCode( | ... | @@ -715,7 +717,7 @@ fn updateDeclCode( |
| 715 | } else if (code.len < old_size) { | 717 | } else if (code.len < old_size) { |
| 716 | atom.shrink(macho_file); | 718 | atom.shrink(macho_file); |
| 717 | } else if (macho_file.getAtom(atom.next_index) == null) { | 719 | } else if (macho_file.getAtom(atom.next_index) == null) { |
| 718 | const needed_size = atom.value + code.len - sect.addr; | 720 | const needed_size = atom.value + code.len; |
| 719 | sect.size = needed_size; | 721 | sect.size = needed_size; |
| 720 | } | 722 | } |
| 721 | } else { | 723 | } else { |
| ... | @@ -733,7 +735,7 @@ fn updateDeclCode( | ... | @@ -733,7 +735,7 @@ fn updateDeclCode( |
| 733 | } | 735 | } |
| 734 | 736 | ||
| 735 | if (!sect.isZerofill()) { | 737 | if (!sect.isZerofill()) { |
| 736 | const file_offset = sect.offset + atom.value - sect.addr; | 738 | const file_offset = sect.offset + atom.value; |
| 737 | try macho_file.base.file.?.pwriteAll(code, file_offset); | 739 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 738 | } | 740 | } |
| 739 | } | 741 | } |
| ... | @@ -1036,7 +1038,7 @@ fn lowerConst( | ... | @@ -1036,7 +1038,7 @@ fn lowerConst( |
| 1036 | nlist.n_value = 0; | 1038 | nlist.n_value = 0; |
| 1037 | 1039 | ||
| 1038 | const sect = macho_file.sections.items(.header)[output_section_index]; | 1040 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1039 | const file_offset = sect.offset + atom.value - sect.addr; | 1041 | const file_offset = sect.offset + atom.value; |
| 1040 | try macho_file.base.file.?.pwriteAll(code, file_offset); | 1042 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 1041 | 1043 | ||
| 1042 | return .{ .ok = sym_index }; | 1044 | return .{ .ok = sym_index }; |
| ... | @@ -1213,7 +1215,7 @@ fn updateLazySymbol( | ... | @@ -1213,7 +1215,7 @@ fn updateLazySymbol( |
| 1213 | } | 1215 | } |
| 1214 | 1216 | ||
| 1215 | const sect = macho_file.sections.items(.header)[output_section_index]; | 1217 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1216 | const file_offset = sect.offset + atom.value - sect.addr; | 1218 | const file_offset = sect.offset + atom.value; |
| 1217 | try macho_file.base.file.?.pwriteAll(code, file_offset); | 1219 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 1218 | } | 1220 | } |
| 1219 | 1221 |
src/link/MachO/eh_frame.zig+4-4| ... | @@ -416,7 +416,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { | ... | @@ -416,7 +416,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { |
| 416 | { | 416 | { |
| 417 | const offset = fde.out_offset + 8; | 417 | const offset = fde.out_offset + 8; |
| 418 | const saddr = sect.addr + offset; | 418 | const saddr = sect.addr + offset; |
| 419 | const taddr = fde.getAtom(macho_file).value; | 419 | const taddr = fde.getAtom(macho_file).getAddress(macho_file); |
| 420 | std.mem.writeInt( | 420 | std.mem.writeInt( |
| 421 | i64, | 421 | i64, |
| 422 | buffer[offset..][0..8], | 422 | buffer[offset..][0..8], |
| ... | @@ -428,7 +428,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { | ... | @@ -428,7 +428,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { |
| 428 | if (fde.getLsdaAtom(macho_file)) |atom| { | 428 | if (fde.getLsdaAtom(macho_file)) |atom| { |
| 429 | const offset = fde.out_offset + fde.lsda_ptr_offset; | 429 | const offset = fde.out_offset + fde.lsda_ptr_offset; |
| 430 | const saddr = sect.addr + offset; | 430 | const saddr = sect.addr + offset; |
| 431 | const taddr = atom.value + fde.lsda_offset; | 431 | const taddr = atom.getAddress(macho_file) + fde.lsda_offset; |
| 432 | switch (fde.getCie(macho_file).lsda_size.?) { | 432 | switch (fde.getCie(macho_file).lsda_size.?) { |
| 433 | .p32 => std.mem.writeInt( | 433 | .p32 => std.mem.writeInt( |
| 434 | i32, | 434 | i32, |
| ... | @@ -501,7 +501,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. | ... | @@ -501,7 +501,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 501 | { | 501 | { |
| 502 | const offset = fde.out_offset + 8; | 502 | const offset = fde.out_offset + 8; |
| 503 | const saddr = sect.addr + offset; | 503 | const saddr = sect.addr + offset; |
| 504 | const taddr = fde.getAtom(macho_file).value; | 504 | const taddr = fde.getAtom(macho_file).getAddress(macho_file); |
| 505 | std.mem.writeInt( | 505 | std.mem.writeInt( |
| 506 | i64, | 506 | i64, |
| 507 | code[offset..][0..8], | 507 | code[offset..][0..8], |
| ... | @@ -513,7 +513,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. | ... | @@ -513,7 +513,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 513 | if (fde.getLsdaAtom(macho_file)) |atom| { | 513 | if (fde.getLsdaAtom(macho_file)) |atom| { |
| 514 | const offset = fde.out_offset + fde.lsda_ptr_offset; | 514 | const offset = fde.out_offset + fde.lsda_ptr_offset; |
| 515 | const saddr = sect.addr + offset; | 515 | const saddr = sect.addr + offset; |
| 516 | const taddr = atom.value + fde.lsda_offset; | 516 | const taddr = atom.getAddress(macho_file) + fde.lsda_offset; |
| 517 | switch (fde.getCie(macho_file).lsda_size.?) { | 517 | switch (fde.getCie(macho_file).lsda_size.?) { |
| 518 | .p32 => std.mem.writeInt( | 518 | .p32 => std.mem.writeInt( |
| 519 | i32, | 519 | i32, |
src/link/MachO/relocatable.zig+153-60| ... | @@ -12,7 +12,7 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u | ... | @@ -12,7 +12,7 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u |
| 12 | 12 | ||
| 13 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | 13 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 14 | 14 | ||
| 15 | if (positionals.items.len == 1) { | 15 | if (macho_file.getZigObject() == null and positionals.items.len == 1) { |
| 16 | // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all | 16 | // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all |
| 17 | // debug info segments/sections (this is apparently by design by Apple), we copy | 17 | // debug info segments/sections (this is apparently by design by Apple), we copy |
| 18 | // the *only* input file over. | 18 | // the *only* input file over. |
| ... | @@ -46,50 +46,23 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u | ... | @@ -46,50 +46,23 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u |
| 46 | 46 | ||
| 47 | try macho_file.addUndefinedGlobals(); | 47 | try macho_file.addUndefinedGlobals(); |
| 48 | try macho_file.resolveSymbols(); | 48 | try macho_file.resolveSymbols(); |
| 49 | markExports(macho_file); | 49 | try markExports(macho_file); |
| 50 | claimUnresolved(macho_file); | 50 | try claimUnresolved(macho_file); |
| 51 | try initOutputSections(macho_file); | 51 | try initOutputSections(macho_file); |
| 52 | try macho_file.sortSections(); | 52 | try macho_file.sortSections(); |
| 53 | try macho_file.addAtomsToSections(); | 53 | try macho_file.addAtomsToSections(); |
| 54 | try calcSectionSizes(macho_file); | 54 | try calcSectionSizes(macho_file); |
| 55 | 55 | ||
| 56 | { | 56 | try createSegment(macho_file); |
| 57 | // For relocatable, we only ever need a single segment so create it now. | 57 | try allocateSections(macho_file); |
| 58 | const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC; | 58 | allocateSegment(macho_file); |
| 59 | try macho_file.segments.append(gpa, .{ | ||
| 60 | .cmdsize = @sizeOf(macho.segment_command_64), | ||
| 61 | .segname = MachO.makeStaticString(""), | ||
| 62 | .maxprot = prot, | ||
| 63 | .initprot = prot, | ||
| 64 | }); | ||
| 65 | const seg = &macho_file.segments.items[0]; | ||
| 66 | seg.nsects = @intCast(macho_file.sections.items(.header).len); | ||
| 67 | seg.cmdsize += seg.nsects * @sizeOf(macho.section_64); | ||
| 68 | } | ||
| 69 | |||
| 70 | var off = try allocateSections(macho_file); | ||
| 71 | 59 | ||
| 72 | { | 60 | var off = off: { |
| 73 | // Allocate the single segment. | 61 | const seg = macho_file.segments.items[0]; |
| 74 | assert(macho_file.segments.items.len == 1); | 62 | const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow; |
| 75 | const seg = &macho_file.segments.items[0]; | 63 | break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info)); |
| 76 | var vmaddr: u64 = 0; | 64 | }; |
| 77 | var fileoff: u64 = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); | 65 | off = allocateSectionsRelocs(macho_file, off); |
| 78 | seg.vmaddr = vmaddr; | ||
| 79 | seg.fileoff = fileoff; | ||
| 80 | |||
| 81 | for (macho_file.sections.items(.header)) |header| { | ||
| 82 | vmaddr = header.addr + header.size; | ||
| 83 | if (!header.isZerofill()) { | ||
| 84 | fileoff = header.offset + header.size; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | seg.vmsize = vmaddr - seg.vmaddr; | ||
| 89 | seg.filesize = fileoff - seg.fileoff; | ||
| 90 | } | ||
| 91 | |||
| 92 | macho_file.allocateAtoms(); | ||
| 93 | 66 | ||
| 94 | state_log.debug("{}", .{macho_file.dumpState()}); | 67 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 95 | 68 | ||
| ... | @@ -109,8 +82,13 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u | ... | @@ -109,8 +82,13 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u |
| 109 | try writeHeader(macho_file, ncmds, sizeofcmds); | 82 | try writeHeader(macho_file, ncmds, sizeofcmds); |
| 110 | } | 83 | } |
| 111 | 84 | ||
| 112 | fn markExports(macho_file: *MachO) void { | 85 | fn markExports(macho_file: *MachO) error{OutOfMemory}!void { |
| 113 | for (macho_file.objects.items) |index| { | 86 | var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1); |
| 87 | defer objects.deinit(); | ||
| 88 | if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index); | ||
| 89 | objects.appendSliceAssumeCapacity(macho_file.objects.items); | ||
| 90 | |||
| 91 | for (objects.items) |index| { | ||
| 114 | for (macho_file.getFile(index).?.getSymbols()) |sym_index| { | 92 | for (macho_file.getFile(index).?.getSymbols()) |sym_index| { |
| 115 | const sym = macho_file.getSymbol(sym_index); | 93 | const sym = macho_file.getSymbol(sym_index); |
| 116 | const file = sym.getFile(macho_file) orelse continue; | 94 | const file = sym.getFile(macho_file) orelse continue; |
| ... | @@ -122,13 +100,22 @@ fn markExports(macho_file: *MachO) void { | ... | @@ -122,13 +100,22 @@ fn markExports(macho_file: *MachO) void { |
| 122 | } | 100 | } |
| 123 | } | 101 | } |
| 124 | 102 | ||
| 125 | fn claimUnresolved(macho_file: *MachO) void { | 103 | fn claimUnresolved(macho_file: *MachO) error{OutOfMemory}!void { |
| 126 | for (macho_file.objects.items) |index| { | 104 | var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1); |
| 127 | const object = macho_file.getFile(index).?.object; | 105 | defer objects.deinit(); |
| 106 | if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index); | ||
| 107 | objects.appendSliceAssumeCapacity(macho_file.objects.items); | ||
| 108 | |||
| 109 | for (objects.items) |index| { | ||
| 110 | const file = macho_file.getFile(index).?; | ||
| 128 | 111 | ||
| 129 | for (object.symbols.items, 0..) |sym_index, i| { | 112 | for (file.getSymbols(), 0..) |sym_index, i| { |
| 130 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | 113 | const nlist_idx = @as(Symbol.Index, @intCast(i)); |
| 131 | const nlist = object.symtab.items(.nlist)[nlist_idx]; | 114 | const nlist = switch (file) { |
| 115 | .object => |x| x.symtab.items(.nlist)[nlist_idx], | ||
| 116 | .zig_object => |x| x.symtab.items(.nlist)[nlist_idx], | ||
| 117 | else => unreachable, | ||
| 118 | }; | ||
| 132 | if (!nlist.ext()) continue; | 119 | if (!nlist.ext()) continue; |
| 133 | if (!nlist.undf()) continue; | 120 | if (!nlist.undf()) continue; |
| 134 | 121 | ||
| ... | @@ -203,6 +190,16 @@ fn calcSectionSizes(macho_file: *MachO) !void { | ... | @@ -203,6 +190,16 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 203 | sect.@"align" = 3; | 190 | sect.@"align" = 3; |
| 204 | sect.nreloc = eh_frame.calcNumRelocs(macho_file); | 191 | sect.nreloc = eh_frame.calcNumRelocs(macho_file); |
| 205 | } | 192 | } |
| 193 | |||
| 194 | if (macho_file.getZigObject()) |zo| { | ||
| 195 | for (zo.atoms.items) |atom_index| { | ||
| 196 | const atom = macho_file.getAtom(atom_index) orelse continue; | ||
| 197 | if (!atom.flags.alive) continue; | ||
| 198 | const header = &macho_file.sections.items(.header)[atom.out_n_sect]; | ||
| 199 | if (!macho_file.isZigSection(atom.out_n_sect)) continue; | ||
| 200 | header.nreloc += atom.calcNumRelocs(macho_file); | ||
| 201 | } | ||
| 202 | } | ||
| 206 | } | 203 | } |
| 207 | 204 | ||
| 208 | fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { | 205 | fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { |
| ... | @@ -231,30 +228,66 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { | ... | @@ -231,30 +228,66 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { |
| 231 | sect.@"align" = 3; | 228 | sect.@"align" = 3; |
| 232 | } | 229 | } |
| 233 | 230 | ||
| 234 | fn allocateSections(macho_file: *MachO) !u32 { | 231 | fn allocateSections(macho_file: *MachO) !void { |
| 235 | var fileoff = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); | ||
| 236 | var vmaddr: u64 = 0; | ||
| 237 | const slice = macho_file.sections.slice(); | 232 | const slice = macho_file.sections.slice(); |
| 238 | 233 | ||
| 239 | for (slice.items(.header)) |*header| { | 234 | const last_index = for (0..slice.items(.header).len) |i| { |
| 235 | if (macho_file.isZigSection(@intCast(i))) break i; | ||
| 236 | } else slice.items(.header).len; | ||
| 237 | |||
| 238 | for (slice.items(.header)[0..last_index]) |*header| { | ||
| 240 | const alignment = try math.powi(u32, 2, header.@"align"); | 239 | const alignment = try math.powi(u32, 2, header.@"align"); |
| 241 | vmaddr = mem.alignForward(u64, vmaddr, alignment); | 240 | if (!header.isZerofill()) { |
| 242 | header.addr = vmaddr; | 241 | header.offset = math.cast(u32, macho_file.findFreeSpace(header.size, alignment)) orelse |
| 243 | vmaddr += header.size; | 242 | return error.Overflow; |
| 243 | } | ||
| 244 | header.addr = macho_file.findFreeSpaceVirtual(header.size, alignment); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | fn createSegment(macho_file: *MachO) !void { | ||
| 249 | const gpa = macho_file.base.comp.gpa; | ||
| 250 | |||
| 251 | // For relocatable, we only ever need a single segment so create it now. | ||
| 252 | const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC; | ||
| 253 | try macho_file.segments.append(gpa, .{ | ||
| 254 | .cmdsize = @sizeOf(macho.segment_command_64), | ||
| 255 | .segname = MachO.makeStaticString(""), | ||
| 256 | .maxprot = prot, | ||
| 257 | .initprot = prot, | ||
| 258 | }); | ||
| 259 | const seg = &macho_file.segments.items[0]; | ||
| 260 | seg.nsects = @intCast(macho_file.sections.items(.header).len); | ||
| 261 | seg.cmdsize += seg.nsects * @sizeOf(macho.section_64); | ||
| 262 | } | ||
| 244 | 263 | ||
| 264 | fn allocateSegment(macho_file: *MachO) void { | ||
| 265 | // Allocate the single segment. | ||
| 266 | const seg = &macho_file.segments.items[0]; | ||
| 267 | var vmaddr: u64 = 0; | ||
| 268 | var fileoff: u64 = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64); | ||
| 269 | seg.vmaddr = vmaddr; | ||
| 270 | seg.fileoff = fileoff; | ||
| 271 | |||
| 272 | for (macho_file.sections.items(.header)) |header| { | ||
| 273 | vmaddr = @max(vmaddr, header.addr + header.size); | ||
| 245 | if (!header.isZerofill()) { | 274 | if (!header.isZerofill()) { |
| 246 | fileoff = mem.alignForward(u32, fileoff, alignment); | 275 | fileoff = @max(fileoff, header.offset + header.size); |
| 247 | header.offset = fileoff; | ||
| 248 | fileoff += @intCast(header.size); | ||
| 249 | } | 276 | } |
| 250 | } | 277 | } |
| 251 | 278 | ||
| 279 | seg.vmsize = vmaddr - seg.vmaddr; | ||
| 280 | seg.filesize = fileoff - seg.fileoff; | ||
| 281 | } | ||
| 282 | |||
| 283 | fn allocateSectionsRelocs(macho_file: *MachO, off: u32) u32 { | ||
| 284 | var fileoff = off; | ||
| 285 | const slice = macho_file.sections.slice(); | ||
| 252 | for (slice.items(.header)) |*header| { | 286 | for (slice.items(.header)) |*header| { |
| 253 | if (header.nreloc == 0) continue; | 287 | if (header.nreloc == 0) continue; |
| 254 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); | 288 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); |
| 255 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); | 289 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); |
| 256 | } | 290 | } |
| 257 | |||
| 258 | return fileoff; | 291 | return fileoff; |
| 259 | } | 292 | } |
| 260 | 293 | ||
| ... | @@ -272,9 +305,10 @@ fn writeAtoms(macho_file: *MachO) !void { | ... | @@ -272,9 +305,10 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 272 | const cpu_arch = macho_file.getTarget().cpu.arch; | 305 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 273 | const slice = macho_file.sections.slice(); | 306 | const slice = macho_file.sections.slice(); |
| 274 | 307 | ||
| 275 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { | 308 | for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| { |
| 276 | if (atoms.items.len == 0) continue; | 309 | if (atoms.items.len == 0) continue; |
| 277 | if (header.isZerofill()) continue; | 310 | if (header.isZerofill()) continue; |
| 311 | if (macho_file.isZigSection(@intCast(i))) continue; | ||
| 278 | 312 | ||
| 279 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 313 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 280 | const code = try gpa.alloc(u8, size); | 314 | const code = try gpa.alloc(u8, size); |
| ... | @@ -288,9 +322,9 @@ fn writeAtoms(macho_file: *MachO) !void { | ... | @@ -288,9 +322,9 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 288 | for (atoms.items) |atom_index| { | 322 | for (atoms.items) |atom_index| { |
| 289 | const atom = macho_file.getAtom(atom_index).?; | 323 | const atom = macho_file.getAtom(atom_index).?; |
| 290 | assert(atom.flags.alive); | 324 | assert(atom.flags.alive); |
| 291 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; | 325 | const off = math.cast(usize, atom.value) orelse return error.Overflow; |
| 292 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | 326 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 293 | try atom.getFile(macho_file).object.getAtomData(atom.*, code[off..][0..atom_size]); | 327 | try atom.getData(macho_file, code[off..][0..atom_size]); |
| 294 | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); | 328 | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); |
| 295 | } | 329 | } |
| 296 | 330 | ||
| ... | @@ -302,6 +336,63 @@ fn writeAtoms(macho_file: *MachO) !void { | ... | @@ -302,6 +336,63 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 302 | try macho_file.base.file.?.pwriteAll(code, header.offset); | 336 | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 303 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | 337 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 304 | } | 338 | } |
| 339 | |||
| 340 | if (macho_file.getZigObject()) |zo| { | ||
| 341 | // TODO: this is ugly; perhaps we should aggregrate before? | ||
| 342 | var relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa); | ||
| 343 | defer { | ||
| 344 | for (relocs.values()) |*list| { | ||
| 345 | list.deinit(); | ||
| 346 | } | ||
| 347 | relocs.deinit(); | ||
| 348 | } | ||
| 349 | |||
| 350 | for (macho_file.sections.items(.header), 0..) |header, n_sect| { | ||
| 351 | if (header.isZerofill()) continue; | ||
| 352 | if (!macho_file.isZigSection(@intCast(n_sect))) continue; | ||
| 353 | const gop = try relocs.getOrPut(@intCast(n_sect)); | ||
| 354 | if (gop.found_existing) continue; | ||
| 355 | gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); | ||
| 356 | } | ||
| 357 | |||
| 358 | for (zo.atoms.items) |atom_index| { | ||
| 359 | const atom = macho_file.getAtom(atom_index) orelse continue; | ||
| 360 | if (!atom.flags.alive) continue; | ||
| 361 | const header = macho_file.sections.items(.header)[atom.out_n_sect]; | ||
| 362 | if (header.isZerofill()) continue; | ||
| 363 | if (!macho_file.isZigSection(atom.out_n_sect)) continue; | ||
| 364 | if (atom.getRelocs(macho_file).len == 0) continue; | ||
| 365 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | ||
| 366 | const code = try gpa.alloc(u8, atom_size); | ||
| 367 | defer gpa.free(code); | ||
| 368 | atom.getData(macho_file, code) catch |err| switch (err) { | ||
| 369 | error.InputOutput => { | ||
| 370 | try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{ | ||
| 371 | atom.getName(macho_file), | ||
| 372 | }); | ||
| 373 | return error.FlushFailure; | ||
| 374 | }, | ||
| 375 | else => |e| { | ||
| 376 | try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{ | ||
| 377 | atom.getName(macho_file), | ||
| 378 | @errorName(e), | ||
| 379 | }); | ||
| 380 | return error.FlushFailure; | ||
| 381 | }, | ||
| 382 | }; | ||
| 383 | const file_offset = header.offset + atom.value; | ||
| 384 | const rels = relocs.getPtr(atom.out_n_sect).?; | ||
| 385 | try atom.writeRelocs(macho_file, code, rels); | ||
| 386 | try macho_file.base.file.?.pwriteAll(code, file_offset); | ||
| 387 | } | ||
| 388 | |||
| 389 | for (relocs.keys(), relocs.values()) |sect_id, rels| { | ||
| 390 | const header = macho_file.sections.items(.header)[sect_id]; | ||
| 391 | assert(rels.items.len == header.nreloc); | ||
| 392 | mem.sort(macho.relocation_info, rels.items, {}, sortReloc); | ||
| 393 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(rels.items), header.reloff); | ||
| 394 | } | ||
| 395 | } | ||
| 305 | } | 396 | } |
| 306 | 397 | ||
| 307 | fn writeCompactUnwind(macho_file: *MachO) !void { | 398 | fn writeCompactUnwind(macho_file: *MachO) !void { |
| ... | @@ -492,6 +583,7 @@ const assert = std.debug.assert; | ... | @@ -492,6 +583,7 @@ const assert = std.debug.assert; |
| 492 | const eh_frame = @import("eh_frame.zig"); | 583 | const eh_frame = @import("eh_frame.zig"); |
| 493 | const link = @import("../../link.zig"); | 584 | const link = @import("../../link.zig"); |
| 494 | const load_commands = @import("load_commands.zig"); | 585 | const load_commands = @import("load_commands.zig"); |
| 586 | const log = std.log.scoped(.link); | ||
| 495 | const macho = std.macho; | 587 | const macho = std.macho; |
| 496 | const math = std.math; | 588 | const math = std.math; |
| 497 | const mem = std.mem; | 589 | const mem = std.mem; |
| ... | @@ -501,5 +593,6 @@ const trace = @import("../../tracy.zig").trace; | ... | @@ -501,5 +593,6 @@ const trace = @import("../../tracy.zig").trace; |
| 501 | 593 | ||
| 502 | const Atom = @import("Atom.zig"); | 594 | const Atom = @import("Atom.zig"); |
| 503 | const Compilation = @import("../../Compilation.zig"); | 595 | const Compilation = @import("../../Compilation.zig"); |
| 596 | const File = @import("file.zig").File; | ||
| 504 | const MachO = @import("../MachO.zig"); | 597 | const MachO = @import("../MachO.zig"); |
| 505 | const Symbol = @import("Symbol.zig"); | 598 | const Symbol = @import("Symbol.zig"); |
src/link/MachO/thunks.zig+9-4| ... | @@ -66,7 +66,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | ... | @@ -66,7 +66,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 66 | if (atom.out_n_sect != target.out_n_sect) return false; | 66 | if (atom.out_n_sect != target.out_n_sect) return false; |
| 67 | const target_atom = target.getAtom(macho_file).?; | 67 | const target_atom = target.getAtom(macho_file).?; |
| 68 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | 68 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; |
| 69 | const saddr = @as(i64, @intCast(atom.value)) + @as(i64, @intCast(rel.offset - atom.off)); | 69 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); |
| 70 | const taddr: i64 = @intCast(rel.getTargetAddress(macho_file)); | 70 | const taddr: i64 = @intCast(rel.getTargetAddress(macho_file)); |
| 71 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; | 71 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; |
| 72 | return true; | 72 | return true; |
| ... | @@ -85,14 +85,19 @@ pub const Thunk = struct { | ... | @@ -85,14 +85,19 @@ pub const Thunk = struct { |
| 85 | return thunk.symbols.keys().len * trampoline_size; | 85 | return thunk.symbols.keys().len * trampoline_size; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | pub fn getAddress(thunk: Thunk, sym_index: Symbol.Index) u64 { | 88 | pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 { |
| 89 | return thunk.value + thunk.symbols.getIndex(sym_index).? * trampoline_size; | 89 | const header = macho_file.sections.items(.header)[thunk.out_n_sect]; |
| 90 | return header.addr + thunk.value; | ||
| 91 | } | ||
| 92 | |||
| 93 | pub fn getTargetAddress(thunk: Thunk, sym_index: Symbol.Index, macho_file: *MachO) u64 { | ||
| 94 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(sym_index).? * trampoline_size; | ||
| 90 | } | 95 | } |
| 91 | 96 | ||
| 92 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { | 97 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { |
| 93 | for (thunk.symbols.keys(), 0..) |sym_index, i| { | 98 | for (thunk.symbols.keys(), 0..) |sym_index, i| { |
| 94 | const sym = macho_file.getSymbol(sym_index); | 99 | const sym = macho_file.getSymbol(sym_index); |
| 95 | const saddr = thunk.value + i * trampoline_size; | 100 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 96 | const taddr = sym.getAddress(.{}, macho_file); | 101 | const taddr = sym.getAddress(.{}, macho_file); |
| 97 | const pages = try Relocation.calcNumberOfPages(saddr, taddr); | 102 | const pages = try Relocation.calcNumberOfPages(saddr, taddr); |
| 98 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | 103 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); |
test/link/link.zig+12-3| ... | @@ -27,14 +27,23 @@ pub const Options = struct { | ... | @@ -27,14 +27,23 @@ pub const Options = struct { |
| 27 | optimize: std.builtin.OptimizeMode = .Debug, | 27 | optimize: std.builtin.OptimizeMode = .Debug, |
| 28 | use_llvm: bool = true, | 28 | use_llvm: bool = true, |
| 29 | use_lld: bool = false, | 29 | use_lld: bool = false, |
| 30 | strip: ?bool = null, | ||
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| 32 | pub fn addTestStep(b: *Build, prefix: []const u8, opts: Options) *Step { | 33 | pub fn addTestStep(b: *Build, prefix: []const u8, opts: Options) *Step { |
| 33 | const target = opts.target.result.zigTriple(b.allocator) catch @panic("OOM"); | 34 | const target = opts.target.result.zigTriple(b.allocator) catch @panic("OOM"); |
| 34 | const optimize = @tagName(opts.optimize); | 35 | const optimize = @tagName(opts.optimize); |
| 35 | const use_llvm = if (opts.use_llvm) "llvm" else "no-llvm"; | 36 | const use_llvm = if (opts.use_llvm) "llvm" else "no-llvm"; |
| 36 | const name = std.fmt.allocPrint(b.allocator, "test-{s}-{s}-{s}-{s}", .{ | 37 | const use_lld = if (opts.use_lld) "lld" else "no-lld"; |
| 37 | prefix, target, optimize, use_llvm, | 38 | if (opts.strip) |strip| { |
| 39 | const s = if (strip) "strip" else "no-strip"; | ||
| 40 | const name = std.fmt.allocPrint(b.allocator, "test-{s}-{s}-{s}-{s}-{s}-{s}", .{ | ||
| 41 | prefix, target, optimize, use_llvm, use_lld, s, | ||
| 42 | }) catch @panic("OOM"); | ||
| 43 | return b.step(name, ""); | ||
| 44 | } | ||
| 45 | const name = std.fmt.allocPrint(b.allocator, "test-{s}-{s}-{s}-{s}-{s}", .{ | ||
| 46 | prefix, target, optimize, use_llvm, use_lld, | ||
| 38 | }) catch @panic("OOM"); | 47 | }) catch @panic("OOM"); |
| 39 | return b.step(name, ""); | 48 | return b.step(name, ""); |
| 40 | } | 49 | } |
| ... | @@ -87,7 +96,7 @@ fn addCompileStep( | ... | @@ -87,7 +96,7 @@ fn addCompileStep( |
| 87 | break :rsf b.addWriteFiles().add("a.zig", bytes); | 96 | break :rsf b.addWriteFiles().add("a.zig", bytes); |
| 88 | }, | 97 | }, |
| 89 | .pic = overlay.pic, | 98 | .pic = overlay.pic, |
| 90 | .strip = overlay.strip, | 99 | .strip = if (base.strip) |s| s else overlay.strip, |
| 91 | }, | 100 | }, |
| 92 | .use_llvm = base.use_llvm, | 101 | .use_llvm = base.use_llvm, |
| 93 | .use_lld = base.use_lld, | 102 | .use_lld = base.use_lld, |
test/link/macho.zig+14-1| ... | @@ -15,6 +15,11 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -15,6 +15,11 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 15 | .os_tag = .macos, | 15 | .os_tag = .macos, |
| 16 | }); | 16 | }); |
| 17 | 17 | ||
| 18 | // Exercise linker with self-hosted backend (no LLVM) | ||
| 19 | macho_step.dependOn(testHelloZig(b, .{ .use_llvm = false, .target = x86_64_target })); | ||
| 20 | macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .strip = true, .target = x86_64_target })); | ||
| 21 | |||
| 22 | // Exercise linker with LLVM backend | ||
| 18 | macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); | 23 | macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); |
| 19 | macho_step.dependOn(testEmptyObject(b, .{ .target = default_target })); | 24 | macho_step.dependOn(testEmptyObject(b, .{ .target = default_target })); |
| 20 | macho_step.dependOn(testEmptyZig(b, .{ .target = default_target })); | 25 | macho_step.dependOn(testEmptyZig(b, .{ .target = default_target })); |
| ... | @@ -1234,7 +1239,14 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step { | ... | @@ -1234,7 +1239,14 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step { |
| 1234 | const run = addRunArtifact(exe); | 1239 | const run = addRunArtifact(exe); |
| 1235 | run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") }); | 1240 | run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") }); |
| 1236 | run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") }); | 1241 | run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") }); |
| 1237 | run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") }); | 1242 | if (opts.use_llvm) { |
| 1243 | // TODO: enable this once self-hosted can print panics and stack traces | ||
| 1244 | run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") }); | ||
| 1245 | } | ||
| 1246 | if (builtin.os.tag == .macos) { | ||
| 1247 | const signal: u32 = if (opts.use_llvm) std.os.darwin.SIG.ABRT else std.os.darwin.SIG.TRAP; | ||
| 1248 | run.addCheck(.{ .expect_term = .{ .Signal = signal } }); | ||
| 1249 | } | ||
| 1238 | test_step.dependOn(&run.step); | 1250 | test_step.dependOn(&run.step); |
| 1239 | 1251 | ||
| 1240 | return test_step; | 1252 | return test_step; |
| ... | @@ -2307,6 +2319,7 @@ fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step { | ... | @@ -2307,6 +2319,7 @@ fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step { |
| 2307 | return link.addTestStep(b, "macho-" ++ prefix, opts); | 2319 | return link.addTestStep(b, "macho-" ++ prefix, opts); |
| 2308 | } | 2320 | } |
| 2309 | 2321 | ||
| 2322 | const builtin = @import("builtin"); | ||
| 2310 | const addAsmSourceBytes = link.addAsmSourceBytes; | 2323 | const addAsmSourceBytes = link.addAsmSourceBytes; |
| 2311 | const addCSourceBytes = link.addCSourceBytes; | 2324 | const addCSourceBytes = link.addCSourceBytes; |
| 2312 | const addRunArtifact = link.addRunArtifact; | 2325 | const addRunArtifact = link.addRunArtifact; |