Commit 5750620715
src/link/MachO/Atom.zig
@@ -360,7 +360,6 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc) ?Index {
if (zld.getStubsAtomIndexForSymbol(target)) |stubs_atom| return stubs_atom;
- if (zld.getTlvPtrAtomIndexForSymbol(target)) |tlv_ptr_atom| return tlv_ptr_atom;
if (target.getFile() == null) {
const target_sym_name = zld.getSymbolName(target);
@@ -413,7 +412,8 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma
.ARM64_RELOC_TLVP_LOAD_PAGE21,
.ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
=> {
- try addTlvPtrEntry(zld, target);
+ const sym = zld.getSymbol(target);
+ if (sym.undf()) try zld.addTlvPtrEntry(target);
},
else => {},
}
@@ -454,28 +454,14 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
try zld.addGotEntry(target);
},
.X86_64_RELOC_TLV => {
- try addTlvPtrEntry(zld, target);
+ const sym = zld.getSymbol(target);
+ if (sym.undf()) try zld.addTlvPtrEntry(target);
},
else => {},
}
}
}
-fn addTlvPtrEntry(zld: *Zld, target: SymbolWithLoc) !void {
- const target_sym = zld.getSymbol(target);
- if (!target_sym.undf()) return;
- if (zld.tlv_ptr_table.contains(target)) return;
-
- const gpa = zld.gpa;
- const atom_index = try zld.createTlvPtrAtom();
- const tlv_ptr_index = @as(u32, @intCast(zld.tlv_ptr_entries.items.len));
- try zld.tlv_ptr_entries.append(gpa, .{
- .target = target,
- .atom_index = atom_index,
- });
- try zld.tlv_ptr_table.putNoClobber(gpa, target, tlv_ptr_index);
-}
-
pub fn addStub(zld: *Zld, target: SymbolWithLoc) !void {
const target_sym = zld.getSymbol(target);
if (!target_sym.undf()) return;
@@ -641,10 +627,12 @@ fn resolveRelocsArm64(
const header = zld.sections.items(.header)[source_sym.n_sect - 1];
break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
};
- const target_addr = if (is_via_got)
- zld.getGotEntryAddress(target).?
- else
- try getRelocTargetAddress(zld, target, is_tlv);
+ const target_addr = blk: {
+ if (is_via_got) break :blk zld.getGotEntryAddress(target).?;
+ if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())
+ break :blk zld.getTlvPtrEntryAddress(target).?;
+ break :blk try getRelocTargetAddress(zld, target, is_tlv);
+ };
log.debug(" | source_addr = 0x{x}", .{source_addr});
@@ -802,7 +790,7 @@ fn resolveRelocsArm64(
}
};
- var inst = if (zld.tlv_ptr_table.contains(target)) aarch64.Instruction{
+ var inst = if (zld.tlv_ptr_table.lookup.contains(target)) aarch64.Instruction{
.load_store_register = .{
.rt = reg_info.rd,
.rn = reg_info.rn,
@@ -938,14 +926,15 @@ fn resolveRelocsX86(
const header = zld.sections.items(.header)[source_sym.n_sect - 1];
break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
};
+ const target_addr = blk: {
+ if (is_via_got) break :blk zld.getGotEntryAddress(target).?;
+ if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())
+ break :blk zld.getTlvPtrEntryAddress(target).?;
+ break :blk try getRelocTargetAddress(zld, target, is_tlv);
+ };
log.debug(" | source_addr = 0x{x}", .{source_addr});
- const target_addr = if (is_via_got)
- zld.getGotEntryAddress(target).?
- else
- try getRelocTargetAddress(zld, target, is_tlv);
-
switch (rel_type) {
.X86_64_RELOC_BRANCH => {
const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
@@ -971,7 +960,7 @@ fn resolveRelocsX86(
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
- if (zld.tlv_ptr_table.get(target) == null) {
+ if (zld.tlv_ptr_table.lookup.get(target) == null) {
// We need to rewrite the opcode from movq to leaq.
atom_code[rel_offset - 2] = 0x8d;
}
@@ -1112,3 +1101,19 @@ pub fn relocRequiresGot(zld: *Zld, rel: macho.relocation_info) bool {
else => unreachable,
}
}
+
+pub fn relocIsTlv(zld: *Zld, rel: macho.relocation_info) bool {
+ switch (zld.options.target.cpu.arch) {
+ .aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
+ .ARM64_RELOC_TLVP_LOAD_PAGE21,
+ .ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
+ => return true,
+ else => return false,
+ },
+ .x86_64 => switch (@as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type))) {
+ .X86_64_RELOC_TLV => return true,
+ else => return false,
+ },
+ else => unreachable,
+ }
+}
src/link/MachO/zld.zig
@@ -68,6 +68,7 @@ pub const Zld = struct {
sections: std.MultiArrayList(Section) = .{},
got_section_index: ?u8 = null,
+ tlv_ptr_section_index: ?u8 = null,
locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
@@ -81,9 +82,7 @@ pub const Zld = struct {
strtab: StringTable(.strtab) = .{},
- tlv_ptr_entries: std.ArrayListUnmanaged(IndirectPointer) = .{},
- tlv_ptr_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
-
+ tlv_ptr_table: TableSection(SymbolWithLoc) = .{},
got_table: TableSection(SymbolWithLoc) = .{},
stubs: std.ArrayListUnmanaged(IndirectPointer) = .{},
@@ -268,24 +267,6 @@ pub const Zld = struct {
return index;
}
- pub fn createTlvPtrAtom(self: *Zld) !AtomIndex {
- const sym_index = try self.allocateSymbol();
- const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3);
- const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
- sym.n_type = macho.N_SECT;
-
- const sect_id = (try self.getOutputSection(.{
- .segname = makeStaticString("__DATA"),
- .sectname = makeStaticString("__thread_ptrs"),
- .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
- })).?;
- sym.n_sect = sect_id + 1;
-
- self.addAtomToSection(atom_index);
-
- return atom_index;
- }
-
fn createDyldStubBinderGotAtom(self: *Zld) !void {
const global_index = self.dyld_stub_binder_index orelse return;
const target = self.globals.items[global_index];
@@ -841,7 +822,6 @@ pub const Zld = struct {
pub fn deinit(self: *Zld) void {
const gpa = self.gpa;
- self.tlv_ptr_entries.deinit(gpa);
self.tlv_ptr_table.deinit(gpa);
self.got_table.deinit(gpa);
self.stubs.deinit(gpa);
@@ -959,16 +939,26 @@ pub const Zld = struct {
return global_index;
}
- pub fn addGotEntry(zld: *Zld, target: SymbolWithLoc) !void {
- if (zld.got_table.lookup.contains(target)) return;
- _ = try zld.got_table.allocateEntry(zld.gpa, target);
- if (zld.got_section_index == null) {
- zld.got_section_index = try zld.initSection("__DATA_CONST", "__got", .{
+ pub fn addGotEntry(self: *Zld, target: SymbolWithLoc) !void {
+ if (self.got_table.lookup.contains(target)) return;
+ _ = try self.got_table.allocateEntry(self.gpa, target);
+ if (self.got_section_index == null) {
+ self.got_section_index = try self.initSection("__DATA_CONST", "__got", .{
.flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
});
}
}
+ pub fn addTlvPtrEntry(self: *Zld, target: SymbolWithLoc) !void {
+ if (self.tlv_ptr_table.lookup.contains(target)) return;
+ _ = try self.tlv_ptr_table.allocateEntry(self.gpa, target);
+ if (self.tlv_ptr_section_index == null) {
+ self.tlv_ptr_section_index = try self.initSection("__DATA", "__thread_ptrs", .{
+ .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
+ });
+ }
+ }
+
fn allocateSpecialSymbols(self: *Zld) !void {
for (&[_]?u32{
self.dso_handle_index,
@@ -1033,12 +1023,10 @@ pub const Zld = struct {
} else if (atom.getFile() == null) outer: {
switch (header.type()) {
macho.S_NON_LAZY_SYMBOL_POINTERS => unreachable,
+ macho.S_THREAD_LOCAL_VARIABLE_POINTERS => unreachable,
macho.S_LAZY_SYMBOL_POINTERS => {
try self.writeLazyPointer(count, buffer.writer());
},
- macho.S_THREAD_LOCAL_VARIABLE_POINTERS => {
- buffer.appendSliceAssumeCapacity(&[_]u8{0} ** @sizeOf(u64));
- },
else => {
if (self.stub_helper_preamble_sym_index) |sym_index| {
if (sym_index == atom.sym_index) {
@@ -1087,12 +1075,11 @@ pub const Zld = struct {
}
}
- fn writeGotEntries(self: *Zld) !void {
- const sect_id = self.got_section_index orelse return;
+ fn writePointerEntries(self: *Zld, sect_id: u8, table: anytype) !void {
const header = self.sections.items(.header)[sect_id];
var buffer = try std.ArrayList(u8).initCapacity(self.gpa, header.size);
defer buffer.deinit();
- for (self.got_table.entries.items) |entry| {
+ for (table.entries.items) |entry| {
const sym = self.getSymbol(entry);
buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable;
}
@@ -1147,6 +1134,7 @@ pub const Zld = struct {
for (&[_]*?u8{
&self.got_section_index,
+ &self.tlv_ptr_section_index,
}) |maybe_index| {
if (maybe_index.*) |*index| {
index.* = backlinks[index.*];
@@ -1236,6 +1224,12 @@ pub const Zld = struct {
header.size = self.got_table.count() * @sizeOf(u64);
header.@"align" = 3;
}
+
+ if (self.tlv_ptr_section_index) |sect_id| {
+ const header = &self.sections.items(.header)[sect_id];
+ header.size = self.tlv_ptr_table.count() * @sizeOf(u64);
+ header.@"align" = 3;
+ }
}
fn allocateSegments(self: *Zld) !void {
@@ -1579,44 +1573,6 @@ pub const Zld = struct {
try rebase.finalize(self.gpa);
}
- fn collectBindDataFromContainer(
- self: *Zld,
- sect_id: u8,
- bind: *Bind,
- container: anytype,
- ) !void {
- const slice = self.sections.slice();
- const segment_index = slice.items(.segment_index)[sect_id];
- const seg = self.getSegment(sect_id);
-
- try bind.entries.ensureUnusedCapacity(self.gpa, container.items.len);
-
- for (container.items) |entry| {
- const bind_sym_name = entry.getTargetSymbolName(self);
- const bind_sym = entry.getTargetSymbol(self);
- if (bind_sym.sect()) continue;
-
- const sym = entry.getAtomSymbol(self);
- const base_offset = sym.n_value - seg.vmaddr;
-
- const dylib_ordinal = @divTrunc(@as(i16, @bitCast(bind_sym.n_desc)), macho.N_SYMBOL_RESOLVER);
- log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
- base_offset,
- bind_sym_name,
- dylib_ordinal,
- });
- if (bind_sym.weakRef()) {
- log.debug(" | marking as weak ref ", .{});
- }
- bind.entries.appendAssumeCapacity(.{
- .target = entry.target,
- .offset = base_offset,
- .segment_id = segment_index,
- .addend = 0,
- });
- }
- }
-
fn collectBindData(
self: *Zld,
bind: *Bind,
@@ -1629,8 +1585,8 @@ pub const Zld = struct {
}
// Next, unpack TLV pointers section
- if (self.getSectionByName("__DATA", "__thread_ptrs")) |sect_id| {
- try self.collectBindDataFromContainer(sect_id, bind, self.tlv_ptr_entries);
+ if (self.tlv_ptr_section_index) |sect_id| {
+ try MachO.collectBindDataFromTableSection(self.gpa, self, sect_id, bind, self.tlv_ptr_table);
}
// Finally, unpack the rest.
@@ -2488,6 +2444,12 @@ pub const Zld = struct {
return header.addr + @sizeOf(u64) * index;
}
+ pub fn getTlvPtrEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 {
+ const index = self.tlv_ptr_table.lookup.get(sym_with_loc) orelse return null;
+ const header = self.sections.items(.header)[self.tlv_ptr_section_index.?];
+ return header.addr + @sizeOf(u64) * index;
+ }
+
/// Returns stubs atom that references `sym_with_loc` if one exists.
/// Returns null otherwise.
pub fn getStubsAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex {
@@ -2496,14 +2458,6 @@ pub const Zld = struct {
return entry.atom_index;
}
- /// Returns TLV pointer atom that references `sym_with_loc` if one exists.
- /// Returns null otherwise.
- pub fn getTlvPtrAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex {
- const index = self.tlv_ptr_table.get(sym_with_loc) orelse return null;
- const entry = self.tlv_ptr_entries.items[index];
- return entry.atom_index;
- }
-
/// Returns symbol location corresponding to the set entrypoint.
/// Asserts output mode is executable.
pub fn getEntryPoint(self: Zld) SymbolWithLoc {
@@ -2835,18 +2789,8 @@ pub const Zld = struct {
scoped_log.debug("GOT entries:", .{});
scoped_log.debug("{}", .{self.got_table});
- scoped_log.debug("__thread_ptrs entries:", .{});
- for (self.tlv_ptr_entries.items, 0..) |entry, i| {
- const atom_sym = entry.getAtomSymbol(self);
- const target_sym = entry.getTargetSymbol(self);
- const target_sym_name = entry.getTargetSymbolName(self);
- assert(target_sym.undf());
- scoped_log.debug(" {d}@{x} => import('{s}')", .{
- i,
- atom_sym.n_value,
- target_sym_name,
- });
- }
+ scoped_log.debug("TLV pointers:", .{});
+ scoped_log.debug("{}", .{self.tlv_ptr_table});
scoped_log.debug("stubs entries:", .{});
for (self.stubs.items, 0..) |entry, i| {
@@ -3435,7 +3379,10 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
}
try zld.writeAtoms();
- try zld.writeGotEntries();
+
+ if (zld.got_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.got_table);
+ if (zld.tlv_ptr_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.tlv_ptr_table);
+
try eh_frame.write(&zld, &unwind_info);
try unwind_info.write(&zld);
try zld.writeLinkeditSegmentData();