authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-08 00:29:10+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log7aeedc0912c8218773891ae98a729bb2b1be5231
treeb0e10d2876e1673e3da773fb3c73668b27b4f786
parente524f43a6fbb5189d24aa42667ababdcd92a2ab2

zld: allocate TextBlocks

temporarily by iterating over all defined TextBlocks. However, once we merge this with MachO incremental, updates will be done at the point of creation and/or update. Also, fix mining TLV knowledge for working out TLV pointers.

4 files changed, 86 insertions(+), 58 deletions(-)

src/link/MachO/Object.zig+19-2
......@@ -7,6 +7,7 @@ const fs = std.fs;
77const io = std.io;
88const log = std.log.scoped(.object);
99const macho = std.macho;
10const math = std.math;
1011const mem = std.mem;
1112const reloc = @import("reloc.zig");
1213const sort = std.sort;
......@@ -436,7 +437,7 @@ const TextBlockParser = struct {
436437 .code = try self.allocator.dupe(u8, code),
437438 .relocs = std.ArrayList(Relocation).init(self.allocator),
438439 .rebases = std.ArrayList(u64).init(self.allocator),
439 .tlv_offsets = std.ArrayList(u64).init(self.allocator),
440 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
440441 .size = size,
441442 .alignment = self.section.@"align",
442443 };
......@@ -533,6 +534,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
533534 }
534535 }
535536
537 // Update target section's metadata
538 // TODO should we update segment's size here too?
539 // How does it tie with incremental space allocs?
540 const tseg = &zld.load_commands.items[match.seg].Segment;
541 const tsect = &tseg.sections.items[match.sect];
542 tsect.size += block.size;
543 tsect.@"align" = math.max(tsect.@"align", block.alignment);
544
536545 if (zld.blocks.getPtr(match)) |last| {
537546 last.*.next = block;
538547 block.prev = last.*;
......@@ -580,7 +589,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
580589 .code = try self.allocator.dupe(u8, code),
581590 .relocs = std.ArrayList(Relocation).init(self.allocator),
582591 .rebases = std.ArrayList(u64).init(self.allocator),
583 .tlv_offsets = std.ArrayList(u64).init(self.allocator),
592 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
584593 .size = sect.size,
585594 .alignment = sect.@"align",
586595 };
......@@ -589,6 +598,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
589598 try self.parseRelocs(zld, relocs, block, 0);
590599 }
591600
601 // Update target section's metadata
602 // TODO should we update segment's size here too?
603 // How does it tie with incremental space allocs?
604 const tseg = &zld.load_commands.items[match.seg].Segment;
605 const tsect = &tseg.sections.items[match.sect];
606 tsect.size += block.size;
607 tsect.@"align" = math.max(tsect.@"align", block.alignment);
608
592609 if (zld.blocks.getPtr(match)) |last| {
593610 last.*.next = block;
594611 block.prev = last.*;
src/link/MachO/Symbol.zig+15
......@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
1010const Dylib = @import("Dylib.zig");
1111const Object = @import("Object.zig");
1212const StringTable = @import("StringTable.zig");
13const Zld = @import("Zld.zig");
1314
1415/// Symbol name. Owned slice.
1516name: []const u8,
......@@ -80,6 +81,20 @@ pub const Regular = struct {
8081 }
8182 try std.fmt.format(writer, "}}", .{});
8283 }
84
85 pub fn sectionId(self: Regular, zld: *Zld) u8 {
86 // TODO there might be a more generic way of doing this.
87 var section: u8 = 0;
88 for (zld.load_commands.items) |cmd, cmd_id| {
89 if (cmd != .Segment) break;
90 if (cmd_id == self.segment_id) {
91 section += @intCast(u8, self.section_id) + 1;
92 break;
93 }
94 section += @intCast(u8, cmd.Segment.sections.items.len);
95 }
96 return section;
97 }
8398};
8499
85100pub const Tentative = struct {
src/link/MachO/Zld.zig+48-53
......@@ -129,10 +129,15 @@ pub const TextBlock = struct {
129129 size: u64,
130130 alignment: u32,
131131 rebases: std.ArrayList(u64),
132 tlv_offsets: std.ArrayList(u64),
132 tlv_offsets: std.ArrayList(TlvOffset),
133133 next: ?*TextBlock = null,
134134 prev: ?*TextBlock = null,
135135
136 pub const TlvOffset = struct {
137 local_sym_index: u32,
138 offset: u64,
139 };
140
136141 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
137142 if (block.aliases) |aliases| {
138143 allocator.free(aliases);
......@@ -281,10 +286,11 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
281286 try self.addRpaths(args.rpaths);
282287 try self.addDataInCodeLC();
283288 try self.addCodeSignatureLC();
284 // try self.allocateTextSegment();
285 // try self.allocateDataConstSegment();
286 // try self.allocateDataSegment();
287 // self.allocateLinkeditSegment();
289 try self.allocateTextSegment();
290 try self.allocateDataConstSegment();
291 try self.allocateDataSegment();
292 self.allocateLinkeditSegment();
293 try self.allocateTextBlocks();
288294
289295 var it = self.blocks.iterator();
290296 while (it.next()) |entry| {
......@@ -292,6 +298,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
292298 const sect = seg.sections.items[entry.key_ptr.sect];
293299
294300 log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
301 log.warn("{}", .{sect});
295302 entry.value_ptr.*.print(self);
296303 }
297304 return error.TODO;
......@@ -865,14 +872,14 @@ fn sortSections(self: *Zld) !void {
865872 while (it.next()) |entry| {
866873 const old = entry.key_ptr.*;
867874 const sect = if (old.seg == self.text_segment_cmd_index.?)
868 text_index_mapping.get(old.sect)
875 text_index_mapping.get(old.sect).?
869876 else if (old.seg == self.data_const_segment_cmd_index.?)
870 data_const_index_mapping.get(old.sect)
877 data_const_index_mapping.get(old.sect).?
871878 else
872 data_index_mapping.get(old.sect);
879 data_index_mapping.get(old.sect).?;
873880 transient.putAssumeCapacityNoClobber(.{
874881 .seg = old.seg,
875 .sect = old.sect,
882 .sect = sect,
876883 }, entry.value_ptr.*);
877884 }
878885
......@@ -880,6 +887,18 @@ fn sortSections(self: *Zld) !void {
880887 self.blocks.deinit(self.allocator);
881888 self.blocks = transient;
882889 }
890
891 for (self.locals.items) |sym, i| {
892 if (i == 0) continue; // skip the null symbol
893 assert(sym.payload == .regular);
894 const reg = &sym.payload.regular;
895 reg.section_id = if (reg.segment_id == self.text_segment_cmd_index.?)
896 text_index_mapping.get(reg.section_id).?
897 else if (reg.segment_id == self.data_const_segment_cmd_index.?)
898 data_const_index_mapping.get(reg.section_id).?
899 else
900 data_index_mapping.get(reg.section_id).?;
901 }
883902}
884903
885904fn allocateTextSegment(self: *Zld) !void {
......@@ -991,50 +1010,26 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
9911010 seg.inner.vmsize = seg_size_aligned;
9921011}
9931012
994fn allocateSymbol(self: *Zld, symbol: *Symbol) !void {
995 const reg = &symbol.payload.regular;
996 const object = reg.file orelse return;
997 const source_sect = &object.sections.items[reg.section];
998 const target_map = source_sect.target_map orelse {
999 log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{
1000 segmentName(source_sect.inner),
1001 sectionName(source_sect.inner),
1002 symbol.name,
1003 });
1004 return;
1005 };
1006
1007 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1008 const target_sect = target_seg.sections.items[target_map.section_id];
1009 const target_addr = target_sect.addr + target_map.offset;
1010 const address = reg.address - source_sect.inner.addr + target_addr;
1011
1012 log.debug("resolving symbol '{s}' at 0x{x}", .{ symbol.name, address });
1013
1014 // TODO there might be a more generic way of doing this.
1015 var section: u8 = 0;
1016 for (self.load_commands.items) |cmd, cmd_id| {
1017 if (cmd != .Segment) break;
1018 if (cmd_id == target_map.segment_id) {
1019 section += @intCast(u8, target_map.section_id) + 1;
1020 break;
1013fn allocateTextBlocks(self: *Zld) !void {
1014 var it = self.blocks.iterator();
1015 while (it.next()) |entry| {
1016 const match = entry.key_ptr.*;
1017 var block: *TextBlock = entry.value_ptr.*;
1018
1019 const seg = self.load_commands.items[match.seg].Segment;
1020 const sect = seg.sections.items[match.sect];
1021 var base_addr: u64 = sect.addr + sect.size;
1022
1023 while (true) {
1024 const sym = self.locals.items[block.local_sym_index];
1025 assert(sym.payload == .regular);
1026 sym.payload.regular.address = base_addr - block.size;
1027 base_addr -= block.size;
1028
1029 if (block.prev) |prev| {
1030 block = prev;
1031 } else break;
10211032 }
1022 section += @intCast(u8, cmd.Segment.sections.items.len);
1023 }
1024
1025 reg.address = address;
1026 reg.section = section;
1027}
1028
1029fn allocateSymbols(self: *Zld) !void {
1030 for (self.locals.items) |symbol| {
1031 if (symbol.payload != .regular) continue;
1032 try self.allocateSymbol(symbol);
1033 }
1034
1035 for (self.globals.values()) |symbol| {
1036 if (symbol.payload != .regular) continue;
1037 try self.allocateSymbol(symbol);
10381033 }
10391034}
10401035
......@@ -1487,7 +1482,7 @@ fn resolveSymbols(self: *Zld) !void {
14871482 .code = code,
14881483 .relocs = std.ArrayList(Relocation).init(self.allocator),
14891484 .rebases = std.ArrayList(u64).init(self.allocator),
1490 .tlv_offsets = std.ArrayList(u64).init(self.allocator),
1485 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
14911486 .size = size,
14921487 .alignment = alignment,
14931488 };
src/link/MachO/reloc.zig+4-3
......@@ -674,10 +674,11 @@ pub const Parser = struct {
674674 }
675675
676676 // TLV is handled via a separate offset mechanism.
677 // Save the offset to the initializer.
678 // TODO I believe this can be simplified a lot!
679677 if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) {
680 try self.block.tlv_offsets.append(out_rel.offset);
678 try self.block.tlv_offsets.append(.{
679 .local_sym_index = out_rel.target.payload.regular.local_sym_index,
680 .offset = out_rel.offset,
681 });
681682 }
682683 },
683684 }