aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/link/MachO/Object.zig2
-rw-r--r--src/link/MachO/Zld.zig138
-rw-r--r--src/link/MachO/reloc.zig28
3 files changed, 149 insertions, 19 deletions
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index e8c619e86e..e7189d1f1b 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -207,7 +207,7 @@ pub fn parseSections(self: *Object) !void {
};
// Parse relocations
- var relocs: ?[]*Relocation = if (sect.nreloc > 0) relocs: {
+ section.relocs = if (sect.nreloc > 0) relocs: {
var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);
defer self.allocator.free(raw_relocs);
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig
index 16f5fbf693..62d88cd489 100644
--- a/src/link/MachO/Zld.zig
+++ b/src/link/MachO/Zld.zig
@@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
const GotEntry = struct {
+ tag: enum {
+ local,
+ import,
+ },
index: u32,
target_addr: u64,
+ file: u16,
+ local_index: u32,
};
const MappingKey = struct {
@@ -273,7 +279,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
try self.allocateDataSegment();
self.allocateLinkeditSegment();
try self.allocateSymbols();
- self.printSymtab();
+ try self.allocateStubsAndGotEntries();
+ self.printDebug();
// try self.writeStubHelperCommon();
// try self.resolveRelocsAndWriteSections();
// try self.flush();
@@ -957,7 +964,7 @@ fn allocateSymbols(self: *Zld) !void {
const target_addr = target_sect.addr + target_mapping.offset;
const n_value = source_sym.inner.n_value - source_sect.addr + target_addr;
- log.warn("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value });
+ log.debug("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value });
// TODO there might be a more generic way of doing this.
var n_sect: u8 = 0;
@@ -979,6 +986,41 @@ fn allocateSymbols(self: *Zld) !void {
}
}
+fn allocateStubsAndGotEntries(self: *Zld) !void {
+ for (self.got_entries.items()) |*entry| {
+ if (entry.value.tag == .import) continue;
+
+ const object = self.objects.items[entry.value.file];
+ const sym = object.symtab.items[entry.value.local_index];
+ const sym_name = object.getString(sym.inner.n_strx);
+ assert(mem.eql(u8, sym_name, entry.key));
+
+ // TODO clean this up
+ entry.value.target_addr = target_addr: {
+ if (sym.tag != .Local) {
+ const glob = self.symtab.get(sym_name) orelse unreachable;
+ break :target_addr glob.inner.n_value;
+ }
+
+ const target_mapping = self.mappings.get(.{
+ .object_id = entry.value.file,
+ .source_sect_id = sym.inner.n_sect - 1,
+ }) orelse unreachable;
+ const source_sect = object.sections.items[target_mapping.source_sect_id];
+ const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
+ const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
+ const target_sect_addr = target_sect.addr + target_mapping.offset;
+
+ break :target_addr target_sect_addr + sym.inner.n_value - source_sect.inner.addr;
+ };
+
+ log.warn("resolving GOT entry '{s}' at 0x{x}", .{
+ entry.key,
+ entry.value.target_addr,
+ });
+ }
+}
+
fn writeStubHelperCommon(self: *Zld) !void {
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
@@ -1385,9 +1427,85 @@ fn resolveSymbols(self: *Zld) !void {
if (has_unresolved) {
return error.UndefinedSymbolReference;
}
+
+ // Finally put dyld_stub_binder as an Import
+ var name = try self.allocator.dupe(u8, "dyld_stub_binder");
+ try self.symtab.putNoClobber(self.allocator, name, .{
+ .tag = .Import,
+ .inner = .{
+ .n_strx = 0, // This will be populated once we write the string table.
+ .n_type = macho.N_UNDF | macho.N_EXT,
+ .n_sect = 0,
+ .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
+ .n_value = 0,
+ },
+ .file = 0,
+ });
}
-fn resolveStubsAndGotEntries(self: *Zld) !void {}
+fn resolveStubsAndGotEntries(self: *Zld) !void {
+ for (self.objects.items) |object, object_id| {
+ log.debug("\nresolving stubs and got entries from {s}", .{object.name});
+
+ for (object.sections.items) |sect| {
+ const relocs = sect.relocs orelse continue;
+ for (relocs) |reloc| {
+ switch (reloc.@"type") {
+ .unsigned => continue,
+ .got_page, .got_page_off => {
+ const sym = object.symtab.items[reloc.target.symbol];
+ const sym_name = object.getString(sym.inner.n_strx);
+
+ if (self.got_entries.contains(sym_name)) continue;
+
+ const is_import = self.symtab.get(sym_name).?.tag == .Import;
+ var name = try self.allocator.dupe(u8, sym_name);
+ const index = @intCast(u32, self.got_entries.items().len);
+ try self.got_entries.putNoClobber(self.allocator, name, .{
+ .tag = if (is_import) .import else .local,
+ .index = index,
+ .target_addr = 0,
+ .file = if (is_import) 0 else @intCast(u16, object_id),
+ .local_index = if (is_import) 0 else reloc.target.symbol,
+ });
+
+ log.debug(" | found GOT entry {s}: {}", .{ sym_name, self.got_entries.get(sym_name) });
+ },
+ else => {
+ const sym = object.symtab.items[reloc.target.symbol];
+ const sym_name = object.getString(sym.inner.n_strx);
+
+ if (sym.tag != .Undef) continue;
+
+ const in_globals = self.symtab.get(sym_name) orelse unreachable;
+
+ if (in_globals.tag != .Import) continue;
+ if (self.stubs.contains(sym_name)) continue;
+
+ var name = try self.allocator.dupe(u8, sym_name);
+ const index = @intCast(u32, self.stubs.items().len);
+ try self.stubs.putNoClobber(self.allocator, name, index);
+
+ log.debug(" | found stub {s}: {}", .{ sym_name, self.stubs.get(sym_name) });
+ },
+ }
+ }
+ }
+ }
+
+ // Finally, put dyld_stub_binder as the final GOT entry
+ var name = try self.allocator.dupe(u8, "dyld_stub_binder");
+ const index = @intCast(u32, self.got_entries.items().len);
+ try self.got_entries.putNoClobber(self.allocator, name, .{
+ .tag = .import,
+ .index = index,
+ .target_addr = 0,
+ .file = 0,
+ .local_index = 0,
+ });
+
+ log.debug(" | found GOT entry dyld_stub_binder: {}", .{self.got_entries.get("dyld_stub_binder")});
+}
fn resolveRelocsAndWriteSections(self: *Zld) !void {
for (self.objects.items) |object, object_id| {
@@ -2871,9 +2989,21 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool {
return ((group_decode >> 2) == 4);
}
-fn printSymtab(self: Zld) void {
+fn printDebug(self: Zld) void {
log.warn("symtab", .{});
for (self.symtab.items()) |entry| {
log.warn(" | {s} => {any}", .{ entry.key, entry.value });
}
+
+ log.warn("\n", .{});
+ log.warn("GOT entries", .{});
+ for (self.got_entries.items()) |entry| {
+ log.warn(" | {s} => {any}", .{ entry.key, entry.value });
+ }
+
+ log.warn("\n", .{});
+ log.warn("stubs", .{});
+ for (self.stubs.items()) |entry| {
+ log.warn(" | {s} => {any}", .{ entry.key, entry.value });
+ }
}
diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig
index 8dadcb2b1b..187cdfa4ce 100644
--- a/src/link/MachO/reloc.zig
+++ b/src/link/MachO/reloc.zig
@@ -292,12 +292,12 @@ const RelocIterator = struct {
self.index += 1;
if (self.index < self.buffer.len) {
const reloc = self.buffer[@intCast(u64, self.index)];
- log.warn("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
- log.warn(" | offset = {}", .{reloc.r_address});
- log.warn(" | PC = {}", .{reloc.r_pcrel == 1});
- log.warn(" | length = {}", .{reloc.r_length});
- log.warn(" | symbolnum = {}", .{reloc.r_symbolnum});
- log.warn(" | extern = {}", .{reloc.r_extern == 1});
+ log.debug("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
+ log.debug(" | offset = {}", .{reloc.r_address});
+ log.debug(" | PC = {}", .{reloc.r_pcrel == 1});
+ log.debug(" | length = {}", .{reloc.r_length});
+ log.debug(" | symbolnum = {}", .{reloc.r_symbolnum});
+ log.debug(" | extern = {}", .{reloc.r_extern == 1});
return reloc;
}
return null;
@@ -419,7 +419,7 @@ const Parser = struct {
.inst = parsed_inst,
};
- log.warn(" | emitting {}", .{branch});
+ log.debug(" | emitting {}", .{branch});
try parser.parsed.append(&branch.base);
}
@@ -458,7 +458,7 @@ const Parser = struct {
.inst = parsed_inst,
};
- log.warn(" | emitting {}", .{page});
+ log.debug(" | emitting {}", .{page});
break :ptr &page.base;
},
@@ -476,7 +476,7 @@ const Parser = struct {
.inst = parsed_inst,
};
- log.warn(" | emitting {}", .{page});
+ log.debug(" | emitting {}", .{page});
break :ptr &page.base;
},
@@ -494,7 +494,7 @@ const Parser = struct {
.inst = parsed_inst,
};
- log.warn(" | emitting {}", .{page});
+ log.debug(" | emitting {}", .{page});
break :ptr &page.base;
},
@@ -551,7 +551,7 @@ const Parser = struct {
.addend = parser.addend,
};
- log.warn(" | emitting {}", .{page_off});
+ log.debug(" | emitting {}", .{page_off});
try parser.parsed.append(&page_off.base);
}
@@ -588,7 +588,7 @@ const Parser = struct {
},
};
- log.warn(" | emitting {}", .{page_off});
+ log.debug(" | emitting {}", .{page_off});
try parser.parsed.append(&page_off.base);
}
@@ -655,7 +655,7 @@ const Parser = struct {
},
};
- log.warn(" | emitting {}", .{page_off});
+ log.debug(" | emitting {}", .{page_off});
try parser.parsed.append(&page_off.base);
}
@@ -716,7 +716,7 @@ const Parser = struct {
.addend = addend,
};
- log.warn(" | emitting {}", .{unsigned});
+ log.debug(" | emitting {}", .{unsigned});
try parser.parsed.append(&unsigned.base);
}
};