mirror of
https://github.com/ziglang/zig.git
synced 2026-01-19 05:45:12 +00:00
macho: save lazy binding info as part of the atom
This commit is contained in:
parent
c12183b608
commit
d19d3342c2
@ -155,9 +155,7 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
|
||||
|
||||
got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *TextBlock) = .{},
|
||||
|
||||
stubs: std.ArrayListUnmanaged(u32) = .{},
|
||||
stubs_map: std.AutoHashMapUnmanaged(u32, u32) = .{},
|
||||
stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},
|
||||
|
||||
error_flags: File.ErrorFlags = File.ErrorFlags{},
|
||||
|
||||
@ -783,27 +781,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
|
||||
|
||||
try self.parseTextBlocks();
|
||||
try self.sortSections();
|
||||
|
||||
for (self.stubs.items) |_| {
|
||||
const stub_helper_atom = try self.createStubHelperAtom();
|
||||
try self.allocateAtomStage1(stub_helper_atom, .{
|
||||
.seg = self.text_segment_cmd_index.?,
|
||||
.sect = self.stub_helper_section_index.?,
|
||||
});
|
||||
|
||||
const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.local_sym_index);
|
||||
try self.allocateAtomStage1(laptr_atom, .{
|
||||
.seg = self.data_segment_cmd_index.?,
|
||||
.sect = self.la_symbol_ptr_section_index.?,
|
||||
});
|
||||
|
||||
const stub_atom = try self.createStubAtom(laptr_atom.local_sym_index);
|
||||
try self.allocateAtomStage1(stub_atom, .{
|
||||
.seg = self.text_segment_cmd_index.?,
|
||||
.sect = self.stubs_section_index.?,
|
||||
});
|
||||
}
|
||||
|
||||
try self.allocateTextSegment();
|
||||
try self.allocateDataConstSegment();
|
||||
try self.allocateDataSegment();
|
||||
@ -2159,7 +2136,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
|
||||
return atom;
|
||||
}
|
||||
|
||||
fn createStubHelperAtom(self: *MachO) !*TextBlock {
|
||||
pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
|
||||
const arch = self.base.options.target.cpu.arch;
|
||||
const stub_size: u4 = switch (arch) {
|
||||
.x86_64 => 10,
|
||||
@ -2225,7 +2202,7 @@ fn createStubHelperAtom(self: *MachO) !*TextBlock {
|
||||
return atom;
|
||||
}
|
||||
|
||||
fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock {
|
||||
pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock {
|
||||
const local_sym_index = @intCast(u32, self.locals.items.len);
|
||||
try self.locals.append(self.base.allocator, .{
|
||||
.n_strx = try self.makeString("lazy_ptr"),
|
||||
@ -2248,11 +2225,15 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock {
|
||||
},
|
||||
});
|
||||
try atom.rebases.append(self.base.allocator, 0);
|
||||
try atom.lazy_bindings.append(self.base.allocator, .{
|
||||
.local_sym_index = lazy_binding_sym_index,
|
||||
.offset = 0,
|
||||
});
|
||||
self.lazy_binding_info_dirty = true;
|
||||
return atom;
|
||||
}
|
||||
|
||||
fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {
|
||||
pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {
|
||||
const arch = self.base.options.target.cpu.arch;
|
||||
const alignment: u2 = switch (arch) {
|
||||
.x86_64 => 0,
|
||||
@ -2661,7 +2642,10 @@ fn resolveSymbols(self: *MachO) !void {
|
||||
break :blk atom;
|
||||
};
|
||||
const laptr_atom = blk: {
|
||||
const atom = try self.createLazyPointerAtom(stub_helper_atom.local_sym_index);
|
||||
const atom = try self.createLazyPointerAtom(
|
||||
stub_helper_atom.local_sym_index,
|
||||
resolv.where_index,
|
||||
);
|
||||
const match = MatchingSection{
|
||||
.seg = self.data_segment_cmd_index.?,
|
||||
.sect = self.la_symbol_ptr_section_index.?,
|
||||
@ -2990,8 +2974,6 @@ fn writeRebaseInfoTableZld(self: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
|
||||
|
||||
const size = try bind.rebaseInfoSize(pointers.items);
|
||||
var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
|
||||
defer self.base.allocator.free(buffer);
|
||||
@ -3067,22 +3049,29 @@ fn writeLazyBindInfoTableZld(self: *MachO) !void {
|
||||
var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
|
||||
defer pointers.deinit();
|
||||
|
||||
if (self.la_symbol_ptr_section_index) |idx| {
|
||||
if (self.la_symbol_ptr_section_index) |sect| blk: {
|
||||
var atom = self.blocks.get(.{
|
||||
.seg = self.data_segment_cmd_index.?,
|
||||
.sect = sect,
|
||||
}) orelse break :blk;
|
||||
const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[idx];
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
|
||||
|
||||
try pointers.ensureUnusedCapacity(self.stubs.items.len);
|
||||
while (true) {
|
||||
const sym = self.locals.items[atom.local_sym_index];
|
||||
const base_offset = sym.n_value - seg.inner.vmaddr;
|
||||
|
||||
for (self.stubs.items) |import_id, i| {
|
||||
const sym = self.undefs.items[import_id];
|
||||
pointers.appendAssumeCapacity(.{
|
||||
.offset = base_offset + i * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
.dylib_ordinal = @divExact(sym.n_desc, macho.N_SYMBOL_RESOLVER),
|
||||
.name = self.getString(sym.n_strx),
|
||||
});
|
||||
for (atom.lazy_bindings.items) |binding| {
|
||||
const bind_sym = self.undefs.items[binding.local_sym_index];
|
||||
try pointers.append(.{
|
||||
.offset = binding.offset + base_offset,
|
||||
.segment_id = self.data_segment_cmd_index.?,
|
||||
.dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
|
||||
.name = self.getString(bind_sym.n_strx),
|
||||
});
|
||||
}
|
||||
if (atom.prev) |prev| {
|
||||
atom = prev;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3245,7 +3234,7 @@ fn writeSymbolTable(self: *MachO) !void {
|
||||
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
|
||||
|
||||
const nstubs = @intCast(u32, self.stubs.items.len);
|
||||
const nstubs = @intCast(u32, self.stubs_map.keys().len);
|
||||
const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
|
||||
|
||||
dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
@ -3266,8 +3255,8 @@ fn writeSymbolTable(self: *MachO) !void {
|
||||
var writer = stream.writer();
|
||||
|
||||
stubs.reserved1 = 0;
|
||||
for (self.stubs.items) |id| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.stubs_map.keys()) |key| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
|
||||
}
|
||||
|
||||
got.reserved1 = nstubs;
|
||||
@ -3283,8 +3272,8 @@ fn writeSymbolTable(self: *MachO) !void {
|
||||
}
|
||||
|
||||
la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
|
||||
for (self.stubs.items) |id| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.stubs_map.keys()) |key| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
|
||||
@ -3301,7 +3290,6 @@ pub fn deinit(self: *MachO) void {
|
||||
|
||||
self.section_ordinals.deinit(self.base.allocator);
|
||||
self.got_entries_map.deinit(self.base.allocator);
|
||||
self.stubs.deinit(self.base.allocator);
|
||||
self.stubs_map.deinit(self.base.allocator);
|
||||
self.strtab_dir.deinit(self.base.allocator);
|
||||
self.strtab.deinit(self.base.allocator);
|
||||
@ -4557,10 +4545,6 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
|
||||
});
|
||||
try self.unresolved.putNoClobber(self.base.allocator, sym_index, .stub);
|
||||
|
||||
const stubs_index = @intCast(u32, self.stubs.items.len);
|
||||
try self.stubs.append(self.base.allocator, sym_index);
|
||||
try self.stubs_map.putNoClobber(self.base.allocator, sym_index, stubs_index);
|
||||
|
||||
return sym_index;
|
||||
}
|
||||
|
||||
@ -4803,7 +4787,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
|
||||
const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
|
||||
|
||||
const nstubs = @intCast(u32, self.stubs.items.len);
|
||||
const nstubs = @intCast(u32, self.stubs_map.keys().len);
|
||||
const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
|
||||
const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);
|
||||
const nindirectsyms = nstubs * 2 + ngot_entries;
|
||||
@ -4825,8 +4809,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
var writer = stream.writer();
|
||||
|
||||
stubs.reserved1 = 0;
|
||||
for (self.stubs.items) |id| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.stubs_map.keys()) |key| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
|
||||
}
|
||||
|
||||
got.reserved1 = nstubs;
|
||||
@ -4842,8 +4826,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
}
|
||||
|
||||
la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
|
||||
for (self.stubs.items) |id| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.stubs_map.keys()) |key| {
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
|
||||
@ -5050,8 +5034,6 @@ fn writeRebaseInfoTable(self: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
|
||||
|
||||
const size = try bind.rebaseInfoSize(pointers.items);
|
||||
var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
|
||||
defer self.base.allocator.free(buffer);
|
||||
@ -5151,22 +5133,29 @@ fn writeLazyBindInfoTable(self: *MachO) !void {
|
||||
var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
|
||||
defer pointers.deinit();
|
||||
|
||||
if (self.la_symbol_ptr_section_index) |idx| {
|
||||
if (self.la_symbol_ptr_section_index) |sect| blk: {
|
||||
var atom = self.blocks.get(.{
|
||||
.seg = self.data_segment_cmd_index.?,
|
||||
.sect = sect,
|
||||
}) orelse break :blk;
|
||||
const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[idx];
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
|
||||
|
||||
try pointers.ensureUnusedCapacity(self.stubs.items.len);
|
||||
while (true) {
|
||||
const sym = self.locals.items[atom.local_sym_index];
|
||||
const base_offset = sym.n_value - seg.inner.vmaddr;
|
||||
|
||||
for (self.stubs.items) |import_id, i| {
|
||||
const sym = self.undefs.items[import_id];
|
||||
pointers.appendAssumeCapacity(.{
|
||||
.offset = base_offset + i * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
.dylib_ordinal = @divExact(sym.n_desc, macho.N_SYMBOL_RESOLVER),
|
||||
.name = self.getString(sym.n_strx),
|
||||
});
|
||||
for (atom.lazy_bindings.items) |binding| {
|
||||
const bind_sym = self.undefs.items[binding.local_sym_index];
|
||||
try pointers.append(.{
|
||||
.offset = binding.offset + base_offset,
|
||||
.segment_id = self.data_segment_cmd_index.?,
|
||||
.dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
|
||||
.name = self.getString(bind_sym.n_strx),
|
||||
});
|
||||
}
|
||||
if (atom.prev) |prev| {
|
||||
atom = prev;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5203,6 +5192,15 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
|
||||
}) orelse return;
|
||||
if (last_atom.local_sym_index == self.stub_preamble_sym_index.?) return;
|
||||
|
||||
// Because we insert lazy binding opcodes in reverse order (from last to the first atom),
|
||||
// we need reverse the order of atom traversal here as well.
|
||||
// TODO figure out a less error prone mechanims for this!
|
||||
var atom = last_atom;
|
||||
while (atom.prev) |prev| {
|
||||
atom = prev;
|
||||
}
|
||||
atom = atom.next.?;
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
var reader = stream.reader();
|
||||
var offsets = std.ArrayList(u32).init(self.base.allocator);
|
||||
@ -5255,7 +5253,6 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
|
||||
else => unreachable,
|
||||
};
|
||||
var buf: [@sizeOf(u32)]u8 = undefined;
|
||||
var atom = last_atom;
|
||||
_ = offsets.pop();
|
||||
while (offsets.popOrNull()) |bind_offset| {
|
||||
const sym = self.locals.items[atom.local_sym_index];
|
||||
@ -5268,8 +5265,8 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
|
||||
});
|
||||
try self.base.file.?.pwriteAll(&buf, file_offset);
|
||||
|
||||
if (atom.prev) |prev| {
|
||||
atom = prev;
|
||||
if (atom.next) |next| {
|
||||
atom = next;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +50,9 @@ rebases: std.ArrayListUnmanaged(u64) = .{},
|
||||
/// symbols (aka proxies aka imports)
|
||||
bindings: std.ArrayListUnmanaged(SymbolAtOffset) = .{},
|
||||
|
||||
/// List of lazy bindings
|
||||
lazy_bindings: std.ArrayListUnmanaged(SymbolAtOffset) = .{},
|
||||
|
||||
/// List of data-in-code entries. This is currently specific to x86_64 only.
|
||||
dices: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
|
||||
|
||||
@ -570,6 +573,7 @@ pub const empty = TextBlock{
|
||||
|
||||
pub fn deinit(self: *TextBlock, allocator: *Allocator) void {
|
||||
self.dices.deinit(allocator);
|
||||
self.lazy_bindings.deinit(allocator);
|
||||
self.bindings.deinit(allocator);
|
||||
self.rebases.deinit(allocator);
|
||||
self.relocs.deinit(allocator);
|
||||
@ -898,9 +902,53 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
|
||||
if (parsed_rel.where != .undef) break :blk;
|
||||
if (context.macho_file.stubs_map.contains(parsed_rel.where_index)) break :blk;
|
||||
|
||||
const stubs_index = @intCast(u32, context.macho_file.stubs.items.len);
|
||||
try context.macho_file.stubs.append(context.allocator, parsed_rel.where_index);
|
||||
try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stubs_index);
|
||||
const stub_helper_atom = try context.macho_file.createStubHelperAtom();
|
||||
const laptr_atom = try context.macho_file.createLazyPointerAtom(
|
||||
stub_helper_atom.local_sym_index,
|
||||
parsed_rel.where_index,
|
||||
);
|
||||
const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index);
|
||||
try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom);
|
||||
|
||||
if (build_options.is_stage1 and context.macho_file.base.options.use_stage1) {
|
||||
try context.macho_file.allocateAtomStage1(stub_helper_atom, .{
|
||||
.seg = context.macho_file.text_segment_cmd_index.?,
|
||||
.sect = context.macho_file.stub_helper_section_index.?,
|
||||
});
|
||||
try context.macho_file.allocateAtomStage1(laptr_atom, .{
|
||||
.seg = context.macho_file.data_segment_cmd_index.?,
|
||||
.sect = context.macho_file.la_symbol_ptr_section_index.?,
|
||||
});
|
||||
try context.macho_file.allocateAtomStage1(stub_atom, .{
|
||||
.seg = context.macho_file.text_segment_cmd_index.?,
|
||||
.sect = context.macho_file.stubs_section_index.?,
|
||||
});
|
||||
} else {
|
||||
{
|
||||
const match = MachO.MatchingSection{
|
||||
.seg = context.macho_file.text_segment_cmd_index.?,
|
||||
.sect = context.macho_file.stub_helper_section_index.?,
|
||||
};
|
||||
_ = try context.macho_file.allocateAtom(stub_helper_atom, match);
|
||||
try context.macho_file.writeAtom(stub_helper_atom, match);
|
||||
}
|
||||
{
|
||||
const match = MachO.MatchingSection{
|
||||
.seg = context.macho_file.data_segment_cmd_index.?,
|
||||
.sect = context.macho_file.la_symbol_ptr_section_index.?,
|
||||
};
|
||||
_ = try context.macho_file.allocateAtom(laptr_atom, match);
|
||||
try context.macho_file.writeAtom(laptr_atom, match);
|
||||
}
|
||||
{
|
||||
const match = MachO.MatchingSection{
|
||||
.seg = context.macho_file.text_segment_cmd_index.?,
|
||||
.sect = context.macho_file.stubs_section_index.?,
|
||||
};
|
||||
_ = try context.macho_file.allocateAtom(stub_atom, match);
|
||||
try context.macho_file.writeAtom(stub_atom, match);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1145,13 +1193,11 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
|
||||
break :blk sym.n_value;
|
||||
},
|
||||
.undef => {
|
||||
const stubs_index = macho_file.stubs_map.get(rel.where_index) orelse {
|
||||
const atom = macho_file.stubs_map.get(rel.where_index) orelse {
|
||||
// TODO verify in TextBlock that the symbol is indeed dynamically bound.
|
||||
break :blk 0; // Dynamically bound by dyld.
|
||||
};
|
||||
const segment = macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment;
|
||||
const stubs = segment.sections.items[macho_file.stubs_section_index.?];
|
||||
break :blk stubs.addr + stubs_index * stubs.reserved2;
|
||||
break :blk macho_file.locals.items[atom.local_sym_index].n_value;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -9,15 +9,6 @@ pub const Pointer = struct {
|
||||
name: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub fn pointerCmp(context: void, a: Pointer, b: Pointer) bool {
|
||||
_ = context;
|
||||
if (a.segment_id < b.segment_id) return true;
|
||||
if (a.segment_id == b.segment_id) {
|
||||
return a.offset < b.offset;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn rebaseInfoSize(pointers: []const Pointer) !u64 {
|
||||
var stream = std.io.countingWriter(std.io.null_writer);
|
||||
var writer = stream.writer();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user