diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-02-02 22:55:30 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-02-03 09:28:30 +0100 |
| commit | 9fc1685c1caa4c1d093fa8936a5602f54121dd50 (patch) | |
| tree | 95aa99d2c97d48bc0f2715ec1d05ee64b99539f2 | |
| parent | e10a2018a7b6a51243589ec95842d2cef2da45ac (diff) | |
| download | zig-9fc1685c1caa4c1d093fa8936a5602f54121dd50.tar.gz zig-9fc1685c1caa4c1d093fa8936a5602f54121dd50.zip | |
macho: make atom address relative wrt defining section
| -rw-r--r-- | src/link/MachO.zig | 66 | ||||
| -rw-r--r-- | src/link/MachO/Atom.zig | 39 | ||||
| -rw-r--r-- | src/link/MachO/Symbol.zig | 4 | ||||
| -rw-r--r-- | src/link/MachO/ZigObject.zig | 10 | ||||
| -rw-r--r-- | src/link/MachO/relocatable.zig | 4 |
5 files changed, 69 insertions, 54 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 7f58198ce0..d5706eb4de 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -636,7 +636,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node return error.FlushFailure; }, }; - const file_offset = sect.offset + atom.value - sect.addr; + const file_offset = sect.offset + atom.value; atom.resolveRelocs(self, code) catch |err| switch (err) { error.ResolveFailed => has_resolve_error = true, else => |e| { @@ -2393,16 +2393,7 @@ fn allocateSegments(self: *MachO) void { } pub fn allocateAtoms(self: *MachO) void { - const slice = self.sections.slice(); - for (slice.items(.header), slice.items(.atoms)) |header, atoms| { - if (atoms.items.len == 0) continue; - for (atoms.items) |atom_index| { - const atom = self.getAtom(atom_index).?; - assert(atom.flags.alive); - atom.value += header.addr; - } - } - + // TODO: redo this like atoms for (self.thunks.items) |*thunk| { const header = self.sections.items(.header)[thunk.out_n_sect]; thunk.value += header.addr; @@ -2603,7 +2594,7 @@ fn writeAtoms(self: *MachO) !void { for (atoms.items) |atom_index| { const atom = self.getAtom(atom_index).?; assert(atom.flags.alive); - const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; + const off = math.cast(usize, atom.value) orelse return error.Overflow; const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; try atom.getData(self, buffer[off..][0..atom_size]); 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 { if (atom.flags.alive) for (in_dices[start_dice..next_dice]) |dice| { dices.appendAssumeCapacity(.{ - .offset = @intCast(atom.value + dice.offset - start_off - base_address), + .offset = @intCast(atom.getAddress(self) + dice.offset - start_off - base_address), .length = dice.length, .kind = dice.kind, }); @@ -3318,7 +3309,7 @@ fn allocatedSize(self: *MachO, start: u64) u64 { return min_pos - start; } -fn allocatedVirtualSize(self: *MachO, start: u64) u64 { +fn allocatedSizeVirtual(self: *MachO, start: u64) u64 { if (start == 0) return 0; var min_pos: u64 = std.math.maxInt(u64); for (self.segments.items) |seg| { @@ -3518,22 +3509,39 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { sect.size = 0; // Must move the entire section. - const alignment = if (self.base.isRelocatable()) - try math.powi(u32, 2, sect.@"align") - else - self.getPageSize(); - const new_offset = self.findFreeSpace(needed_size, alignment); - - log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ - sect.segName(), - sect.sectName(), - new_offset, - new_offset + existing_size, - }); + if (self.base.isRelocatable()) { + const alignment = try math.powi(u32, 2, sect.@"align"); + const new_offset = self.findFreeSpace(needed_size, alignment); + const new_addr = self.findFreeSpaceVirtual(needed_size, alignment); - try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); + log.debug("new '{s},{s}' file offset 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ + sect.segName(), + sect.sectName(), + new_offset, + new_offset + existing_size, + new_addr, + new_addr + existing_size, + }); + + try self.copyRangeAll(sect.offset, new_offset, existing_size); - sect.offset = @intCast(new_offset); + sect.offset = @intCast(new_offset); + sect.addr = new_addr; + } else { + const alignment = self.getPageSize(); + const new_offset = self.findFreeSpace(needed_size, alignment); + + log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{ + sect.segName(), + sect.sectName(), + new_offset, + new_offset + existing_size, + }); + + try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); + + sect.offset = @intCast(new_offset); + } } sect.size = needed_size; @@ -3547,7 +3555,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { seg.filesize = needed_size; } - const mem_capacity = self.allocatedVirtualSize(seg.vmaddr); + const mem_capacity = self.allocatedSizeVirtual(seg.vmaddr); if (needed_size > mem_capacity) { var err = try self.addErrorWithNotes(2); try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{ diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 80ef540100..59a60f6858 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -1,4 +1,4 @@ -/// Address allocated for this Atom. +/// Address offset allocated for this Atom wrt to its section start address. value: u64 = 0, /// Name of this Atom. @@ -84,6 +84,11 @@ pub fn getInputAddress(self: Atom, macho_file: *MachO) u64 { return self.getInputSection(macho_file).addr + self.off; } +pub fn getAddress(self: Atom, macho_file: *MachO) u64 { + const header = macho_file.sections.items(.header)[self.out_n_sect]; + return header.addr + self.value; +} + pub fn getPriority(self: Atom, macho_file: *MachO) u64 { const file = self.getFile(macho_file); 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 { /// File offset relocation happens transparently, so it is not included in /// this calculation. pub fn capacity(self: Atom, macho_file: *MachO) u64 { - const next_value = if (macho_file.getAtom(self.next_index)) |next| next.value else std.math.maxInt(u32); - return next_value - self.value; + const next_addr = if (macho_file.getAtom(self.next_index)) |next| + next.getAddress(macho_file) + else + std.math.maxInt(u32); + return next_addr - self.getAddress(macho_file); } pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { // No need to keep a free list node for the last block. const next = macho_file.getAtom(self.next_index) orelse return false; - const cap = next.value - self.value; + const cap = next.getAddress(macho_file) - self.getAddress(macho_file); const ideal_cap = MachO.padToIdeal(self.size); if (cap <= ideal_cap) return false; const surplus = cap - ideal_cap; @@ -263,15 +271,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { atom_placement = last.atom_index; break :blk new_start_vaddr; } else { - break :blk sect.addr; + break :blk 0; } }; log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{ self.atom_index, self.getName(macho_file), - self.value, - self.value + self.size, + self.getAddress(macho_file), + self.getAddress(macho_file) + self.size, }); const expand_section = if (atom_placement) |placement_index| @@ -279,7 +287,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { else true; if (expand_section) { - const needed_size = (self.value + self.size) - sect.addr; + const needed_size = self.value + self.size; try macho_file.growSection(self.out_n_sect, needed_size); last_atom_index.* = self.atom_index; @@ -544,7 +552,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { const name = self.getName(macho_file); const relocs = self.getRelocs(macho_file); - relocs_log.debug("{x}: {s}", .{ self.value, name }); + relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), name }); var has_error = false; var stream = std.io.fixedBufferStream(buffer); @@ -569,7 +577,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { try macho_file.reportParseError2( file.getIndex(), "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {s}, target {s}", - .{ name, self.value, rel.offset, @tagName(rel.type), target }, + .{ name, self.getAddress(macho_file), rel.offset, @tagName(rel.type), target }, ); has_error = true; }, @@ -604,7 +612,7 @@ fn resolveRelocInner( const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; const seg_id = macho_file.sections.items(.segment_id)[self.out_n_sect]; const seg = macho_file.segments.items[seg_id]; - const P = @as(i64, @intCast(self.value)) + @as(i64, @intCast(rel_offset)); + const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); const A = rel.addend + rel.getRelocAddend(cpu_arch); const S: i64 = @intCast(rel.getTargetAddress(macho_file)); const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); @@ -919,7 +927,7 @@ const x86_64 = struct { var err = try macho_file.addErrorWithNotes(2); try err.addMsg(macho_file, "{s}: 0x{x}: 0x{x}: failed to relax relocation of type {s}", .{ self.getName(macho_file), - self.value, + self.getAddress(macho_file), rel.offset, @tagName(rel.type), }); @@ -990,12 +998,11 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra const cpu_arch = macho_file.getTarget().cpu.arch; const relocs = self.getRelocs(macho_file); - const sect = macho_file.sections.items(.header)[self.out_n_sect]; var stream = std.io.fixedBufferStream(code); for (relocs) |rel| { const rel_offset = rel.offset - self.off; - const r_address: i32 = math.cast(i32, self.value + rel_offset - sect.addr) orelse return error.Overflow; + const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; const r_symbolnum = r_symbolnum: { const r_symbolnum: u32 = switch (rel.tag) { .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 .x86_64 => { if (rel.meta.pcrel) { if (rel.tag == .local) { - addend -= @as(i64, @intCast(self.value + rel_offset)); + addend -= @as(i64, @intCast(self.getAddress(macho_file) + rel_offset)); } else { addend += 4; } @@ -1144,7 +1151,7 @@ fn format2( const atom = ctx.atom; const macho_file = ctx.macho_file; try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ - atom.atom_index, atom.getName(macho_file), atom.value, + atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), atom.out_n_sect, atom.alignment, atom.size, atom.getRelocs(macho_file).len, atom.thunk_index, }); diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index a61e6f9579..c85918457b 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -118,7 +118,7 @@ pub fn getAddress(symbol: Symbol, opts: struct { return symbol.getObjcStubsAddress(macho_file); } } - if (symbol.getAtom(macho_file)) |atom| return atom.value + symbol.value; + if (symbol.getAtom(macho_file)) |atom| return atom.getAddress(macho_file) + symbol.value; return symbol.value; } @@ -145,7 +145,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { const extra = symbol.getExtra(macho_file).?; const atom = macho_file.getAtom(extra.objc_selrefs).?; assert(atom.flags.alive); - return atom.value; + return atom.getAddress(macho_file); } pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 0634cb68f7..8cb7a466fa 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -154,7 +154,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 @memset(buffer, 0); }, else => { - const file_offset = sect.offset + atom.value - sect.addr; + const file_offset = sect.offset + atom.value; const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); if (amt != buffer.len) return error.InputOutput; }, @@ -715,7 +715,7 @@ fn updateDeclCode( } else if (code.len < old_size) { atom.shrink(macho_file); } else if (macho_file.getAtom(atom.next_index) == null) { - const needed_size = atom.value + code.len - sect.addr; + const needed_size = atom.value + code.len; sect.size = needed_size; } } else { @@ -733,7 +733,7 @@ fn updateDeclCode( } if (!sect.isZerofill()) { - const file_offset = sect.offset + atom.value - sect.addr; + const file_offset = sect.offset + atom.value; try macho_file.base.file.?.pwriteAll(code, file_offset); } } @@ -1036,7 +1036,7 @@ fn lowerConst( nlist.n_value = 0; const sect = macho_file.sections.items(.header)[output_section_index]; - const file_offset = sect.offset + atom.value - sect.addr; + const file_offset = sect.offset + atom.value; try macho_file.base.file.?.pwriteAll(code, file_offset); return .{ .ok = sym_index }; @@ -1213,7 +1213,7 @@ fn updateLazySymbol( } const sect = macho_file.sections.items(.header)[output_section_index]; - const file_offset = sect.offset + atom.value - sect.addr; + const file_offset = sect.offset + atom.value; try macho_file.base.file.?.pwriteAll(code, file_offset); } diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index cbfd81f9d1..0a7000f9ba 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -328,7 +328,7 @@ fn writeAtoms(macho_file: *MachO) !void { for (atoms.items) |atom_index| { const atom = macho_file.getAtom(atom_index).?; assert(atom.flags.alive); - const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; + const off = math.cast(usize, atom.value) orelse return error.Overflow; const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; try atom.getData(macho_file, code[off..][0..atom_size]); try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); @@ -386,7 +386,7 @@ fn writeAtoms(macho_file: *MachO) !void { return error.FlushFailure; }, }; - const file_offset = header.offset + atom.value - header.addr; + const file_offset = header.offset + atom.value; const rels = relocs.getPtr(atom.out_n_sect).?; try atom.writeRelocs(macho_file, code, rels); try macho_file.base.file.?.pwriteAll(code, file_offset); |
