macho: reference TLV thunks via GOT table
This commit is contained in:
@@ -137,7 +137,6 @@ got_section_index: ?u8 = null,
|
||||
data_const_section_index: ?u8 = null,
|
||||
la_symbol_ptr_section_index: ?u8 = null,
|
||||
data_section_index: ?u8 = null,
|
||||
thread_ptr_section_index: ?u8 = null,
|
||||
thread_vars_section_index: ?u8 = null,
|
||||
thread_data_section_index: ?u8 = null,
|
||||
|
||||
@@ -157,7 +156,7 @@ strtab: StringTable(.strtab) = .{},
|
||||
|
||||
got_table: SectionTable = .{},
|
||||
stubs_table: SectionTable = .{},
|
||||
tlvp_table: SectionTable = .{},
|
||||
tlv_table: SectionTable = .{},
|
||||
|
||||
error_flags: File.ErrorFlags = File.ErrorFlags{},
|
||||
|
||||
@@ -1741,31 +1740,6 @@ fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.In
|
||||
return atom_index;
|
||||
}
|
||||
|
||||
fn createThreadLocalPointerAtom(self: *MachO, tlv_desc_sym_index: u32) !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.thread_ptr_section_index.? + 1;
|
||||
sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64));
|
||||
|
||||
log.debug("allocated threadlocal pointer atom at 0x{x}", .{sym.n_value});
|
||||
|
||||
try Atom.addRelocation(self, atom_index, .{
|
||||
.type = .unsigned,
|
||||
.target = .{ .sym_index = tlv_desc_sym_index },
|
||||
.offset = 0,
|
||||
.addend = 0,
|
||||
.pcrel = false,
|
||||
.length = 3,
|
||||
});
|
||||
try Atom.addRebase(self, atom_index, 0);
|
||||
try self.writePtrWidthAtom(atom_index);
|
||||
|
||||
return atom_index;
|
||||
}
|
||||
|
||||
fn createMhExecuteHeaderSymbol(self: *MachO) !void {
|
||||
if (self.base.options.output_mode != .Exe) return;
|
||||
if (self.getGlobal("__mh_execute_header")) |global| {
|
||||
@@ -1916,7 +1890,7 @@ pub fn deinit(self: *MachO) void {
|
||||
|
||||
self.got_table.deinit(gpa);
|
||||
self.stubs_table.deinit(gpa);
|
||||
self.tlvp_table.deinit(gpa);
|
||||
self.tlv_table.deinit(gpa);
|
||||
self.strtab.deinit(gpa);
|
||||
|
||||
self.locals.deinit(gpa);
|
||||
@@ -2150,13 +2124,11 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
|
||||
}
|
||||
|
||||
fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {
|
||||
if (self.tlvp_table.lookup.contains(target)) return;
|
||||
const tlvp_index = try self.tlvp_table.allocateEntry(self.base.allocator, target);
|
||||
const tlv_desc_atom_index = try self.createThreadLocalDescriptorAtom(target);
|
||||
const tlv_desc_atom = self.getAtom(tlv_desc_atom_index);
|
||||
const tlv_ptr_atom_index = try self.createThreadLocalPointerAtom(tlv_desc_atom.getSymbolIndex().?);
|
||||
const tlv_ptr_atom = self.getAtom(tlv_ptr_atom_index);
|
||||
self.tlvp_table.entries.items[tlvp_index].sym_index = tlv_ptr_atom.getSymbolIndex().?;
|
||||
if (self.tlv_table.lookup.contains(target)) return;
|
||||
const tlv_index = try self.tlv_table.allocateEntry(self.base.allocator, target);
|
||||
const tlv_atom_index = try self.createThreadLocalDescriptorAtom(target);
|
||||
const tlv_atom = self.getAtom(tlv_atom_index);
|
||||
self.tlv_table.entries.items[tlv_index].sym_index = tlv_atom.getSymbolIndex().?;
|
||||
self.markRelocsDirtyByTarget(target);
|
||||
}
|
||||
|
||||
@@ -2550,18 +2522,18 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
|
||||
|
||||
if (vaddr != sym.n_value) {
|
||||
sym.n_value = vaddr;
|
||||
const target = SymbolWithLoc{ .sym_index = sym_index };
|
||||
// TODO: I think we should update the offset to the initializer here too.
|
||||
const target: SymbolWithLoc = if (is_threadlocal) blk: {
|
||||
const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{
|
||||
.sym_index = sym_index,
|
||||
}).?;
|
||||
const tlv_atom = self.getAtom(tlv_atom_index);
|
||||
break :blk tlv_atom.getSymbolWithLoc();
|
||||
} else .{ .sym_index = sym_index };
|
||||
self.markRelocsDirtyByTarget(target);
|
||||
if (is_threadlocal) {
|
||||
@panic("TODO update the threadlocal variable's name also");
|
||||
// log.debug(" (updating threadlocal pointer entry)", .{});
|
||||
// const tlvp_atom_index = self.tlvp_table.getAtomIndex(self, target).?;
|
||||
// try self.writePtrWidthAtom(tlvp_atom_index);
|
||||
} else {
|
||||
log.debug(" (updating GOT entry)", .{});
|
||||
const got_atom_index = self.got_table.getAtomIndex(self, target).?;
|
||||
try self.writePtrWidthAtom(got_atom_index);
|
||||
}
|
||||
log.debug(" (updating GOT entry)", .{});
|
||||
const got_atom_index = self.got_table.getAtomIndex(self, target).?;
|
||||
try self.writePtrWidthAtom(got_atom_index);
|
||||
}
|
||||
} else if (code_len < atom.size) {
|
||||
self.shrinkAtom(atom_index, code_len);
|
||||
@@ -2586,12 +2558,15 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
|
||||
self.getAtomPtr(atom_index).size = code_len;
|
||||
sym.n_value = vaddr;
|
||||
|
||||
const target: SymbolWithLoc = .{ .sym_index = sym_index };
|
||||
if (is_threadlocal) {
|
||||
try self.addTlvEntry(target);
|
||||
} else {
|
||||
try self.addGotEntry(target);
|
||||
try self.addTlvEntry(.{ .sym_index = sym_index });
|
||||
}
|
||||
const target: SymbolWithLoc = if (is_threadlocal) blk: {
|
||||
const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{ .sym_index = sym_index }).?;
|
||||
const tlv_atom = self.getAtom(tlv_atom_index);
|
||||
break :blk tlv_atom.getSymbolWithLoc();
|
||||
} else .{ .sym_index = sym_index };
|
||||
try self.addGotEntry(target);
|
||||
}
|
||||
|
||||
try self.writeAtom(atom_index, code);
|
||||
@@ -2927,17 +2902,8 @@ fn populateMissingMetadata(self: *MachO) !void {
|
||||
}
|
||||
|
||||
if (!self.base.options.single_threaded) {
|
||||
if (self.thread_ptr_section_index == null) {
|
||||
self.thread_ptr_section_index = try self.allocateSection("__DATA2", "__thread_ptrs", .{
|
||||
.size = @sizeOf(u64),
|
||||
.alignment = @alignOf(u64),
|
||||
.flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
|
||||
.prot = macho.PROT.READ | macho.PROT.WRITE,
|
||||
});
|
||||
self.segment_table_dirty = true;
|
||||
}
|
||||
if (self.thread_vars_section_index == null) {
|
||||
self.thread_vars_section_index = try self.allocateSection("__DATA3", "__thread_vars", .{
|
||||
self.thread_vars_section_index = try self.allocateSection("__DATA2", "__thread_vars", .{
|
||||
.size = @sizeOf(u64) * 3,
|
||||
.alignment = @sizeOf(u64),
|
||||
.flags = macho.S_THREAD_LOCAL_VARIABLES,
|
||||
@@ -2947,7 +2913,7 @@ fn populateMissingMetadata(self: *MachO) !void {
|
||||
}
|
||||
|
||||
if (self.thread_data_section_index == null) {
|
||||
self.thread_data_section_index = try self.allocateSection("__DATA4", "__thread_data", .{
|
||||
self.thread_data_section_index = try self.allocateSection("__DATA3", "__thread_data", .{
|
||||
.size = @sizeOf(u64),
|
||||
.alignment = @alignOf(u64),
|
||||
.flags = macho.S_THREAD_LOCAL_REGULAR,
|
||||
@@ -4361,7 +4327,7 @@ pub fn logSymtab(self: *MachO) void {
|
||||
log.debug("{}", .{self.stubs_table.fmtDebug(self)});
|
||||
|
||||
log.debug("threadlocal entries:", .{});
|
||||
log.debug("{}", .{self.tlvp_table.fmtDebug(self)});
|
||||
log.debug("{}", .{self.tlv_table.fmtDebug(self)});
|
||||
}
|
||||
|
||||
pub fn logAtoms(self: *MachO) void {
|
||||
|
||||
@@ -15,7 +15,7 @@ pub const Type = enum {
|
||||
got,
|
||||
/// RIP-relative displacement
|
||||
signed,
|
||||
/// RIP-relative displacemen to threadlocal variable descriptor
|
||||
/// RIP-relative displacement to GOT pointer to TLV thunk
|
||||
tlv,
|
||||
|
||||
// aarch64
|
||||
@@ -27,10 +27,6 @@ pub const Type = enum {
|
||||
page,
|
||||
/// Offset to a pointer relative to the start of a page in a section
|
||||
pageoff,
|
||||
/// PC-relative distance to target page in TLV section
|
||||
tlv_page,
|
||||
/// Offset to a pointer relative to the start of a page in TLV section
|
||||
tlv_pageoff,
|
||||
|
||||
// common
|
||||
/// PC/RIP-relative displacement B/BL/CALL
|
||||
@@ -50,7 +46,12 @@ pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
|
||||
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, .tlv_page, .tlv_pageoff => macho_file.tlvp_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());
|
||||
},
|
||||
.branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
|
||||
index
|
||||
else
|
||||
@@ -109,7 +110,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
|
||||
inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
|
||||
mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
|
||||
},
|
||||
.page, .got_page, .tlv_page => {
|
||||
.page, .got_page => {
|
||||
const source_page = @intCast(i32, source_addr >> 12);
|
||||
const target_page = @intCast(i32, target_addr >> 12);
|
||||
const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
|
||||
@@ -158,49 +159,6 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
|
||||
mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
|
||||
}
|
||||
},
|
||||
.tlv_pageoff => {
|
||||
const RegInfo = struct {
|
||||
rd: u5,
|
||||
rn: u5,
|
||||
size: u2,
|
||||
};
|
||||
const reg_info: RegInfo = blk: {
|
||||
if (isArithmeticOp(buffer[0..4])) {
|
||||
const inst = mem.bytesToValue(meta.TagPayload(
|
||||
aarch64.Instruction,
|
||||
aarch64.Instruction.add_subtract_immediate,
|
||||
), buffer[0..4]);
|
||||
break :blk .{
|
||||
.rd = inst.rd,
|
||||
.rn = inst.rn,
|
||||
.size = inst.sf,
|
||||
};
|
||||
} else {
|
||||
const inst = mem.bytesToValue(meta.TagPayload(
|
||||
aarch64.Instruction,
|
||||
aarch64.Instruction.load_store_register,
|
||||
), buffer[0..4]);
|
||||
break :blk .{
|
||||
.rd = inst.rt,
|
||||
.rn = inst.rn,
|
||||
.size = inst.size,
|
||||
};
|
||||
}
|
||||
};
|
||||
const narrowed = @truncate(u12, @intCast(u64, target_addr));
|
||||
var inst = aarch64.Instruction{
|
||||
.add_subtract_immediate = .{
|
||||
.rd = reg_info.rd,
|
||||
.rn = reg_info.rn,
|
||||
.imm12 = narrowed,
|
||||
.sh = 0,
|
||||
.s = 0,
|
||||
.op = 0,
|
||||
.sf = @truncate(u1, reg_info.size),
|
||||
},
|
||||
};
|
||||
mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
|
||||
},
|
||||
.tlv_initializer, .unsigned => switch (self.length) {
|
||||
2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),
|
||||
3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),
|
||||
@@ -227,7 +185,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.got_page, .got_pageoff, .page, .pageoff, .tlv_page, .tlv_pageoff => unreachable, // Invalid target architecture.
|
||||
.got_page, .got_pageoff, .page, .pageoff => unreachable, // Invalid target architecture.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user