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;...@@ -7,6 +7,7 @@ const fs = std.fs;
7const io = std.io;7const io = std.io;
8const log = std.log.scoped(.object);8const log = std.log.scoped(.object);
9const macho = std.macho;9const macho = std.macho;
10const math = std.math;
10const mem = std.mem;11const mem = std.mem;
11const reloc = @import("reloc.zig");12const reloc = @import("reloc.zig");
12const sort = std.sort;13const sort = std.sort;
...@@ -436,7 +437,7 @@ const TextBlockParser = struct {...@@ -436,7 +437,7 @@ const TextBlockParser = struct {
436 .code = try self.allocator.dupe(u8, code),437 .code = try self.allocator.dupe(u8, code),
437 .relocs = std.ArrayList(Relocation).init(self.allocator),438 .relocs = std.ArrayList(Relocation).init(self.allocator),
438 .rebases = std.ArrayList(u64).init(self.allocator),439 .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),
440 .size = size,441 .size = size,
441 .alignment = self.section.@"align",442 .alignment = self.section.@"align",
442 };443 };
...@@ -533,6 +534,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -533,6 +534,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
533 }534 }
534 }535 }
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
536 if (zld.blocks.getPtr(match)) |last| {545 if (zld.blocks.getPtr(match)) |last| {
537 last.*.next = block;546 last.*.next = block;
538 block.prev = last.*;547 block.prev = last.*;
...@@ -580,7 +589,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -580,7 +589,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
580 .code = try self.allocator.dupe(u8, code),589 .code = try self.allocator.dupe(u8, code),
581 .relocs = std.ArrayList(Relocation).init(self.allocator),590 .relocs = std.ArrayList(Relocation).init(self.allocator),
582 .rebases = std.ArrayList(u64).init(self.allocator),591 .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),
584 .size = sect.size,593 .size = sect.size,
585 .alignment = sect.@"align",594 .alignment = sect.@"align",
586 };595 };
...@@ -589,6 +598,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -589,6 +598,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
589 try self.parseRelocs(zld, relocs, block, 0);598 try self.parseRelocs(zld, relocs, block, 0);
590 }599 }
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
592 if (zld.blocks.getPtr(match)) |last| {609 if (zld.blocks.getPtr(match)) |last| {
593 last.*.next = block;610 last.*.next = block;
594 block.prev = last.*;611 block.prev = last.*;
src/link/MachO/Symbol.zig+15
...@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;...@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
10const Dylib = @import("Dylib.zig");10const Dylib = @import("Dylib.zig");
11const Object = @import("Object.zig");11const Object = @import("Object.zig");
12const StringTable = @import("StringTable.zig");12const StringTable = @import("StringTable.zig");
13const Zld = @import("Zld.zig");
1314
14/// Symbol name. Owned slice.15/// Symbol name. Owned slice.
15name: []const u8,16name: []const u8,
...@@ -80,6 +81,20 @@ pub const Regular = struct {...@@ -80,6 +81,20 @@ pub const Regular = struct {
80 }81 }
81 try std.fmt.format(writer, "}}", .{});82 try std.fmt.format(writer, "}}", .{});
82 }83 }
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 }
83};98};
8499
85pub const Tentative = struct {100pub const Tentative = struct {
src/link/MachO/Zld.zig+48-53
...@@ -129,10 +129,15 @@ pub const TextBlock = struct {...@@ -129,10 +129,15 @@ pub const TextBlock = struct {
129 size: u64,129 size: u64,
130 alignment: u32,130 alignment: u32,
131 rebases: std.ArrayList(u64),131 rebases: std.ArrayList(u64),
132 tlv_offsets: std.ArrayList(u64),132 tlv_offsets: std.ArrayList(TlvOffset),
133 next: ?*TextBlock = null,133 next: ?*TextBlock = null,
134 prev: ?*TextBlock = null,134 prev: ?*TextBlock = null,
135135
136 pub const TlvOffset = struct {
137 local_sym_index: u32,
138 offset: u64,
139 };
140
136 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {141 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
137 if (block.aliases) |aliases| {142 if (block.aliases) |aliases| {
138 allocator.free(aliases);143 allocator.free(aliases);
...@@ -281,10 +286,11 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg...@@ -281,10 +286,11 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
281 try self.addRpaths(args.rpaths);286 try self.addRpaths(args.rpaths);
282 try self.addDataInCodeLC();287 try self.addDataInCodeLC();
283 try self.addCodeSignatureLC();288 try self.addCodeSignatureLC();
284 // try self.allocateTextSegment();289 try self.allocateTextSegment();
285 // try self.allocateDataConstSegment();290 try self.allocateDataConstSegment();
286 // try self.allocateDataSegment();291 try self.allocateDataSegment();
287 // self.allocateLinkeditSegment();292 self.allocateLinkeditSegment();
293 try self.allocateTextBlocks();
288294
289 var it = self.blocks.iterator();295 var it = self.blocks.iterator();
290 while (it.next()) |entry| {296 while (it.next()) |entry| {
...@@ -292,6 +298,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg...@@ -292,6 +298,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
292 const sect = seg.sections.items[entry.key_ptr.sect];298 const sect = seg.sections.items[entry.key_ptr.sect];
293299
294 log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });300 log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
301 log.warn("{}", .{sect});
295 entry.value_ptr.*.print(self);302 entry.value_ptr.*.print(self);
296 }303 }
297 return error.TODO;304 return error.TODO;
...@@ -865,14 +872,14 @@ fn sortSections(self: *Zld) !void {...@@ -865,14 +872,14 @@ fn sortSections(self: *Zld) !void {
865 while (it.next()) |entry| {872 while (it.next()) |entry| {
866 const old = entry.key_ptr.*;873 const old = entry.key_ptr.*;
867 const sect = if (old.seg == self.text_segment_cmd_index.?)874 const sect = if (old.seg == self.text_segment_cmd_index.?)
868 text_index_mapping.get(old.sect)875 text_index_mapping.get(old.sect).?
869 else if (old.seg == self.data_const_segment_cmd_index.?)876 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).?
871 else878 else
872 data_index_mapping.get(old.sect);879 data_index_mapping.get(old.sect).?;
873 transient.putAssumeCapacityNoClobber(.{880 transient.putAssumeCapacityNoClobber(.{
874 .seg = old.seg,881 .seg = old.seg,
875 .sect = old.sect,882 .sect = sect,
876 }, entry.value_ptr.*);883 }, entry.value_ptr.*);
877 }884 }
878885
...@@ -880,6 +887,18 @@ fn sortSections(self: *Zld) !void {...@@ -880,6 +887,18 @@ fn sortSections(self: *Zld) !void {
880 self.blocks.deinit(self.allocator);887 self.blocks.deinit(self.allocator);
881 self.blocks = transient;888 self.blocks = transient;
882 }889 }
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 }
883}902}
884903
885fn allocateTextSegment(self: *Zld) !void {904fn allocateTextSegment(self: *Zld) !void {
...@@ -991,50 +1010,26 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {...@@ -991,50 +1010,26 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
991 seg.inner.vmsize = seg_size_aligned;1010 seg.inner.vmsize = seg_size_aligned;
992}1011}
9931012
994fn allocateSymbol(self: *Zld, symbol: *Symbol) !void {1013fn allocateTextBlocks(self: *Zld) !void {
995 const reg = &symbol.payload.regular;1014 var it = self.blocks.iterator();
996 const object = reg.file orelse return;1015 while (it.next()) |entry| {
997 const source_sect = &object.sections.items[reg.section];1016 const match = entry.key_ptr.*;
998 const target_map = source_sect.target_map orelse {1017 var block: *TextBlock = entry.value_ptr.*;
999 log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{1018
1000 segmentName(source_sect.inner),1019 const seg = self.load_commands.items[match.seg].Segment;
1001 sectionName(source_sect.inner),1020 const sect = seg.sections.items[match.sect];
1002 symbol.name,1021 var base_addr: u64 = sect.addr + sect.size;
1003 });1022
1004 return;1023 while (true) {
1005 };1024 const sym = self.locals.items[block.local_sym_index];
10061025 assert(sym.payload == .regular);
1007 const target_seg = self.load_commands.items[target_map.segment_id].Segment;1026 sym.payload.regular.address = base_addr - block.size;
1008 const target_sect = target_seg.sections.items[target_map.section_id];1027 base_addr -= block.size;
1009 const target_addr = target_sect.addr + target_map.offset;1028
1010 const address = reg.address - source_sect.inner.addr + target_addr;1029 if (block.prev) |prev| {
10111030 block = prev;
1012 log.debug("resolving symbol '{s}' at 0x{x}", .{ symbol.name, address });1031 } else break;
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;
1021 }1032 }
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);
1038 }1033 }
1039}1034}
10401035
...@@ -1487,7 +1482,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1487,7 +1482,7 @@ fn resolveSymbols(self: *Zld) !void {
1487 .code = code,1482 .code = code,
1488 .relocs = std.ArrayList(Relocation).init(self.allocator),1483 .relocs = std.ArrayList(Relocation).init(self.allocator),
1489 .rebases = std.ArrayList(u64).init(self.allocator),1484 .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),
1491 .size = size,1486 .size = size,
1492 .alignment = alignment,1487 .alignment = alignment,
1493 };1488 };
src/link/MachO/reloc.zig+4-3
...@@ -674,10 +674,11 @@ pub const Parser = struct {...@@ -674,10 +674,11 @@ pub const Parser = struct {
674 }674 }
675675
676 // TLV is handled via a separate offset mechanism.676 // 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!
679 if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) {677 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 });
681 }682 }
682 },683 },
683 }684 }