authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-08 11:57:14+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log961b463fad37e00fa8a2ca2bbfcb58a2b1d2bea9
treed519b6a8b66c585d0c1ee87175ae4d95044792af
parent7aeedc0912c8218773891ae98a729bb2b1be5231

zld: track symbols defined within TextBlock

in case TextBlock represents an entire section with symbols defined within.

2 files changed, 100 insertions(+), 48 deletions(-)

src/link/MachO/Object.zig+45-27
......@@ -430,17 +430,12 @@ const TextBlockParser = struct {
430430 const block = try self.allocator.create(TextBlock);
431431 errdefer self.allocator.destroy(block);
432432
433 block.* = .{
434 .local_sym_index = senior_nlist.index,
435 .aliases = alias_only_indices,
436 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
437 .code = try self.allocator.dupe(u8, code),
438 .relocs = std.ArrayList(Relocation).init(self.allocator),
439 .rebases = std.ArrayList(u64).init(self.allocator),
440 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
441 .size = size,
442 .alignment = self.section.@"align",
443 };
433 block.* = TextBlock.init(self.allocator);
434 block.local_sym_index = senior_nlist.index;
435 block.aliases = alias_only_indices;
436 block.code = try self.allocator.dupe(u8, code);
437 block.size = size;
438 block.alignment = self.section.@"align";
444439
445440 const relocs = filterRelocs(self.relocs, start_addr, end_addr);
446441 if (relocs.len > 0) {
......@@ -499,16 +494,17 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
499494 _ = try self.file.?.preadAll(raw_relocs, sect.reloff);
500495 const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);
501496
497 // Symbols within this section only.
498 const filtered_nlists = NlistWithIndex.filterInSection(
499 sorted_nlists.items,
500 sect_id + 1,
501 );
502
502503 // Is there any padding between symbols within the section?
503504 const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
504505
505506 next: {
506507 if (is_splittable) blocks: {
507 const filtered_nlists = NlistWithIndex.filterInSection(
508 sorted_nlists.items,
509 sect_id + 1,
510 );
511
512508 if (filtered_nlists.len == 0) break :blocks;
513509
514510 var parser = TextBlockParser{
......@@ -528,7 +524,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
528524 if (reg.file) |file| {
529525 if (file != self) {
530526 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
531 block.deinit(self.allocator);
527 block.deinit();
532528 self.allocator.destroy(block);
533529 continue;
534530 }
......@@ -583,21 +579,43 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
583579 const block = try self.allocator.create(TextBlock);
584580 errdefer self.allocator.destroy(block);
585581
586 block.* = .{
587 .local_sym_index = local_sym_index,
588 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
589 .code = try self.allocator.dupe(u8, code),
590 .relocs = std.ArrayList(Relocation).init(self.allocator),
591 .rebases = std.ArrayList(u64).init(self.allocator),
592 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
593 .size = sect.size,
594 .alignment = sect.@"align",
595 };
582 block.* = TextBlock.init(self.allocator);
583 block.local_sym_index = local_sym_index;
584 block.code = try self.allocator.dupe(u8, code);
585 block.size = sect.size;
586 block.alignment = sect.@"align";
596587
597588 if (relocs.len > 0) {
598589 try self.parseRelocs(zld, relocs, block, 0);
599590 }
600591
592 // Since this is block gets a helper local temporary symbol that didn't exist
593 // in the object file which encompasses the entire section, we need traverse
594 // the filtered symbols and note which symbol is contained within so that
595 // we can properly allocate addresses down the line.
596 // While we're at it, we need to update segment,section mapping of each symbol too.
597 if (filtered_nlists.len > 0) {
598 var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator);
599 defer contained.deinit();
600 try contained.ensureTotalCapacity(filtered_nlists.len);
601
602 for (filtered_nlists) |nlist_with_index| {
603 const sym = self.symbols.items[nlist_with_index.index];
604 assert(sym.payload == .regular);
605 const reg = &sym.payload.regular;
606
607 reg.segment_id = match.seg;
608 reg.section_id = match.sect;
609
610 contained.appendAssumeCapacity(.{
611 .local_sym_index = reg.local_sym_index,
612 .offset = nlist_with_index.nlist.n_value - sect.addr,
613 });
614 }
615
616 block.contained = contained.toOwnedSlice();
617 }
618
601619 // Update target section's metadata
602620 // TODO should we update segment's size here too?
603621 // How does it tie with incremental space allocs?
src/link/MachO/Zld.zig+55-21
......@@ -121,9 +121,11 @@ pub const Output = struct {
121121};
122122
123123pub const TextBlock = struct {
124 allocator: *Allocator,
124125 local_sym_index: u32,
125126 aliases: ?[]u32 = null,
126127 references: std.AutoArrayHashMap(u32, void),
128 contained: ?[]SymbolAtOffset = null,
127129 code: []u8,
128130 relocs: std.ArrayList(Relocation),
129131 size: u64,
......@@ -133,20 +135,42 @@ pub const TextBlock = struct {
133135 next: ?*TextBlock = null,
134136 prev: ?*TextBlock = null,
135137
138 pub const SymbolAtOffset = struct {
139 local_sym_index: u32,
140 offset: u64,
141 };
142
136143 pub const TlvOffset = struct {
137144 local_sym_index: u32,
138145 offset: u64,
139146 };
140147
141 pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
142 if (block.aliases) |aliases| {
143 allocator.free(aliases);
148 pub fn init(allocator: *Allocator) TextBlock {
149 return .{
150 .allocator = allocator,
151 .local_sym_index = undefined,
152 .references = std.AutoArrayHashMap(u32, void).init(allocator),
153 .code = undefined,
154 .relocs = std.ArrayList(Relocation).init(allocator),
155 .size = undefined,
156 .alignment = undefined,
157 .rebases = std.ArrayList(u64).init(allocator),
158 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(allocator),
159 };
160 }
161
162 pub fn deinit(self: *TextBlock) void {
163 if (self.aliases) |aliases| {
164 self.allocator.free(aliases);
165 }
166 self.references.deinit();
167 if (self.contained) |contained| {
168 self.allocator.free(contained);
144169 }
145 block.relocs.deinit();
146 block.references.deinit();
147 block.rebases.deinit();
148 block.tlv_offsets.deinit();
149 allocator.free(block.code);
170 self.allocator.free(self.code);
171 self.relocs.deinit();
172 self.rebases.deinit();
173 self.tlv_offsets.deinit();
150174 }
151175
152176 pub fn print_this(self: *const TextBlock, zld: *Zld) void {
......@@ -164,6 +188,12 @@ pub const TextBlock = struct {
164188 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
165189 }
166190 }
191 if (self.contained) |contained| {
192 log.warn(" | contained symbols:", .{});
193 for (contained) |sym_at_off| {
194 log.warn(" | {}: {}", .{ sym_at_off.offset, zld.locals.items[sym_at_off.local_sym_index] });
195 }
196 }
167197 log.warn(" | code.len = {}", .{self.code.len});
168198 if (self.relocs.items.len > 0) {
169199 log.warn(" | relocations:", .{});
......@@ -1021,10 +1051,20 @@ fn allocateTextBlocks(self: *Zld) !void {
10211051 var base_addr: u64 = sect.addr + sect.size;
10221052
10231053 while (true) {
1054 base_addr -= block.size;
1055
10241056 const sym = self.locals.items[block.local_sym_index];
10251057 assert(sym.payload == .regular);
1026 sym.payload.regular.address = base_addr - block.size;
1027 base_addr -= block.size;
1058 sym.payload.regular.address = base_addr;
1059
1060 // Update each symbol contained within the TextBlock
1061 if (block.contained) |contained| {
1062 for (contained) |sym_at_off| {
1063 const contained_sym = self.locals.items[sym_at_off.local_sym_index];
1064 assert(contained_sym.payload == .regular);
1065 contained_sym.payload.regular.address = base_addr + sym_at_off.offset;
1066 }
1067 }
10281068
10291069 if (block.prev) |prev| {
10301070 block = prev;
......@@ -1476,16 +1516,11 @@ fn resolveSymbols(self: *Zld) !void {
14761516 const block = try self.allocator.create(TextBlock);
14771517 errdefer self.allocator.destroy(block);
14781518
1479 block.* = .{
1480 .local_sym_index = local_sym_index,
1481 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
1482 .code = code,
1483 .relocs = std.ArrayList(Relocation).init(self.allocator),
1484 .rebases = std.ArrayList(u64).init(self.allocator),
1485 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
1486 .size = size,
1487 .alignment = alignment,
1488 };
1519 block.* = TextBlock.init(self.allocator);
1520 block.local_sym_index = local_sym_index;
1521 block.code = code;
1522 block.size = size;
1523 block.alignment = alignment;
14891524
14901525 if (self.blocks.getPtr(match)) |last| {
14911526 last.*.next = block;
......@@ -1907,7 +1942,6 @@ fn addRpaths(self: *Zld, rpaths: []const []const u8) !void {
19071942
19081943fn flush(self: *Zld) !void {
19091944 try self.writeStubHelperCommon();
1910 try self.resolveRelocsAndWriteSections();
19111945
19121946 if (self.common_section_index) |index| {
19131947 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;