mirror of
https://github.com/ziglang/zig.git
synced 2025-12-31 18:43:18 +00:00
macho: use generic TableSection for GOT mgmt
This commit is contained in:
parent
8e3100ae02
commit
711bc2cf39
@ -41,6 +41,7 @@ const Md5 = std.crypto.hash.Md5;
|
||||
const Module = @import("../Module.zig");
|
||||
const Relocation = @import("MachO/Relocation.zig");
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const TableSection = @import("table_section.zig").TableSection;
|
||||
const Trie = @import("MachO/Trie.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
@ -154,13 +155,14 @@ stub_helper_preamble_atom_index: ?Atom.Index = null,
|
||||
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
|
||||
got_table: SectionTable = .{},
|
||||
got_table: TableSection(SymbolWithLoc) = .{},
|
||||
stubs_table: SectionTable = .{},
|
||||
tlv_table: SectionTable = .{},
|
||||
|
||||
error_flags: File.ErrorFlags = File.ErrorFlags{},
|
||||
|
||||
segment_table_dirty: bool = false,
|
||||
got_table_count_dirty: bool = false,
|
||||
|
||||
/// A helper var to indicate if we are at the start of the incremental updates, or
|
||||
/// already somewhere further along the update-and-run chain.
|
||||
@ -1270,6 +1272,30 @@ fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index:
|
||||
if (nwritten != code.len) return error.InputOutput;
|
||||
}
|
||||
|
||||
fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !void {
|
||||
const sect_id = self.got_section_index.?;
|
||||
|
||||
if (self.got_table_count_dirty) {
|
||||
const needed_size = self.got_table.entries.items.len * @sizeOf(u64);
|
||||
try self.growSection(sect_id, needed_size);
|
||||
self.got_table_count_dirty = false;
|
||||
}
|
||||
|
||||
const header = &self.sections.items(.header)[sect_id];
|
||||
const entry = self.got_table.entries.items[index];
|
||||
const entry_value = self.getSymbol(entry).n_value;
|
||||
const entry_offset = index * @sizeOf(u64);
|
||||
const file_offset = header.offset + entry_offset;
|
||||
const vmaddr = header.addr + entry_offset;
|
||||
_ = vmaddr;
|
||||
|
||||
var buf: [8]u8 = undefined;
|
||||
mem.writeIntLittle(u64, &buf, entry_value);
|
||||
try self.base.file.?.pwriteAll(&buf, file_offset);
|
||||
|
||||
// TODO write in memory
|
||||
}
|
||||
|
||||
fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
|
||||
var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
|
||||
try self.writeAtom(atom_index, &buffer);
|
||||
@ -1290,10 +1316,9 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
|
||||
log.debug("marking relocs dirty by address: {x}", .{addr});
|
||||
for (self.relocs.values()) |*relocs| {
|
||||
for (relocs.items) |*reloc| {
|
||||
const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
|
||||
const target_atom = self.getAtom(target_atom_index);
|
||||
const target_sym = target_atom.getSymbol(self);
|
||||
if (target_sym.n_value < addr) continue;
|
||||
const target_addr = reloc.getTargetBaseAddress(self) orelse continue;
|
||||
if (target_addr == 0) continue;
|
||||
if (target_addr < addr) continue;
|
||||
reloc.dirty = true;
|
||||
}
|
||||
}
|
||||
@ -1335,40 +1360,6 @@ pub fn createAtom(self: *MachO) !Atom.Index {
|
||||
return atom_index;
|
||||
}
|
||||
|
||||
pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
|
||||
const atom_index = try self.createAtom();
|
||||
self.getAtomPtr(atom_index).size = @sizeOf(u64);
|
||||
|
||||
const sym = self.getAtom(atom_index).getSymbolPtr(self);
|
||||
sym.n_type = macho.N_SECT;
|
||||
sym.n_sect = self.got_section_index.? + 1;
|
||||
sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64));
|
||||
|
||||
log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});
|
||||
|
||||
try Atom.addRelocation(self, atom_index, .{
|
||||
.type = .unsigned,
|
||||
.target = target,
|
||||
.offset = 0,
|
||||
.addend = 0,
|
||||
.pcrel = false,
|
||||
.length = 3,
|
||||
});
|
||||
|
||||
const target_sym = self.getSymbol(target);
|
||||
if (target_sym.undf()) {
|
||||
try Atom.addBinding(self, atom_index, .{
|
||||
.target = self.getGlobal(self.getSymbolName(target)).?,
|
||||
.offset = 0,
|
||||
});
|
||||
} else {
|
||||
try Atom.addRebase(self, atom_index, 0);
|
||||
}
|
||||
try self.writePtrWidthAtom(atom_index);
|
||||
|
||||
return atom_index;
|
||||
}
|
||||
|
||||
fn createDyldPrivateAtom(self: *MachO) !void {
|
||||
if (self.dyld_private_atom_index != null) return;
|
||||
|
||||
@ -2104,9 +2095,7 @@ fn allocateGlobal(self: *MachO) !u32 {
|
||||
fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
|
||||
if (self.got_table.lookup.contains(target)) return;
|
||||
const got_index = try self.got_table.allocateEntry(self.base.allocator, target);
|
||||
const got_atom_index = try self.createGotAtom(target);
|
||||
const got_atom = self.getAtom(got_atom_index);
|
||||
self.got_table.entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
|
||||
try self.writeOffsetTableEntry(got_index);
|
||||
self.markRelocsDirtyByTarget(target);
|
||||
}
|
||||
|
||||
@ -2532,8 +2521,8 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
|
||||
} else .{ .sym_index = sym_index };
|
||||
self.markRelocsDirtyByTarget(target);
|
||||
log.debug(" (updating GOT entry)", .{});
|
||||
const got_atom_index = self.got_table.getAtomIndex(self, target).?;
|
||||
try self.writePtrWidthAtom(got_atom_index);
|
||||
const got_atom_index = self.got_table.lookup.get(target).?;
|
||||
try self.writeOffsetTableEntry(got_atom_index);
|
||||
}
|
||||
} else if (code_len < atom.size) {
|
||||
self.shrinkAtom(atom_index, code_len);
|
||||
@ -3276,6 +3265,20 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
|
||||
}
|
||||
}
|
||||
|
||||
// Gather GOT pointers
|
||||
const segment_index = self.sections.items(.segment_index)[self.got_section_index.?];
|
||||
for (self.got_table.entries.items, 0..) |entry, i| {
|
||||
if (!self.got_table.lookup.contains(entry)) continue;
|
||||
const sym = self.getSymbol(entry);
|
||||
if (sym.undf()) continue;
|
||||
const offset = i * @sizeOf(u64);
|
||||
log.debug(" | rebase at {x}", .{offset});
|
||||
rebase.entries.appendAssumeCapacity(.{
|
||||
.offset = offset,
|
||||
.segment_id = segment_index,
|
||||
});
|
||||
}
|
||||
|
||||
try rebase.finalize(gpa);
|
||||
}
|
||||
|
||||
@ -3320,6 +3323,32 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
|
||||
}
|
||||
}
|
||||
|
||||
// Gather GOT pointers
|
||||
const segment_index = self.sections.items(.segment_index)[self.got_section_index.?];
|
||||
for (self.got_table.entries.items, 0..) |entry, i| {
|
||||
if (!self.got_table.lookup.contains(entry)) continue;
|
||||
const sym = self.getSymbol(entry);
|
||||
if (!sym.undf()) continue;
|
||||
const offset = i * @sizeOf(u64);
|
||||
const bind_sym = self.getSymbol(entry);
|
||||
const bind_sym_name = self.getSymbolName(entry);
|
||||
const dylib_ordinal = @divTrunc(
|
||||
@bitCast(i16, bind_sym.n_desc),
|
||||
macho.N_SYMBOL_RESOLVER,
|
||||
);
|
||||
log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
|
||||
offset,
|
||||
bind_sym_name,
|
||||
dylib_ordinal,
|
||||
});
|
||||
bind.entries.appendAssumeCapacity(.{
|
||||
.target = entry,
|
||||
.offset = offset,
|
||||
.segment_id = segment_index,
|
||||
.addend = 0,
|
||||
});
|
||||
}
|
||||
|
||||
try bind.finalize(gpa, self);
|
||||
}
|
||||
|
||||
@ -3620,10 +3649,10 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
|
||||
const got = &self.sections.items(.header)[sect_id];
|
||||
got.reserved1 = nstubs;
|
||||
for (self.got_table.entries.items) |entry| {
|
||||
if (entry.sym_index == 0) continue;
|
||||
const target_sym = self.getSymbol(entry.target);
|
||||
if (!self.got_table.lookup.contains(entry)) continue;
|
||||
const target_sym = self.getSymbol(entry);
|
||||
if (target_sym.undf()) {
|
||||
try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);
|
||||
try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?);
|
||||
} else {
|
||||
try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
|
||||
}
|
||||
@ -4321,7 +4350,7 @@ pub fn logSymtab(self: *MachO) void {
|
||||
}
|
||||
|
||||
log.debug("GOT entries:", .{});
|
||||
log.debug("{}", .{self.got_table.fmtDebug(self)});
|
||||
log.debug("{}", .{self.got_table});
|
||||
|
||||
log.debug("stubs entries:", .{});
|
||||
log.debug("{}", .{self.stubs_table.fmtDebug(self)});
|
||||
|
||||
@ -230,7 +230,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
|
||||
.got_load => blk: {
|
||||
const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
|
||||
const got_entry = macho_file.got_table.entries.items[got_index];
|
||||
break :blk got_entry.getSymbol(macho_file);
|
||||
break :blk macho_file.getSymbol(got_entry);
|
||||
},
|
||||
};
|
||||
if (sym.n_value == reloc.prev_vaddr) continue;
|
||||
@ -240,7 +240,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
|
||||
.got_load => blk: {
|
||||
const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
|
||||
const got_entry = macho_file.got_table.entries.items[got_index];
|
||||
break :blk got_entry.getName(macho_file);
|
||||
break :blk macho_file.getSymbolName(got_entry);
|
||||
},
|
||||
};
|
||||
const sect = &self.sections.items[self.debug_info_section_index.?];
|
||||
|
||||
@ -39,25 +39,35 @@ pub const Type = enum {
|
||||
|
||||
/// Returns true if and only if the reloc is dirty AND the target address is available.
|
||||
pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
|
||||
_ = self.getTargetAtomIndex(macho_file) orelse return false;
|
||||
const addr = self.getTargetBaseAddress(macho_file) orelse return false;
|
||||
if (addr == 0) return false;
|
||||
return self.dirty;
|
||||
}
|
||||
|
||||
pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
|
||||
return switch (self.type) {
|
||||
.got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),
|
||||
.tlv => {
|
||||
const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse
|
||||
return null;
|
||||
const thunk_atom = macho_file.getAtom(thunk_atom_index);
|
||||
return macho_file.got_table.getAtomIndex(macho_file, thunk_atom.getSymbolWithLoc());
|
||||
pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {
|
||||
switch (self.type) {
|
||||
.got, .got_page, .got_pageoff => {
|
||||
const got_index = macho_file.got_table.lookup.get(self.target) orelse return null;
|
||||
const header = macho_file.sections.items(.header)[macho_file.got_section_index.?];
|
||||
return header.addr + got_index * @sizeOf(u64);
|
||||
},
|
||||
.branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
|
||||
index
|
||||
else
|
||||
macho_file.getAtomIndexForSymbol(self.target),
|
||||
else => macho_file.getAtomIndexForSymbol(self.target),
|
||||
};
|
||||
.tlv => {
|
||||
const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse return null;
|
||||
const thunk_atom = macho_file.getAtom(thunk_atom_index);
|
||||
const got_index = macho_file.got_table.lookup.get(thunk_atom.getSymbolWithLoc()) orelse return null;
|
||||
const header = macho_file.sections.items(.header)[macho_file.got_section_index.?];
|
||||
return header.addr + got_index * @sizeOf(u64);
|
||||
},
|
||||
.branch => {
|
||||
const atom_index = blk: {
|
||||
if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index| break :blk index;
|
||||
break :blk macho_file.getAtomIndexForSymbol(self.target) orelse return null;
|
||||
};
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
return atom.getSymbol(macho_file).n_value;
|
||||
},
|
||||
else => return macho_file.getSymbol(self.target).n_value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) void {
|
||||
@ -66,17 +76,14 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
|
||||
const source_sym = atom.getSymbol(macho_file);
|
||||
const source_addr = source_sym.n_value + self.offset;
|
||||
|
||||
const target_atom_index = self.getTargetAtomIndex(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
|
||||
const target_atom = macho_file.getAtom(target_atom_index);
|
||||
|
||||
const target_base_addr = self.getTargetBaseAddress(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
|
||||
const target_addr: i64 = switch (self.type) {
|
||||
.tlv_initializer => blk: {
|
||||
assert(self.addend == 0); // Addend here makes no sense.
|
||||
const header = macho_file.sections.items(.header)[macho_file.thread_data_section_index.?];
|
||||
const target_sym = target_atom.getSymbol(macho_file);
|
||||
break :blk @intCast(i64, target_sym.n_value - header.addr);
|
||||
break :blk @intCast(i64, target_base_addr - header.addr);
|
||||
},
|
||||
else => @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend,
|
||||
else => @intCast(i64, target_base_addr) + self.addend,
|
||||
};
|
||||
|
||||
log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user