zld: move tracking binding for proxies into TextBlock

which is the source of binding rather than its target. That is,
we now track by source.
This commit is contained in:
Jakub Konka 2021-07-15 06:47:13 +02:00
parent 0135b46659
commit ec874a9b2b
3 changed files with 44 additions and 48 deletions

View File

@ -121,20 +121,11 @@ pub const Tentative = struct {
};
pub const Proxy = struct {
/// Dynamic binding info - spots within the final
/// executable where this proxy is referenced from.
bind_info: std.ArrayListUnmanaged(struct {
local_sym_index: u32,
offset: u32,
}) = .{},
/// Dylib where to locate this symbol.
/// null means self-reference.
file: ?*Dylib = null,
pub fn deinit(proxy: *Proxy, allocator: *Allocator) void {
proxy.bind_info.deinit(allocator);
}
local_sym_index: u32 = 0,
pub fn dylibOrdinal(proxy: Proxy) u16 {
const dylib = proxy.file orelse return 0;
@ -145,13 +136,10 @@ pub const Proxy = struct {
_ = fmt;
_ = options;
try std.fmt.format(writer, "Proxy {{ ", .{});
if (self.bind_info.items.len > 0) {
// TODO
try std.fmt.format(writer, ".bind_info = {}, ", .{self.bind_info.items.len});
}
if (self.file) |file| {
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
}
try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index});
try std.fmt.format(writer, "}}", .{});
}
};
@ -284,11 +272,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
pub fn deinit(symbol: *Symbol, allocator: *Allocator) void {
allocator.free(symbol.name);
switch (symbol.payload) {
.proxy => |*proxy| proxy.deinit(allocator),
else => {},
}
}
pub fn isStab(sym: macho.nlist_64) bool {

View File

@ -136,6 +136,7 @@ pub const TextBlock = struct {
size: u64,
alignment: u32,
rebases: std.ArrayList(u64),
bindings: std.ArrayList(SymbolAtOffset),
dices: std.ArrayList(macho.data_in_code_entry),
next: ?*TextBlock = null,
prev: ?*TextBlock = null,
@ -226,6 +227,7 @@ pub const TextBlock = struct {
.size = undefined,
.alignment = undefined,
.rebases = std.ArrayList(u64).init(allocator),
.bindings = std.ArrayList(SymbolAtOffset).init(allocator),
.dices = std.ArrayList(macho.data_in_code_entry).init(allocator),
};
}
@ -239,6 +241,7 @@ pub const TextBlock = struct {
self.allocator.free(self.code);
self.relocs.deinit();
self.rebases.deinit();
self.bindings.deinit();
self.dices.deinit();
}
@ -293,6 +296,9 @@ pub const TextBlock = struct {
if (self.rebases.items.len > 0) {
log.warn(" rebases: {any}", .{self.rebases.items});
}
if (self.bindings.items.len > 0) {
log.warn(" bindings: {any}", .{self.bindings.items});
}
if (self.dices.items.len > 0) {
log.warn(" dices: {any}", .{self.dices.items});
}
@ -1745,9 +1751,11 @@ fn resolveSymbols(self: *Zld) !void {
if (!dylib.symbols.contains(symbol.name)) continue;
try referenced.put(dylib, {});
const index = @intCast(u32, self.imports.items.len);
symbol.payload = .{
.proxy = .{
.file = dylib,
.local_sym_index = index,
},
};
try self.imports.append(self.allocator, symbol);
@ -2341,23 +2349,37 @@ fn writeBindInfoTable(self: *Zld) !void {
}
}
for (self.globals.values()) |sym| {
if (sym.payload != .proxy) continue;
{
var it = self.blocks.iterator();
while (it.next()) |entry| {
const match = entry.key_ptr.*;
var block: *TextBlock = entry.value_ptr.*;
const proxy = sym.payload.proxy;
for (proxy.bind_info.items) |info| {
const bind_sym = self.locals.items[info.local_sym_index];
assert(bind_sym.payload == .regular);
const reg = bind_sym.payload.regular;
const base_address = self.load_commands.items[reg.segment_id].Segment.inner.vmaddr;
const offset = reg.address + info.offset - base_address;
if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
try pointers.append(.{
.offset = offset,
.segment_id = reg.segment_id,
.dylib_ordinal = proxy.dylibOrdinal(),
.name = sym.name,
});
const seg = self.load_commands.items[match.seg].Segment;
while (true) {
const sym = self.locals.items[block.local_sym_index];
assert(sym.payload == .regular);
const base_offset = sym.payload.regular.address - seg.inner.vmaddr;
for (block.bindings.items) |binding| {
const bind_sym = self.imports.items[binding.local_sym_index];
const proxy = bind_sym.payload.proxy;
try pointers.append(.{
.offset = binding.offset + base_offset,
.segment_id = match.seg,
.dylib_ordinal = proxy.dylibOrdinal(),
.name = bind_sym.name,
});
}
if (block.prev) |prev| {
block = prev;
} else break;
}
}
}

View File

@ -449,22 +449,13 @@ pub const Relocation = struct {
.proxy => |proxy| {
if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) {
break :blk 0; // Dynamically bound by dyld.
// const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
// const tlv = segment.sections.items[zld.tlv_section_index.?];
// break :blk tlv.addr;
}
const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
const stubs = segment.sections.items[zld.stubs_section_index.?];
const stubs_index = self.target.stubs_index orelse {
if (proxy.bind_info.items.len > 0) {
break :blk 0; // Dynamically bound by dyld.
}
log.err("expected stubs index or dynamic bind address for symbol '{s}'", .{
self.target.name,
});
log.err(" this is an internal linker error", .{});
return error.FailedToResolveRelocationTarget;
// TODO verify in TextBlock that the symbol is indeed dynamically bound.
break :blk 0; // Dynamically bound by dyld.
};
break :blk stubs.addr + stubs_index * stubs.reserved2;
},
@ -647,9 +638,9 @@ pub const Parser = struct {
} else if (out_rel.payload == .unsigned) {
const sym = out_rel.target;
switch (sym.payload) {
.proxy => {
try sym.payload.proxy.bind_info.append(self.zld.allocator, .{
.local_sym_index = self.block.local_sym_index,
.proxy => |proxy| {
try self.block.bindings.append(.{
.local_sym_index = proxy.local_sym_index,
.offset = out_rel.offset,
});
},