authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-22 22:19:15+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-22 23:13:13+02:00
loga4feb97cdfb330207f3da05402983bf3a71de64e
treea2afbbb4567f128b4c1785c26d3a5bdb129dc9ce
parent4fd0cb7618ffb5428981672f6a21c411599f51b2

macho: assign and cache section ordinals upon creation

then, when sorting sections within segments, clear and redo the ordinals since we re-apply them to symbols anyway. It is vital to have the ordinals consistent with parsing and resolving relocs however.

3 files changed, 88 insertions(+), 39 deletions(-)

src/link/MachO.zig+83-34
...@@ -167,6 +167,9 @@ strtab_needs_relocation: bool = false,...@@ -167,6 +167,9 @@ strtab_needs_relocation: bool = false,
167has_dices: bool = false,167has_dices: bool = false,
168has_stabs: bool = false,168has_stabs: bool = false,
169169
170section_ordinals: std.ArrayListUnmanaged(MatchingSection) = .{},
171section_to_ordinal: std.AutoHashMapUnmanaged(MatchingSection, u8) = .{},
172
170pending_updates: std.ArrayListUnmanaged(struct {173pending_updates: std.ArrayListUnmanaged(struct {
171 kind: enum {174 kind: enum {
172 got,175 got,
...@@ -925,6 +928,13 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -925,6 +928,13 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
925 else => unreachable,928 else => unreachable,
926 };929 };
927930
931 // Initialize section ordinals with null ordinal pointing at
932 // PAGEZERO segment.
933 try self.section_ordinals.append(self.base.allocator, .{
934 .seg = 0,
935 .sect = 0,
936 });
937
928 try self.populateMetadata();938 try self.populateMetadata();
929 try self.parseInputFiles(positionals.items, self.base.options.sysroot);939 try self.parseInputFiles(positionals.items, self.base.options.sysroot);
930 try self.parseLibs(libs.items, self.base.options.sysroot);940 try self.parseLibs(libs.items, self.base.options.sysroot);
...@@ -1482,6 +1492,10 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1482,6 +1492,10 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1482 }1492 }
1483 };1493 };
14841494
1495 if (res) |match| {
1496 try self.createSectionOrdinal(match);
1497 }
1498
1485 return res;1499 return res;
1486}1500}
14871501
...@@ -1606,6 +1620,38 @@ fn sortSections(self: *MachO) !void {...@@ -1606,6 +1620,38 @@ fn sortSections(self: *MachO) !void {
1606 self.blocks.deinit(self.base.allocator);1620 self.blocks.deinit(self.base.allocator);
1607 self.blocks = transient;1621 self.blocks = transient;
1608 }1622 }
1623
1624 {
1625 // Create new section ordinals.
1626 self.section_ordinals.clearRetainingCapacity();
1627 self.section_to_ordinal.clearRetainingCapacity();
1628 // First ordinal is always null
1629 self.section_ordinals.appendAssumeCapacity(.{
1630 .seg = 0,
1631 .sect = 0,
1632 });
1633 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1634 for (text_seg.sections.items) |_, sect_id| {
1635 try self.createSectionOrdinal(.{
1636 .seg = self.text_segment_cmd_index.?,
1637 .sect = @intCast(u16, sect_id),
1638 });
1639 }
1640 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1641 for (data_const_seg.sections.items) |_, sect_id| {
1642 try self.createSectionOrdinal(.{
1643 .seg = self.data_const_segment_cmd_index.?,
1644 .sect = @intCast(u16, sect_id),
1645 });
1646 }
1647 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1648 for (data_seg.sections.items) |_, sect_id| {
1649 try self.createSectionOrdinal(.{
1650 .seg = self.data_segment_cmd_index.?,
1651 .sect = @intCast(u16, sect_id),
1652 });
1653 }
1654 }
1609}1655}
16101656
1611fn allocateTextSegment(self: *MachO) !void {1657fn allocateTextSegment(self: *MachO) !void {
...@@ -1732,7 +1778,7 @@ fn allocateTextBlocks(self: *MachO) !void {...@@ -1732,7 +1778,7 @@ fn allocateTextBlocks(self: *MachO) !void {
1732 const sect = seg.sections.items[match.sect];1778 const sect = seg.sections.items[match.sect];
17331779
1734 var base_addr: u64 = sect.addr;1780 var base_addr: u64 = sect.addr;
1735 const n_sect = self.sectionId(match);1781 const n_sect = self.section_to_ordinal.get(match) orelse unreachable;
17361782
1737 log.debug(" within section {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });1783 log.debug(" within section {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
1738 log.debug(" {}", .{sect});1784 log.debug(" {}", .{sect});
...@@ -2260,6 +2306,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2260,6 +2306,7 @@ fn resolveSymbols(self: *MachO) !void {
2260 .sect = self.common_section_index.?,2306 .sect = self.common_section_index.?,
2261 };2307 };
2262 };2308 };
2309 try self.createSectionOrdinal(match);
22632310
2264 const size = sym.n_value;2311 const size = sym.n_value;
2265 const code = try self.base.allocator.alloc(u8, size);2312 const code = try self.base.allocator.alloc(u8, size);
...@@ -2272,7 +2319,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2272,7 +2319,7 @@ fn resolveSymbols(self: *MachO) !void {
2272 var nlist = macho.nlist_64{2319 var nlist = macho.nlist_64{
2273 .n_strx = sym.n_strx,2320 .n_strx = sym.n_strx,
2274 .n_type = macho.N_SECT,2321 .n_type = macho.N_SECT,
2275 .n_sect = self.sectionId(match),2322 .n_sect = self.section_to_ordinal.get(match) orelse unreachable,
2276 .n_desc = 0,2323 .n_desc = 0,
2277 .n_value = 0,2324 .n_value = 0,
2278 };2325 };
...@@ -2402,7 +2449,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2402,7 +2449,7 @@ fn resolveSymbols(self: *MachO) !void {
2402 var nlist = macho.nlist_64{2449 var nlist = macho.nlist_64{
2403 .n_strx = undef.n_strx,2450 .n_strx = undef.n_strx,
2404 .n_type = macho.N_SECT,2451 .n_type = macho.N_SECT,
2405 .n_sect = self.sectionId(match),2452 .n_sect = self.section_to_ordinal.get(match) orelse unreachable,
2406 .n_desc = 0,2453 .n_desc = 0,
2407 .n_value = 0,2454 .n_value = 0,
2408 };2455 };
...@@ -2498,6 +2545,10 @@ fn populateMetadata(self: *MachO) !void {...@@ -2498,6 +2545,10 @@ fn populateMetadata(self: *MachO) !void {
2498 .@"align" = alignment,2545 .@"align" = alignment,
2499 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2546 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2500 });2547 });
2548 try self.createSectionOrdinal(.{
2549 .seg = self.text_segment_cmd_index.?,
2550 .sect = self.text_section_index.?,
2551 });
2501 }2552 }
25022553
2503 if (self.stubs_section_index == null) {2554 if (self.stubs_section_index == null) {
...@@ -2518,6 +2569,10 @@ fn populateMetadata(self: *MachO) !void {...@@ -2518,6 +2569,10 @@ fn populateMetadata(self: *MachO) !void {
2518 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2569 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2519 .reserved2 = stub_size,2570 .reserved2 = stub_size,
2520 });2571 });
2572 try self.createSectionOrdinal(.{
2573 .seg = self.text_segment_cmd_index.?,
2574 .sect = self.stubs_section_index.?,
2575 });
2521 }2576 }
25222577
2523 if (self.stub_helper_section_index == null) {2578 if (self.stub_helper_section_index == null) {
...@@ -2538,6 +2593,10 @@ fn populateMetadata(self: *MachO) !void {...@@ -2538,6 +2593,10 @@ fn populateMetadata(self: *MachO) !void {
2538 .@"align" = alignment,2593 .@"align" = alignment,
2539 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2594 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2540 });2595 });
2596 try self.createSectionOrdinal(.{
2597 .seg = self.text_segment_cmd_index.?,
2598 .sect = self.stub_helper_section_index.?,
2599 });
2541 }2600 }
25422601
2543 if (self.data_const_segment_cmd_index == null) {2602 if (self.data_const_segment_cmd_index == null) {
...@@ -2557,6 +2616,10 @@ fn populateMetadata(self: *MachO) !void {...@@ -2557,6 +2616,10 @@ fn populateMetadata(self: *MachO) !void {
2557 .@"align" = 3, // 2^3 = @sizeOf(u64)2616 .@"align" = 3, // 2^3 = @sizeOf(u64)
2558 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,2617 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
2559 });2618 });
2619 try self.createSectionOrdinal(.{
2620 .seg = self.data_const_segment_cmd_index.?,
2621 .sect = self.got_section_index.?,
2622 });
2560 }2623 }
25612624
2562 if (self.data_segment_cmd_index == null) {2625 if (self.data_segment_cmd_index == null) {
...@@ -2576,6 +2639,10 @@ fn populateMetadata(self: *MachO) !void {...@@ -2576,6 +2639,10 @@ fn populateMetadata(self: *MachO) !void {
2576 .@"align" = 3, // 2^3 = @sizeOf(u64)2639 .@"align" = 3, // 2^3 = @sizeOf(u64)
2577 .flags = macho.S_LAZY_SYMBOL_POINTERS,2640 .flags = macho.S_LAZY_SYMBOL_POINTERS,
2578 });2641 });
2642 try self.createSectionOrdinal(.{
2643 .seg = self.data_segment_cmd_index.?,
2644 .sect = self.la_symbol_ptr_section_index.?,
2645 });
2579 }2646 }
25802647
2581 if (self.data_section_index == null) {2648 if (self.data_section_index == null) {
...@@ -2584,6 +2651,10 @@ fn populateMetadata(self: *MachO) !void {...@@ -2584,6 +2651,10 @@ fn populateMetadata(self: *MachO) !void {
2584 try data_seg.addSection(self.base.allocator, "__data", .{2651 try data_seg.addSection(self.base.allocator, "__data", .{
2585 .@"align" = 3, // 2^3 = @sizeOf(u64)2652 .@"align" = 3, // 2^3 = @sizeOf(u64)
2586 });2653 });
2654 try self.createSectionOrdinal(.{
2655 .seg = self.data_segment_cmd_index.?,
2656 .sect = self.data_section_index.?,
2657 });
2587 }2658 }
25882659
2589 if (self.linkedit_segment_cmd_index == null) {2660 if (self.linkedit_segment_cmd_index == null) {
...@@ -3290,6 +3361,8 @@ pub fn deinit(self: *MachO) void {...@@ -3290,6 +3361,8 @@ pub fn deinit(self: *MachO) void {
3290 ds.deinit(self.base.allocator);3361 ds.deinit(self.base.allocator);
3291 }3362 }
32923363
3364 self.section_ordinals.deinit(self.base.allocator);
3365 self.section_to_ordinal.deinit(self.base.allocator);
3293 self.pending_updates.deinit(self.base.allocator);3366 self.pending_updates.deinit(self.base.allocator);
3294 self.got_entries.deinit(self.base.allocator);3367 self.got_entries.deinit(self.base.allocator);
3295 self.got_entries_map.deinit(self.base.allocator);3368 self.got_entries_map.deinit(self.base.allocator);
...@@ -5816,37 +5889,6 @@ pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool {...@@ -5816,37 +5889,6 @@ pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool {
5816 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");5889 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
5817}5890}
58185891
5819pub fn sectionId(self: MachO, match: MatchingSection) u8 {
5820 // TODO there might be a more generic way of doing this.
5821 var section: u8 = 0;
5822 for (self.load_commands.items) |cmd, cmd_id| {
5823 if (cmd != .Segment) break;
5824 if (cmd_id == match.seg) {
5825 section += @intCast(u8, match.sect) + 1;
5826 break;
5827 }
5828 section += @intCast(u8, cmd.Segment.sections.items.len);
5829 }
5830 return section;
5831}
5832
5833pub fn unpackSectionId(self: MachO, section_id: u8) MatchingSection {
5834 var match: MatchingSection = undefined;
5835 var section: u8 = 0;
5836 outer: for (self.load_commands.items) |cmd, cmd_id| {
5837 assert(cmd == .Segment);
5838 for (cmd.Segment.sections.items) |_, sect_id| {
5839 section += 1;
5840 if (section_id == section) {
5841 match.seg = @intCast(u16, cmd_id);
5842 match.sect = @intCast(u16, sect_id);
5843 break :outer;
5844 }
5845 }
5846 }
5847 return match;
5848}
5849
5850fn packDylibOrdinal(ordinal: u16) u16 {5892fn packDylibOrdinal(ordinal: u16) u16 {
5851 return ordinal * macho.N_SYMBOL_RESOLVER;5893 return ordinal * macho.N_SYMBOL_RESOLVER;
5852}5894}
...@@ -5867,3 +5909,10 @@ pub fn findFirst(comptime T: type, haystack: []T, start: usize, predicate: anyty...@@ -5867,3 +5909,10 @@ pub fn findFirst(comptime T: type, haystack: []T, start: usize, predicate: anyty
5867 }5909 }
5868 return i;5910 return i;
5869}5911}
5912
5913fn createSectionOrdinal(self: *MachO, match: MatchingSection) !void {
5914 if (self.section_to_ordinal.contains(match)) return;
5915 const ordinal = @intCast(u8, self.section_ordinals.items.len);
5916 try self.section_ordinals.append(self.base.allocator, match);
5917 try self.section_to_ordinal.putNoClobber(self.base.allocator, match, ordinal);
5918}
src/link/MachO/Object.zig+2-2
...@@ -733,7 +733,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -733,7 +733,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
733 try macho_file.locals.append(macho_file.base.allocator, .{733 try macho_file.locals.append(macho_file.base.allocator, .{
734 .n_strx = try macho_file.makeString(sym_name),734 .n_strx = try macho_file.makeString(sym_name),
735 .n_type = macho.N_SECT,735 .n_type = macho.N_SECT,
736 .n_sect = macho_file.sectionId(match),736 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,
737 .n_desc = 0,737 .n_desc = 0,
738 .n_value = sect.addr,738 .n_value = sect.addr,
739 });739 });
...@@ -779,7 +779,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -779,7 +779,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
779 const nlist = nlist_with_index.nlist;779 const nlist = nlist_with_index.nlist;
780 const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable;780 const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
781 const local = &macho_file.locals.items[local_sym_index];781 const local = &macho_file.locals.items[local_sym_index];
782 local.n_sect = macho_file.sectionId(match);782 local.n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable;
783783
784 const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {784 const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
785 // TODO there has to be a better to handle this.785 // TODO there has to be a better to handle this.
src/link/MachO/TextBlock.zig+3-3
...@@ -620,7 +620,7 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo...@@ -620,7 +620,7 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
620 try ctx.macho_file.locals.append(ctx.macho_file.base.allocator, .{620 try ctx.macho_file.locals.append(ctx.macho_file.base.allocator, .{
621 .n_strx = try ctx.macho_file.makeString(sym_name),621 .n_strx = try ctx.macho_file.makeString(sym_name),
622 .n_type = macho.N_SECT,622 .n_type = macho.N_SECT,
623 .n_sect = ctx.macho_file.sectionId(match),623 .n_sect = ctx.macho_file.section_to_ordinal.get(match) orelse unreachable,
624 .n_desc = 0,624 .n_desc = 0,
625 .n_value = sect.addr,625 .n_value = sect.addr,
626 });626 });
...@@ -832,7 +832,7 @@ pub fn parseRelocsFromObject(...@@ -832,7 +832,7 @@ pub fn parseRelocsFromObject(
832 },832 },
833 .local => {833 .local => {
834 const source_sym = ctx.macho_file.locals.items[self.local_sym_index];834 const source_sym = ctx.macho_file.locals.items[self.local_sym_index];
835 const match = ctx.macho_file.unpackSectionId(source_sym.n_sect);835 const match = ctx.macho_file.section_ordinals.items[source_sym.n_sect];
836 const seg = ctx.macho_file.load_commands.items[match.seg].Segment;836 const seg = ctx.macho_file.load_commands.items[match.seg].Segment;
837 const sect = seg.sections.items[match.sect];837 const sect = seg.sections.items[match.sect];
838 const sect_type = commands.sectionType(sect);838 const sect_type = commands.sectionType(sect);
...@@ -1096,7 +1096,7 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {...@@ -1096,7 +1096,7 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
1096 const sym = macho_file.locals.items[rel.where_index];1096 const sym = macho_file.locals.items[rel.where_index];
1097 const is_tlv = is_tlv: {1097 const is_tlv = is_tlv: {
1098 const source_sym = macho_file.locals.items[self.local_sym_index];1098 const source_sym = macho_file.locals.items[self.local_sym_index];
1099 const match = macho_file.unpackSectionId(source_sym.n_sect);1099 const match = macho_file.section_ordinals.items[source_sym.n_sect];
1100 const seg = macho_file.load_commands.items[match.seg].Segment;1100 const seg = macho_file.load_commands.items[match.seg].Segment;
1101 const sect = seg.sections.items[match.sect];1101 const sect = seg.sections.items[match.sect];
1102 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;1102 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;