| author | |
| committer | |
| log | 9fc1685c1caa4c1d093fa8936a5602f54121dd50 |
| tree | 95aa99d2c97d48bc0f2715ec1d05ee64b99539f2 |
| parent | e10a2018a7b6a51243589ec95842d2cef2da45ac |
5 files changed, 69 insertions(+), 54 deletions(-)
src/link/MachO.zig+37-29| ... | ... | @@ -636,7 +636,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 636 | 636 | return error.FlushFailure; |
| 637 | 637 | }, |
| 638 | 638 | }; |
| 639 | const file_offset = sect.offset + atom.value - sect.addr; | |
| 639 | const file_offset = sect.offset + atom.value; | |
| 640 | 640 | atom.resolveRelocs(self, code) catch |err| switch (err) { |
| 641 | 641 | error.ResolveFailed => has_resolve_error = true, |
| 642 | 642 | else => |e| { |
| ... | ... | @@ -2393,16 +2393,7 @@ fn allocateSegments(self: *MachO) void { |
| 2393 | 2393 | } |
| 2394 | 2394 | |
| 2395 | 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 | ||
| 2396 | // TODO: redo this like atoms | |
| 2406 | 2397 | for (self.thunks.items) |*thunk| { |
| 2407 | 2398 | const header = self.sections.items(.header)[thunk.out_n_sect]; |
| 2408 | 2399 | thunk.value += header.addr; |
| ... | ... | @@ -2603,7 +2594,7 @@ fn writeAtoms(self: *MachO) !void { |
| 2603 | 2594 | for (atoms.items) |atom_index| { |
| 2604 | 2595 | const atom = self.getAtom(atom_index).?; |
| 2605 | 2596 | assert(atom.flags.alive); |
| 2606 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; | |
| 2597 | const off = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 2607 | 2598 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 2608 | 2599 | try atom.getData(self, buffer[off..][0..atom_size]); |
| 2609 | 2600 | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { |
| ... | ... | @@ -2825,7 +2816,7 @@ pub fn writeDataInCode(self: *MachO, base_address: u64, off: u32) !u32 { |
| 2825 | 2816 | |
| 2826 | 2817 | if (atom.flags.alive) for (in_dices[start_dice..next_dice]) |dice| { |
| 2827 | 2818 | dices.appendAssumeCapacity(.{ |
| 2828 | .offset = @intCast(atom.value + dice.offset - start_off - base_address), | |
| 2819 | .offset = @intCast(atom.getAddress(self) + dice.offset - start_off - base_address), | |
| 2829 | 2820 | .length = dice.length, |
| 2830 | 2821 | .kind = dice.kind, |
| 2831 | 2822 | }); |
| ... | ... | @@ -3318,7 +3309,7 @@ fn allocatedSize(self: *MachO, start: u64) u64 { |
| 3318 | 3309 | return min_pos - start; |
| 3319 | 3310 | } |
| 3320 | 3311 | |
| 3321 | fn allocatedVirtualSize(self: *MachO, start: u64) u64 { | |
| 3312 | fn allocatedSizeVirtual(self: *MachO, start: u64) u64 { | |
| 3322 | 3313 | if (start == 0) return 0; |
| 3323 | 3314 | var min_pos: u64 = std.math.maxInt(u64); |
| 3324 | 3315 | for (self.segments.items) |seg| { |
| ... | ... | @@ -3518,22 +3509,39 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3518 | 3509 | sect.size = 0; |
| 3519 | 3510 | |
| 3520 | 3511 | // Must move the entire section. |
| 3521 | const alignment = if (self.base.isRelocatable()) | |
| 3522 | try math.powi(u32, 2, sect.@"align") | |
| 3523 | else | |
| 3524 | self.getPageSize(); | |
| 3525 | const new_offset = self.findFreeSpace(needed_size, alignment); | |
| 3526 | ||
| 3527 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ | |
| 3528 | sect.segName(), | |
| 3529 | sect.sectName(), | |
| 3530 | new_offset, | |
| 3531 | new_offset + existing_size, | |
| 3532 | }); | |
| 3512 | if (self.base.isRelocatable()) { | |
| 3513 | const alignment = try math.powi(u32, 2, sect.@"align"); | |
| 3514 | const new_offset = self.findFreeSpace(needed_size, alignment); | |
| 3515 | const new_addr = self.findFreeSpaceVirtual(needed_size, alignment); | |
| 3533 | 3516 | |
| 3534 | try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); | |
| 3517 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ | |
| 3518 | sect.segName(), | |
| 3519 | sect.sectName(), | |
| 3520 | new_offset, | |
| 3521 | new_offset + existing_size, | |
| 3522 | new_addr, | |
| 3523 | new_addr + existing_size, | |
| 3524 | }); | |
| 3525 | ||
| 3526 | try self.copyRangeAll(sect.offset, new_offset, existing_size); | |
| 3535 | 3527 | |
| 3536 | sect.offset = @intCast(new_offset); | |
| 3528 | sect.offset = @intCast(new_offset); | |
| 3529 | sect.addr = new_addr; | |
| 3530 | } else { | |
| 3531 | const alignment = self.getPageSize(); | |
| 3532 | const new_offset = self.findFreeSpace(needed_size, alignment); | |
| 3533 | ||
| 3534 | log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ | |
| 3535 | sect.segName(), | |
| 3536 | sect.sectName(), | |
| 3537 | new_offset, | |
| 3538 | new_offset + existing_size, | |
| 3539 | }); | |
| 3540 | ||
| 3541 | try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); | |
| 3542 | ||
| 3543 | sect.offset = @intCast(new_offset); | |
| 3544 | } | |
| 3537 | 3545 | } |
| 3538 | 3546 | |
| 3539 | 3547 | sect.size = needed_size; |
| ... | ... | @@ -3547,7 +3555,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3547 | 3555 | seg.filesize = needed_size; |
| 3548 | 3556 | } |
| 3549 | 3557 | |
| 3550 | const mem_capacity = self.allocatedVirtualSize(seg.vmaddr); | |
| 3558 | const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr); | |
| 3551 | 3559 | if (needed_size > mem_capacity) { |
| 3552 | 3560 | var err = try self.addErrorWithNotes(2); |
| 3553 | 3561 | try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{ |
src/link/MachO/Atom.zig+23-16| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | /// Address allocated for this Atom. | |
| 1 | /// Address offset allocated for this Atom wrt to its section start address. | |
| 2 | 2 | value: u64 = 0, |
| 3 | 3 | |
| 4 | 4 | /// Name of this Atom. |
| ... | ... | @@ -84,6 +84,11 @@ pub fn getInputAddress(self: Atom, macho_file: *MachO) u64 { |
| 84 | 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 | 92 | pub fn getPriority(self: Atom, macho_file: *MachO) u64 { |
| 88 | 93 | const file = self.getFile(macho_file); |
| 89 | 94 | return (@as(u64, @intCast(file.getIndex())) << 32) | @as(u64, @intCast(self.n_sect)); |
| ... | ... | @@ -189,14 +194,17 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 189 | 194 | /// File offset relocation happens transparently, so it is not included in |
| 190 | 195 | /// this calculation. |
| 191 | 196 | 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); | |
| 193 | return next_value - self.value; | |
| 197 | const next_addr = if (macho_file.getAtom(self.next_index)) |next| | |
| 198 | next.getAddress(macho_file) | |
| 199 | else | |
| 200 | std.math.maxInt(u32); | |
| 201 | return next_addr - self.getAddress(macho_file); | |
| 194 | 202 | } |
| 195 | 203 | |
| 196 | 204 | pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { |
| 197 | 205 | // No need to keep a free list node for the last block. |
| 198 | 206 | const next = macho_file.getAtom(self.next_index) orelse return false; |
| 199 | const cap = next.value - self.value; | |
| 207 | const cap = next.getAddress(macho_file) - self.getAddress(macho_file); | |
| 200 | 208 | const ideal_cap = MachO.padToIdeal(self.size); |
| 201 | 209 | if (cap <= ideal_cap) return false; |
| 202 | 210 | const surplus = cap - ideal_cap; |
| ... | ... | @@ -263,15 +271,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 263 | 271 | atom_placement = last.atom_index; |
| 264 | 272 | break :blk new_start_vaddr; |
| 265 | 273 | } else { |
| 266 | break :blk sect.addr; | |
| 274 | break :blk 0; | |
| 267 | 275 | } |
| 268 | 276 | }; |
| 269 | 277 | |
| 270 | 278 | log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{ |
| 271 | 279 | self.atom_index, |
| 272 | 280 | self.getName(macho_file), |
| 273 | self.value, | |
| 274 | self.value + self.size, | |
| 281 | self.getAddress(macho_file), | |
| 282 | self.getAddress(macho_file) + self.size, | |
| 275 | 283 | }); |
| 276 | 284 | |
| 277 | 285 | const expand_section = if (atom_placement) |placement_index| |
| ... | ... | @@ -279,7 +287,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 279 | 287 | else |
| 280 | 288 | true; |
| 281 | 289 | if (expand_section) { |
| 282 | const needed_size = (self.value + self.size) - sect.addr; | |
| 290 | const needed_size = self.value + self.size; | |
| 283 | 291 | try macho_file.growSection(self.out_n_sect, needed_size); |
| 284 | 292 | last_atom_index.* = self.atom_index; |
| 285 | 293 | |
| ... | ... | @@ -544,7 +552,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 544 | 552 | const name = self.getName(macho_file); |
| 545 | 553 | const relocs = self.getRelocs(macho_file); |
| 546 | 554 | |
| 547 | relocs_log.debug("{x}: {s}", .{ self.value, name }); | |
| 555 | relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), name }); | |
| 548 | 556 | |
| 549 | 557 | var has_error = false; |
| 550 | 558 | var stream = std.io.fixedBufferStream(buffer); |
| ... | ... | @@ -569,7 +577,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 569 | 577 | try macho_file.reportParseError2( |
| 570 | 578 | file.getIndex(), |
| 571 | 579 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {s}, target {s}", |
| 572 | .{ name, self.value, rel.offset, @tagName(rel.type), target }, | |
| 580 | .{ name, self.getAddress(macho_file), rel.offset, @tagName(rel.type), target }, | |
| 573 | 581 | ); |
| 574 | 582 | has_error = true; |
| 575 | 583 | }, |
| ... | ... | @@ -604,7 +612,7 @@ fn resolveRelocInner( |
| 604 | 612 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; |
| 605 | 613 | const seg_id = macho_file.sections.items(.segment_id)[self.out_n_sect]; |
| 606 | 614 | const seg = macho_file.segments.items[seg_id]; |
| 607 | const P = @as(i64, @intCast(self.value)) + @as(i64, @intCast(rel_offset)); | |
| 615 | const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); | |
| 608 | 616 | const A = rel.addend + rel.getRelocAddend(cpu_arch); |
| 609 | 617 | const S: i64 = @intCast(rel.getTargetAddress(macho_file)); |
| 610 | 618 | const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); |
| ... | ... | @@ -919,7 +927,7 @@ const x86_64 = struct { |
| 919 | 927 | var err = try macho_file.addErrorWithNotes(2); |
| 920 | 928 | try err.addMsg(macho_file, "{s}: 0x{x}: 0x{x}: failed to relax relocation of type {s}", .{ |
| 921 | 929 | self.getName(macho_file), |
| 922 | self.value, | |
| 930 | self.getAddress(macho_file), | |
| 923 | 931 | rel.offset, |
| 924 | 932 | @tagName(rel.type), |
| 925 | 933 | }); |
| ... | ... | @@ -990,12 +998,11 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 990 | 998 | |
| 991 | 999 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 992 | 1000 | const relocs = self.getRelocs(macho_file); |
| 993 | const sect = macho_file.sections.items(.header)[self.out_n_sect]; | |
| 994 | 1001 | var stream = std.io.fixedBufferStream(code); |
| 995 | 1002 | |
| 996 | 1003 | for (relocs) |rel| { |
| 997 | 1004 | 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; | |
| 1005 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; | |
| 999 | 1006 | const r_symbolnum = r_symbolnum: { |
| 1000 | 1007 | const r_symbolnum: u32 = switch (rel.tag) { |
| 1001 | 1008 | .local => rel.getTargetAtom(macho_file).out_n_sect + 1, |
| ... | ... | @@ -1062,7 +1069,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1062 | 1069 | .x86_64 => { |
| 1063 | 1070 | if (rel.meta.pcrel) { |
| 1064 | 1071 | if (rel.tag == .local) { |
| 1065 | addend -= @as(i64, @intCast(self.value + rel_offset)); | |
| 1072 | addend -= @as(i64, @intCast(self.getAddress(macho_file) + rel_offset)); | |
| 1066 | 1073 | } else { |
| 1067 | 1074 | addend += 4; |
| 1068 | 1075 | } |
| ... | ... | @@ -1144,7 +1151,7 @@ fn format2( |
| 1144 | 1151 | const atom = ctx.atom; |
| 1145 | 1152 | const macho_file = ctx.macho_file; |
| 1146 | 1153 | 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, | |
| 1154 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), | |
| 1148 | 1155 | atom.out_n_sect, atom.alignment, atom.size, |
| 1149 | 1156 | atom.getRelocs(macho_file).len, atom.thunk_index, |
| 1150 | 1157 | }); |
src/link/MachO/Symbol.zig+2-2| ... | ... | @@ -118,7 +118,7 @@ pub fn getAddress(symbol: Symbol, opts: struct { |
| 118 | 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 | 122 | return symbol.value; |
| 123 | 123 | } |
| 124 | 124 | |
| ... | ... | @@ -145,7 +145,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 145 | 145 | const extra = symbol.getExtra(macho_file).?; |
| 146 | 146 | const atom = macho_file.getAtom(extra.objc_selrefs).?; |
| 147 | 147 | assert(atom.flags.alive); |
| 148 | return atom.value; | |
| 148 | return atom.getAddress(macho_file); | |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { |
src/link/MachO/ZigObject.zig+5-5| ... | ... | @@ -154,7 +154,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 154 | 154 | @memset(buffer, 0); |
| 155 | 155 | }, |
| 156 | 156 | else => { |
| 157 | const file_offset = sect.offset + atom.value - sect.addr; | |
| 157 | const file_offset = sect.offset + atom.value; | |
| 158 | 158 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); |
| 159 | 159 | if (amt != buffer.len) return error.InputOutput; |
| 160 | 160 | }, |
| ... | ... | @@ -715,7 +715,7 @@ fn updateDeclCode( |
| 715 | 715 | } else if (code.len < old_size) { |
| 716 | 716 | atom.shrink(macho_file); |
| 717 | 717 | } else if (macho_file.getAtom(atom.next_index) == null) { |
| 718 | const needed_size = atom.value + code.len - sect.addr; | |
| 718 | const needed_size = atom.value + code.len; | |
| 719 | 719 | sect.size = needed_size; |
| 720 | 720 | } |
| 721 | 721 | } else { |
| ... | ... | @@ -733,7 +733,7 @@ fn updateDeclCode( |
| 733 | 733 | } |
| 734 | 734 | |
| 735 | 735 | if (!sect.isZerofill()) { |
| 736 | const file_offset = sect.offset + atom.value - sect.addr; | |
| 736 | const file_offset = sect.offset + atom.value; | |
| 737 | 737 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 738 | 738 | } |
| 739 | 739 | } |
| ... | ... | @@ -1036,7 +1036,7 @@ fn lowerConst( |
| 1036 | 1036 | nlist.n_value = 0; |
| 1037 | 1037 | |
| 1038 | 1038 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1039 | const file_offset = sect.offset + atom.value - sect.addr; | |
| 1039 | const file_offset = sect.offset + atom.value; | |
| 1040 | 1040 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 1041 | 1041 | |
| 1042 | 1042 | return .{ .ok = sym_index }; |
| ... | ... | @@ -1213,7 +1213,7 @@ fn updateLazySymbol( |
| 1213 | 1213 | } |
| 1214 | 1214 | |
| 1215 | 1215 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1216 | const file_offset = sect.offset + atom.value - sect.addr; | |
| 1216 | const file_offset = sect.offset + atom.value; | |
| 1217 | 1217 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 1218 | 1218 | } |
| 1219 | 1219 |
src/link/MachO/relocatable.zig+2-2| ... | ... | @@ -328,7 +328,7 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 328 | 328 | for (atoms.items) |atom_index| { |
| 329 | 329 | const atom = macho_file.getAtom(atom_index).?; |
| 330 | 330 | assert(atom.flags.alive); |
| 331 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; | |
| 331 | const off = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 332 | 332 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 333 | 333 | try atom.getData(macho_file, code[off..][0..atom_size]); |
| 334 | 334 | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); |
| ... | ... | @@ -386,7 +386,7 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 386 | 386 | return error.FlushFailure; |
| 387 | 387 | }, |
| 388 | 388 | }; |
| 389 | const file_offset = header.offset + atom.value - header.addr; | |
| 389 | const file_offset = header.offset + atom.value; | |
| 390 | 390 | const rels = relocs.getPtr(atom.out_n_sect).?; |
| 391 | 391 | try atom.writeRelocs(macho_file, code, rels); |
| 392 | 392 | try macho_file.base.file.?.pwriteAll(code, file_offset); |