| author | |
| committer | |
| log | 961b463fad37e00fa8a2ca2bbfcb58a2b1d2bea9 |
| tree | d519b6a8b66c585d0c1ee87175ae4d95044792af |
| parent | 7aeedc0912c8218773891ae98a729bb2b1be5231 |
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 { | ... | @@ -430,17 +430,12 @@ const TextBlockParser = struct { |
| 430 | const block = try self.allocator.create(TextBlock); | 430 | const block = try self.allocator.create(TextBlock); |
| 431 | errdefer self.allocator.destroy(block); | 431 | errdefer self.allocator.destroy(block); |
| 432 | 432 | ||
| 433 | block.* = .{ | 433 | block.* = TextBlock.init(self.allocator); |
| 434 | .local_sym_index = senior_nlist.index, | 434 | block.local_sym_index = senior_nlist.index; |
| 435 | .aliases = alias_only_indices, | 435 | block.aliases = alias_only_indices; |
| 436 | .references = std.AutoArrayHashMap(u32, void).init(self.allocator), | 436 | block.code = try self.allocator.dupe(u8, code); |
| 437 | .code = try self.allocator.dupe(u8, code), | 437 | block.size = size; |
| 438 | .relocs = std.ArrayList(Relocation).init(self.allocator), | 438 | block.alignment = self.section.@"align"; |
| 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 | }; | ||
| 444 | 439 | ||
| 445 | const relocs = filterRelocs(self.relocs, start_addr, end_addr); | 440 | const relocs = filterRelocs(self.relocs, start_addr, end_addr); |
| 446 | if (relocs.len > 0) { | 441 | if (relocs.len > 0) { |
| ... | @@ -499,16 +494,17 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -499,16 +494,17 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 499 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); | 494 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); |
| 500 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); | 495 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); |
| 501 | 496 | ||
| 497 | // Symbols within this section only. | ||
| 498 | const filtered_nlists = NlistWithIndex.filterInSection( | ||
| 499 | sorted_nlists.items, | ||
| 500 | sect_id + 1, | ||
| 501 | ); | ||
| 502 | |||
| 502 | // Is there any padding between symbols within the section? | 503 | // Is there any padding between symbols within the section? |
| 503 | const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; | 504 | const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| 504 | 505 | ||
| 505 | next: { | 506 | next: { |
| 506 | if (is_splittable) blocks: { | 507 | if (is_splittable) blocks: { |
| 507 | const filtered_nlists = NlistWithIndex.filterInSection( | ||
| 508 | sorted_nlists.items, | ||
| 509 | sect_id + 1, | ||
| 510 | ); | ||
| 511 | |||
| 512 | if (filtered_nlists.len == 0) break :blocks; | 508 | if (filtered_nlists.len == 0) break :blocks; |
| 513 | 509 | ||
| 514 | var parser = TextBlockParser{ | 510 | var parser = TextBlockParser{ |
| ... | @@ -528,7 +524,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -528,7 +524,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 528 | if (reg.file) |file| { | 524 | if (reg.file) |file| { |
| 529 | if (file != self) { | 525 | if (file != self) { |
| 530 | log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? }); | 526 | log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? }); |
| 531 | block.deinit(self.allocator); | 527 | block.deinit(); |
| 532 | self.allocator.destroy(block); | 528 | self.allocator.destroy(block); |
| 533 | continue; | 529 | continue; |
| 534 | } | 530 | } |
| ... | @@ -583,21 +579,43 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -583,21 +579,43 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 583 | const block = try self.allocator.create(TextBlock); | 579 | const block = try self.allocator.create(TextBlock); |
| 584 | errdefer self.allocator.destroy(block); | 580 | errdefer self.allocator.destroy(block); |
| 585 | 581 | ||
| 586 | block.* = .{ | 582 | block.* = TextBlock.init(self.allocator); |
| 587 | .local_sym_index = local_sym_index, | 583 | block.local_sym_index = local_sym_index; |
| 588 | .references = std.AutoArrayHashMap(u32, void).init(self.allocator), | 584 | block.code = try self.allocator.dupe(u8, code); |
| 589 | .code = try self.allocator.dupe(u8, code), | 585 | block.size = sect.size; |
| 590 | .relocs = std.ArrayList(Relocation).init(self.allocator), | 586 | block.alignment = sect.@"align"; |
| 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 | }; | ||
| 596 | 587 | ||
| 597 | if (relocs.len > 0) { | 588 | if (relocs.len > 0) { |
| 598 | try self.parseRelocs(zld, relocs, block, 0); | 589 | try self.parseRelocs(zld, relocs, block, 0); |
| 599 | } | 590 | } |
| 600 | 591 | ||
| 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 | |||
| 601 | // Update target section's metadata | 619 | // Update target section's metadata |
| 602 | // TODO should we update segment's size here too? | 620 | // TODO should we update segment's size here too? |
| 603 | // How does it tie with incremental space allocs? | 621 | // How does it tie with incremental space allocs? |
src/link/MachO/Zld.zig+55-21| ... | @@ -121,9 +121,11 @@ pub const Output = struct { | ... | @@ -121,9 +121,11 @@ pub const Output = struct { |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | pub const TextBlock = struct { | 123 | pub const TextBlock = struct { |
| 124 | allocator: *Allocator, | ||
| 124 | local_sym_index: u32, | 125 | local_sym_index: u32, |
| 125 | aliases: ?[]u32 = null, | 126 | aliases: ?[]u32 = null, |
| 126 | references: std.AutoArrayHashMap(u32, void), | 127 | references: std.AutoArrayHashMap(u32, void), |
| 128 | contained: ?[]SymbolAtOffset = null, | ||
| 127 | code: []u8, | 129 | code: []u8, |
| 128 | relocs: std.ArrayList(Relocation), | 130 | relocs: std.ArrayList(Relocation), |
| 129 | size: u64, | 131 | size: u64, |
| ... | @@ -133,20 +135,42 @@ pub const TextBlock = struct { | ... | @@ -133,20 +135,42 @@ pub const TextBlock = struct { |
| 133 | next: ?*TextBlock = null, | 135 | next: ?*TextBlock = null, |
| 134 | prev: ?*TextBlock = null, | 136 | prev: ?*TextBlock = null, |
| 135 | 137 | ||
| 138 | pub const SymbolAtOffset = struct { | ||
| 139 | local_sym_index: u32, | ||
| 140 | offset: u64, | ||
| 141 | }; | ||
| 142 | |||
| 136 | pub const TlvOffset = struct { | 143 | pub const TlvOffset = struct { |
| 137 | local_sym_index: u32, | 144 | local_sym_index: u32, |
| 138 | offset: u64, | 145 | offset: u64, |
| 139 | }; | 146 | }; |
| 140 | 147 | ||
| 141 | pub fn deinit(block: *TextBlock, allocator: *Allocator) void { | 148 | pub fn init(allocator: *Allocator) TextBlock { |
| 142 | if (block.aliases) |aliases| { | 149 | return .{ |
| 143 | allocator.free(aliases); | 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); | ||
| 144 | } | 169 | } |
| 145 | block.relocs.deinit(); | 170 | self.allocator.free(self.code); |
| 146 | block.references.deinit(); | 171 | self.relocs.deinit(); |
| 147 | block.rebases.deinit(); | 172 | self.rebases.deinit(); |
| 148 | block.tlv_offsets.deinit(); | 173 | self.tlv_offsets.deinit(); |
| 149 | allocator.free(block.code); | ||
| 150 | } | 174 | } |
| 151 | 175 | ||
| 152 | pub fn print_this(self: *const TextBlock, zld: *Zld) void { | 176 | pub fn print_this(self: *const TextBlock, zld: *Zld) void { |
| ... | @@ -164,6 +188,12 @@ pub const TextBlock = struct { | ... | @@ -164,6 +188,12 @@ pub const TextBlock = struct { |
| 164 | log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); | 188 | log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); |
| 165 | } | 189 | } |
| 166 | } | 190 | } |
| 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 | } | ||
| 167 | log.warn(" | code.len = {}", .{self.code.len}); | 197 | log.warn(" | code.len = {}", .{self.code.len}); |
| 168 | if (self.relocs.items.len > 0) { | 198 | if (self.relocs.items.len > 0) { |
| 169 | log.warn(" | relocations:", .{}); | 199 | log.warn(" | relocations:", .{}); |
| ... | @@ -1021,10 +1051,20 @@ fn allocateTextBlocks(self: *Zld) !void { | ... | @@ -1021,10 +1051,20 @@ fn allocateTextBlocks(self: *Zld) !void { |
| 1021 | var base_addr: u64 = sect.addr + sect.size; | 1051 | var base_addr: u64 = sect.addr + sect.size; |
| 1022 | 1052 | ||
| 1023 | while (true) { | 1053 | while (true) { |
| 1054 | base_addr -= block.size; | ||
| 1055 | |||
| 1024 | const sym = self.locals.items[block.local_sym_index]; | 1056 | const sym = self.locals.items[block.local_sym_index]; |
| 1025 | assert(sym.payload == .regular); | 1057 | assert(sym.payload == .regular); |
| 1026 | sym.payload.regular.address = base_addr - block.size; | 1058 | sym.payload.regular.address = base_addr; |
| 1027 | base_addr -= block.size; | 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 | } | ||
| 1028 | 1068 | ||
| 1029 | if (block.prev) |prev| { | 1069 | if (block.prev) |prev| { |
| 1030 | block = prev; | 1070 | block = prev; |
| ... | @@ -1476,16 +1516,11 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1476,16 +1516,11 @@ fn resolveSymbols(self: *Zld) !void { |
| 1476 | const block = try self.allocator.create(TextBlock); | 1516 | const block = try self.allocator.create(TextBlock); |
| 1477 | errdefer self.allocator.destroy(block); | 1517 | errdefer self.allocator.destroy(block); |
| 1478 | 1518 | ||
| 1479 | block.* = .{ | 1519 | block.* = TextBlock.init(self.allocator); |
| 1480 | .local_sym_index = local_sym_index, | 1520 | block.local_sym_index = local_sym_index; |
| 1481 | .references = std.AutoArrayHashMap(u32, void).init(self.allocator), | 1521 | block.code = code; |
| 1482 | .code = code, | 1522 | block.size = size; |
| 1483 | .relocs = std.ArrayList(Relocation).init(self.allocator), | 1523 | block.alignment = alignment; |
| 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 | }; | ||
| 1489 | 1524 | ||
| 1490 | if (self.blocks.getPtr(match)) |last| { | 1525 | if (self.blocks.getPtr(match)) |last| { |
| 1491 | last.*.next = block; | 1526 | last.*.next = block; |
| ... | @@ -1907,7 +1942,6 @@ fn addRpaths(self: *Zld, rpaths: []const []const u8) !void { | ... | @@ -1907,7 +1942,6 @@ fn addRpaths(self: *Zld, rpaths: []const []const u8) !void { |
| 1907 | 1942 | ||
| 1908 | fn flush(self: *Zld) !void { | 1943 | fn flush(self: *Zld) !void { |
| 1909 | try self.writeStubHelperCommon(); | 1944 | try self.writeStubHelperCommon(); |
| 1910 | try self.resolveRelocsAndWriteSections(); | ||
| 1911 | 1945 | ||
| 1912 | if (self.common_section_index) |index| { | 1946 | if (self.common_section_index) |index| { |
| 1913 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 1947 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |