aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-07-15 06:47:13 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-07-15 18:49:47 +0200
commitec874a9b2bf24bb37f1e90558153bbf04ac5f22a (patch)
tree2b8544cf3422b200cde70f9ced99f2207fa00f75 /src/link
parent0135b4665988530c0bd6b36ef7cb93ecaf999776 (diff)
downloadzig-ec874a9b2bf24bb37f1e90558153bbf04ac5f22a.tar.gz
zig-ec874a9b2bf24bb37f1e90558153bbf04ac5f22a.zip
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.
Diffstat (limited to 'src/link')
-rw-r--r--src/link/MachO/Symbol.zig21
-rw-r--r--src/link/MachO/Zld.zig52
-rw-r--r--src/link/MachO/reloc.zig19
3 files changed, 44 insertions, 48 deletions
diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig
index 1c270e8510..28aee6eeb0 100644
--- a/src/link/MachO/Symbol.zig
+++ b/src/link/MachO/Symbol.zig
@@ -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 {
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig
index ce08f6d82d..62e34cb6b0 100644
--- a/src/link/MachO/Zld.zig
+++ b/src/link/MachO/Zld.zig
@@ -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;
+ }
}
}
diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig
index d92d047cd9..c8b176c9c2 100644
--- a/src/link/MachO/reloc.zig
+++ b/src/link/MachO/reloc.zig
@@ -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,
});
},