authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-07 10:36:41+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log555b66c25567ab23402e3792bdbe81b7a4e98803
tree7f4dab9ab3c66caf1c4057b46d5dc068f1104bbc
parentdbd2eb7c7f9267e8ae508d0995c1d4c5a3b46309

zld: move should_rebase logic into Symbol


4 files changed, 111 insertions(+), 152 deletions(-)

src/link/MachO/Object.zig+39-19
......@@ -339,6 +339,7 @@ const TextBlockParser = struct {
339339 zld: *Zld,
340340 nlists: []NlistWithIndex,
341341 index: u32 = 0,
342 match: Zld.MatchingSection,
342343
343344 fn peek(self: *TextBlockParser) ?NlistWithIndex {
344345 return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
......@@ -405,6 +406,8 @@ const TextBlockParser = struct {
405406 const senior_nlist = aliases.pop();
406407 const senior_sym = self.zld.locals.items[senior_nlist.index];
407408 assert(senior_sym.payload == .regular);
409 senior_sym.payload.regular.segment_id = self.match.seg;
410 senior_sym.payload.regular.section_id = self.match.sect;
408411
409412 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
410413 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;
......@@ -417,6 +420,11 @@ const TextBlockParser = struct {
417420 try out.ensureTotalCapacity(aliases.items.len);
418421 for (aliases.items) |alias| {
419422 out.appendAssumeCapacity(alias.index);
423
424 const sym = self.zld.locals.items[alias.index];
425 const reg = &sym.payload.regular;
426 reg.segment_id = self.match.seg;
427 reg.section_id = self.match.sect;
420428 }
421429 break :blk out.toOwnedSlice();
422430 } else null;
......@@ -439,6 +447,18 @@ const TextBlockParser = struct {
439447 try self.object.parseRelocs(self.zld, relocs, block, start_addr);
440448 }
441449
450 const is_zerofill = blk: {
451 const tseg = self.zld.load_commands.items[self.match.seg].Segment;
452 const tsect = tseg.sections.items[self.match.sect];
453 const tsect_type = sectionType(tsect);
454 break :blk tsect_type == macho.S_ZEROFILL or
455 tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or
456 tsect_type == macho.S_THREAD_LOCAL_VARIABLES;
457 };
458 if (is_zerofill) {
459 mem.set(u8, block.code, 0);
460 }
461
442462 self.index += 1;
443463
444464 return block;
......@@ -511,28 +531,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
511531 .object = self,
512532 .zld = zld,
513533 .nlists = filtered_nlists,
534 .match = match,
514535 };
515536
516537 while (try parser.next()) |block| {
517 {
518 const sym = zld.locals.items[block.local_sym_index];
519 const reg = &sym.payload.regular;
520 if (reg.file) |file| {
521 if (file != self) {
522 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
523 continue;
524 }
525 }
526 reg.segment_id = match.seg;
527 reg.section_id = match.sect;
528 }
529
530 if (block.aliases) |aliases| {
531 for (aliases) |alias| {
532 const sym = zld.locals.items[alias];
533 const reg = &sym.payload.regular;
534 reg.segment_id = match.seg;
535 reg.section_id = match.sect;
538 const sym = zld.locals.items[block.local_sym_index];
539 const reg = &sym.payload.regular;
540 if (reg.file) |file| {
541 if (file != self) {
542 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
543 continue;
536544 }
537545 }
538546
......@@ -587,6 +595,18 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
587595 try self.parseRelocs(zld, relocs, block, 0);
588596 }
589597
598 const is_zerofill = blk: {
599 const tseg = zld.load_commands.items[match.seg].Segment;
600 const tsect = tseg.sections.items[match.sect];
601 const tsect_type = sectionType(tsect);
602 break :blk tsect_type == macho.S_ZEROFILL or
603 tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or
604 tsect_type == macho.S_THREAD_LOCAL_VARIABLES;
605 };
606 if (is_zerofill) {
607 mem.set(u8, block.code, 0);
608 }
609
590610 if (zld.last_text_block) |last| {
591611 last.next = block;
592612 block.prev = last;
src/link/MachO/Symbol.zig+19-2
......@@ -2,6 +2,7 @@ const Symbol = @This();
22
33const std = @import("std");
44const assert = std.debug.assert;
5const commands = @import("commands.zig");
56const macho = std.macho;
67const mem = std.mem;
78
......@@ -57,6 +58,8 @@ pub const Regular = struct {
5758
5859 local_sym_index: u32 = 0,
5960
61 should_rebase: bool = false,
62
6063 pub const Linkage = enum {
6164 translation_unit,
6265 linkage_unit,
......@@ -74,6 +77,9 @@ pub const Regular = struct {
7477 if (self.weak_ref) {
7578 try std.fmt.format(writer, ".weak_ref, ", .{});
7679 }
80 if (self.should_rebase) {
81 try std.fmt.format(writer, ".should_rebase, ", .{});
82 }
7783 if (self.file) |file| {
7884 try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
7985 }
......@@ -108,8 +114,8 @@ pub const Proxy = struct {
108114 /// Dynamic binding info - spots within the final
109115 /// executable where this proxy is referenced from.
110116 bind_info: std.ArrayListUnmanaged(struct {
111 segment_id: u16,
112 address: u64,
117 local_sym_index: u32,
118 offset: u32,
113119 }) = .{},
114120
115121 /// Dylib where to locate this symbol.
......@@ -198,6 +204,17 @@ pub fn isTemp(symbol: Symbol) bool {
198204 return false;
199205}
200206
207pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool {
208 if (self.payload != .regular) return false;
209
210 const reg = self.payload.regular;
211 const seg = zld.load_command.items[reg.segment_id].Segment;
212 const sect = seg.sections.items[reg.section_id];
213 const sect_type = commands.sectionType(sect);
214
215 return sect_type == macho.S_THREAD_LOCAL_VARIABLES;
216}
217
201218pub fn asNlist(symbol: *Symbol, strtab: *StringTable) !macho.nlist_64 {
202219 const n_strx = try strtab.getOrPut(symbol.name);
203220 const nlist = nlist: {
src/link/MachO/Zld.zig+2-127
......@@ -107,8 +107,6 @@ locals: std.ArrayListUnmanaged(*Symbol) = .{},
107107imports: std.ArrayListUnmanaged(*Symbol) = .{},
108108globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
109109
110threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
111local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
112110stubs: std.ArrayListUnmanaged(*Symbol) = .{},
113111got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
114112
......@@ -197,8 +195,6 @@ pub fn init(allocator: *Allocator) !Zld {
197195}
198196
199197pub fn deinit(self: *Zld) void {
200 self.threadlocal_offsets.deinit(self.allocator);
201 self.local_rebases.deinit(self.allocator);
202198 self.stubs.deinit(self.allocator);
203199 self.got_entries.deinit(self.allocator);
204200
......@@ -225,8 +221,6 @@ pub fn deinit(self: *Zld) void {
225221 }
226222 self.dylibs.deinit(self.allocator);
227223
228 self.globals.deinit(self.allocator);
229
230224 for (self.imports.items) |sym| {
231225 sym.deinit(self.allocator);
232226 self.allocator.destroy(sym);
......@@ -239,6 +233,7 @@ pub fn deinit(self: *Zld) void {
239233 }
240234 self.locals.deinit(self.allocator);
241235
236 self.globals.deinit(self.allocator);
242237 self.strtab.deinit();
243238}
244239
......@@ -290,7 +285,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
290285 // try self.allocateDataSegment();
291286 // self.allocateLinkeditSegment();
292287 // try self.allocateSymbols();
293 // try self.allocateProxyBindAddresses();
294288 // try self.flush();
295289}
296290
......@@ -449,7 +443,7 @@ fn updateMetadata(self: *Zld) !void {
449443 }
450444}
451445
452const MatchingSection = struct {
446pub const MatchingSection = struct {
453447 seg: u16,
454448 sect: u16,
455449};
......@@ -1140,31 +1134,6 @@ fn allocateSymbols(self: *Zld) !void {
11401134 }
11411135}
11421136
1143fn allocateProxyBindAddresses(self: *Zld) !void {
1144 for (self.objects.items) |object| {
1145 for (object.sections.items) |sect| {
1146 const relocs = sect.relocs orelse continue;
1147
1148 for (relocs) |rel| {
1149 if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased
1150 if (rel.target != .symbol) continue;
1151
1152 const sym = object.symbols.items[rel.target.symbol];
1153 if (sym.payload != .proxy) continue;
1154
1155 const target_map = sect.target_map orelse continue;
1156 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1157 const target_sect = target_seg.sections.items[target_map.section_id];
1158
1159 try sym.payload.proxy.bind_info.append(self.allocator, .{
1160 .segment_id = target_map.segment_id,
1161 .address = target_sect.addr + target_map.offset + rel.offset,
1162 });
1163 }
1164 }
1165 }
1166}
1167
11681137fn writeStubHelperCommon(self: *Zld) !void {
11691138 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
11701139 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
......@@ -1748,72 +1717,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
17481717 args.source_source_sect_addr = sect.inner.addr;
17491718 args.source_target_sect_addr = source_sect.inner.addr;
17501719 }
1751
1752 const sect_type = sectionType(target_sect);
1753 const should_rebase = rebase: {
1754 if (!unsigned.is_64bit) break :rebase false;
1755
1756 // TODO actually, a check similar to what dyld is doing, that is, verifying
1757 // that the segment is writable should be enough here.
1758 const is_right_segment = blk: {
1759 if (self.data_segment_cmd_index) |idx| {
1760 if (target_map.segment_id == idx) {
1761 break :blk true;
1762 }
1763 }
1764 if (self.data_const_segment_cmd_index) |idx| {
1765 if (target_map.segment_id == idx) {
1766 break :blk true;
1767 }
1768 }
1769 break :blk false;
1770 };
1771
1772 if (!is_right_segment) break :rebase false;
1773 if (sect_type != macho.S_LITERAL_POINTERS and
1774 sect_type != macho.S_REGULAR)
1775 {
1776 break :rebase false;
1777 }
1778 if (rel.target == .symbol) {
1779 const sym = object.symbols.items[rel.target.symbol];
1780 if (sym.payload == .proxy) {
1781 break :rebase false;
1782 }
1783 }
1784
1785 break :rebase true;
1786 };
1787
1788 if (should_rebase) {
1789 try self.local_rebases.append(self.allocator, .{
1790 .offset = source_addr - target_seg.inner.vmaddr,
1791 .segment_id = target_map.segment_id,
1792 });
1793 }
1794
1795 // TLV is handled via a separate offset mechanism.
1796 // Calculate the offset to the initializer.
1797 if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1798 // TODO we don't want to save offset to tlv_bootstrap
1799 if (mem.eql(u8, object.symbols.items[rel.target.symbol].name, "__tlv_bootstrap")) break :tlv;
1800
1801 const base_addr = blk: {
1802 if (self.tlv_data_section_index) |index| {
1803 const tlv_data = target_seg.sections.items[index];
1804 break :blk tlv_data.addr;
1805 } else {
1806 const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?];
1807 break :blk tlv_bss.addr;
1808 }
1809 };
1810 // Since we require TLV data to always preceed TLV bss section, we calculate
1811 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.
1812 try self.threadlocal_offsets.append(self.allocator, .{
1813 .source_addr = args.source_addr,
1814 .offset = args.target_addr - base_addr,
1815 });
1816 }
18171720 },
18181721 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
18191722 const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
......@@ -1839,34 +1742,6 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
18391742 try rel.resolve(args);
18401743 }
18411744 }
1842
1843 log.debug("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{
1844 segname,
1845 sectname,
1846 object.name,
1847 target_sect_off,
1848 target_sect_off + sect.code.len,
1849 });
1850
1851 if (sectionType(target_sect) == macho.S_ZEROFILL or
1852 sectionType(target_sect) == macho.S_THREAD_LOCAL_ZEROFILL or
1853 sectionType(target_sect) == macho.S_THREAD_LOCAL_VARIABLES)
1854 {
1855 log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{
1856 segmentName(target_sect),
1857 sectionName(target_sect),
1858 target_sect_off,
1859 target_sect_off + sect.code.len,
1860 });
1861
1862 // Zero-out the space
1863 var zeroes = try self.allocator.alloc(u8, sect.code.len);
1864 defer self.allocator.free(zeroes);
1865 mem.set(u8, zeroes, 0);
1866 try self.file.?.pwriteAll(zeroes, target_sect_off);
1867 } else {
1868 try self.file.?.pwriteAll(sect.code, target_sect_off);
1869 }
18701745 }
18711746 }
18721747}
src/link/MachO/reloc.zig+51-4
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const aarch64 = @import("../../codegen/aarch64.zig");
33const assert = std.debug.assert;
4const commands = @import("commands.zig");
45const log = std.log.scoped(.reloc);
56const macho = std.macho;
67const math = std.math;
......@@ -567,14 +568,60 @@ pub const Parser = struct {
567568 const index = @intCast(u32, self.zld.got_entries.items.len);
568569 out_rel.target.got_index = index;
569570 try self.zld.got_entries.append(self.zld.allocator, out_rel.target);
571
570572 log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index });
571 }
573 } else if (out_rel.payload == .unsigned) {
574 const sym = out_rel.target;
575 switch (sym.payload) {
576 .proxy => {
577 try sym.payload.proxy.bind_info.append(self.zld.allocator, .{
578 .local_sym_index = self.block.local_sym_index,
579 .offset = out_rel.offset,
580 });
581 },
582 else => {
583 const source_sym = self.zld.locals.items[self.block.local_sym_index];
584 const source_reg = &source_sym.payload.regular;
585 const seg = self.zld.load_commands.items[source_reg.segment_id].Segment;
586 const sect = seg.sections.items[source_reg.section_id];
587 const sect_type = commands.sectionType(sect);
588
589 const should_rebase = rebase: {
590 if (!out_rel.payload.unsigned.is_64bit) break :rebase false;
591
592 // TODO actually, a check similar to what dyld is doing, that is, verifying
593 // that the segment is writable should be enough here.
594 const is_right_segment = blk: {
595 if (self.zld.data_segment_cmd_index) |idx| {
596 if (source_reg.segment_id == idx) {
597 break :blk true;
598 }
599 }
600 if (self.zld.data_const_segment_cmd_index) |idx| {
601 if (source_reg.segment_id == idx) {
602 break :blk true;
603 }
604 }
605 break :blk false;
606 };
607
608 if (!is_right_segment) break :rebase false;
609 if (sect_type != macho.S_LITERAL_POINTERS and
610 sect_type != macho.S_REGULAR)
611 {
612 break :rebase false;
613 }
572614
573 if (out_rel.payload == .branch) {
615 break :rebase true;
616 };
617 source_reg.should_rebase = should_rebase;
618 },
619 }
620 } else if (out_rel.payload == .branch) blk: {
574621 const sym = out_rel.target;
575622
576 if (sym.stubs_index != null) continue;
577 if (sym.payload != .proxy) continue;
623 if (sym.stubs_index != null) break :blk;
624 if (sym.payload != .proxy) break :blk;
578625
579626 const index = @intCast(u32, self.zld.stubs.items.len);
580627 sym.stubs_index = index;