From e524f43a6fbb5189d24aa42667ababdcd92a2ab2 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 7 Jul 2021 22:15:41 +0200 Subject: [PATCH] zld: save rebase and TLV offset as part of TextBlock instead of as part of the Symbol. This seems to be more optimal way of handling dyld ops in presence of no splittable input sections in object files. --- src/link/MachO/Object.zig | 28 ++++------------------------ src/link/MachO/Symbol.zig | 5 ----- src/link/MachO/Zld.zig | 29 ++++++++++++++++++++--------- src/link/MachO/reloc.zig | 14 ++++++++++++-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 011aca06c379fdbabf6f17ba7e0f6080d5d7f549..f000119edf38a26d069790b5094cc844b1d3cf90 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -435,6 +435,8 @@ const TextBlockParser = struct { .references = std.AutoArrayHashMap(u32, void).init(self.allocator), .code = try self.allocator.dupe(u8, code), .relocs = std.ArrayList(Relocation).init(self.allocator), + .rebases = std.ArrayList(u64).init(self.allocator), + .tlv_offsets = std.ArrayList(u64).init(self.allocator), .size = size, .alignment = self.section.@"align", }; @@ -444,18 +446,6 @@ const TextBlockParser = struct { try self.object.parseRelocs(self.zld, relocs, block, start_addr); } - const is_zerofill = blk: { - const tseg = self.zld.load_commands.items[self.match.seg].Segment; - const tsect = tseg.sections.items[self.match.sect]; - const tsect_type = sectionType(tsect); - break :blk tsect_type == macho.S_ZEROFILL or - tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or - tsect_type == macho.S_THREAD_LOCAL_VARIABLES; - }; - if (is_zerofill) { - mem.set(u8, block.code, 0); - } - self.index += 1; return block; @@ -589,6 +579,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { .references = std.AutoArrayHashMap(u32, void).init(self.allocator), .code = try self.allocator.dupe(u8, code), .relocs = std.ArrayList(Relocation).init(self.allocator), + .rebases = std.ArrayList(u64).init(self.allocator), + .tlv_offsets = std.ArrayList(u64).init(self.allocator), .size = sect.size, .alignment = sect.@"align", }; @@ -597,18 +589,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { try self.parseRelocs(zld, relocs, block, 0); } - const is_zerofill = blk: { - const tseg = zld.load_commands.items[match.seg].Segment; - const tsect = tseg.sections.items[match.sect]; - const tsect_type = sectionType(tsect); - break :blk tsect_type == macho.S_ZEROFILL or - tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or - tsect_type == macho.S_THREAD_LOCAL_VARIABLES; - }; - if (is_zerofill) { - mem.set(u8, block.code, 0); - } - if (zld.blocks.getPtr(match)) |last| { last.*.next = block; block.prev = last.*; diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 5f437dc209274f546b88c6867eb9df463d941aa6..86624653f5871de9ebfed4c47fe720c7283c889f 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -58,8 +58,6 @@ pub const Regular = struct { local_sym_index: u32 = 0, - should_rebase: bool = false, - pub const Linkage = enum { translation_unit, linkage_unit, @@ -77,9 +75,6 @@ pub const Regular = struct { if (self.weak_ref) { try std.fmt.format(writer, ".weak_ref, ", .{}); } - if (self.should_rebase) { - try std.fmt.format(writer, ".should_rebase, ", .{}); - } if (self.file) |file| { try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 485f6eda42a916c7cf0e68abfe97473cbc089a48..53bb31a718a9543d338930868e166e4ac7ec910e 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -128,6 +128,8 @@ pub const TextBlock = struct { relocs: std.ArrayList(Relocation), size: u64, alignment: u32, + rebases: std.ArrayList(u64), + tlv_offsets: std.ArrayList(u64), next: ?*TextBlock = null, prev: ?*TextBlock = null, @@ -137,6 +139,8 @@ pub const TextBlock = struct { } block.relocs.deinit(); block.references.deinit(); + block.rebases.deinit(); + block.tlv_offsets.deinit(); allocator.free(block.code); } @@ -144,24 +148,30 @@ pub const TextBlock = struct { log.warn("TextBlock", .{}); log.warn(" | {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] }); if (self.aliases) |aliases| { - log.warn(" | Aliases:", .{}); + log.warn(" | aliases:", .{}); for (aliases) |index| { log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); } } if (self.references.count() > 0) { - log.warn(" | References:", .{}); + log.warn(" | references:", .{}); for (self.references.keys()) |index| { log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); } } log.warn(" | code.len = {}", .{self.code.len}); if (self.relocs.items.len > 0) { - log.warn("Relocations:", .{}); + log.warn(" | relocations:", .{}); for (self.relocs.items) |rel| { - log.warn(" | {}", .{rel}); + log.warn(" | {}", .{rel}); } } + if (self.rebases.items.len > 0) { + log.warn(" | rebases: {any}", .{self.rebases.items}); + } + if (self.tlv_offsets.items.len > 0) { + log.warn(" | TLV offsets: {any}", .{self.tlv_offsets.items}); + } log.warn(" | size = {}", .{self.size}); log.warn(" | align = {}", .{self.alignment}); } @@ -271,6 +281,10 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg try self.addRpaths(args.rpaths); try self.addDataInCodeLC(); try self.addCodeSignatureLC(); + // try self.allocateTextSegment(); + // try self.allocateDataConstSegment(); + // try self.allocateDataSegment(); + // self.allocateLinkeditSegment(); var it = self.blocks.iterator(); while (it.next()) |entry| { @@ -281,11 +295,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg entry.value_ptr.*.print(self); } return error.TODO; - // try self.allocateTextSegment(); - // try self.allocateDataConstSegment(); - // try self.allocateDataSegment(); - // self.allocateLinkeditSegment(); - // try self.allocateSymbols(); // try self.flush(); } @@ -1477,6 +1486,8 @@ fn resolveSymbols(self: *Zld) !void { .references = std.AutoArrayHashMap(u32, void).init(self.allocator), .code = code, .relocs = std.ArrayList(Relocation).init(self.allocator), + .rebases = std.ArrayList(u64).init(self.allocator), + .tlv_offsets = std.ArrayList(u64).init(self.allocator), .size = size, .alignment = alignment, }; diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index d35344c71b3a4fdfd6074dc2e9523bccc974082d..b645ec152e15ed4eb8b249fee00f7a09a829c6df 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -405,7 +405,7 @@ pub const Relocation = struct { pub fn resolve(self: Relocation, zld: *Zld) !void { const source_addr = blk: { const sym = zld.locals.items[self.block.local_sym_index]; - break :blk sym.payload.regular.address; + break :blk sym.payload.regular.address + self.offset; }; const target_addr = blk: { const is_via_got = inner: { @@ -668,7 +668,17 @@ pub const Parser = struct { break :rebase true; }; - source_reg.should_rebase = should_rebase; + + if (should_rebase) { + try self.block.rebases.append(out_rel.offset); + } + + // TLV is handled via a separate offset mechanism. + // Save the offset to the initializer. + // TODO I believe this can be simplified a lot! + if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) { + try self.block.tlv_offsets.append(out_rel.offset); + } }, } } else if (out_rel.payload == .branch) blk: { -- 2.54.0