authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-27 20:32:11+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-27 20:32:11+02:00
loga14e98fcaceed92be8b1859d7ae331176d4e4d84
tree4cf097c9ba5a21fb6c997f6f2380497f9bde2a34
parentad4a8e76654cbb6cab8b2de49a3b83c941bb26c7

macho: remove sorting sections and refactor atom parsing in objects


2 files changed, 29 insertions(+), 233 deletions(-)

src/link/MachO.zig+7-156
......@@ -782,7 +782,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
782782 }
783783
784784 try self.parseTextBlocks();
785 // try self.sortSections();
786785 try self.allocateTextSegment();
787786 try self.allocateDataConstSegment();
788787 try self.allocateDataSegment();
......@@ -1500,158 +1499,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15001499 return res;
15011500}
15021501
1503fn sortSections(self: *MachO) !void {
1504 var text_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator);
1505 defer text_index_mapping.deinit();
1506 var data_const_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator);
1507 defer data_const_index_mapping.deinit();
1508 var data_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator);
1509 defer data_index_mapping.deinit();
1510
1511 {
1512 // __TEXT segment
1513 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1514 var sections = seg.sections.toOwnedSlice(self.base.allocator);
1515 defer self.base.allocator.free(sections);
1516 try seg.sections.ensureCapacity(self.base.allocator, sections.len);
1517
1518 const indices = &[_]*?u16{
1519 &self.text_section_index,
1520 &self.stubs_section_index,
1521 &self.stub_helper_section_index,
1522 &self.gcc_except_tab_section_index,
1523 &self.cstring_section_index,
1524 &self.ustring_section_index,
1525 &self.text_const_section_index,
1526 &self.objc_methlist_section_index,
1527 &self.objc_methname_section_index,
1528 &self.objc_methtype_section_index,
1529 &self.objc_classname_section_index,
1530 &self.eh_frame_section_index,
1531 };
1532 for (indices) |maybe_index| {
1533 const new_index: u16 = if (maybe_index.*) |index| blk: {
1534 const idx = @intCast(u16, seg.sections.items.len);
1535 seg.sections.appendAssumeCapacity(sections[index]);
1536 try text_index_mapping.putNoClobber(index, idx);
1537 break :blk idx;
1538 } else continue;
1539 maybe_index.* = new_index;
1540 }
1541 }
1542
1543 {
1544 // __DATA_CONST segment
1545 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1546 var sections = seg.sections.toOwnedSlice(self.base.allocator);
1547 defer self.base.allocator.free(sections);
1548 try seg.sections.ensureCapacity(self.base.allocator, sections.len);
1549
1550 const indices = &[_]*?u16{
1551 &self.got_section_index,
1552 &self.mod_init_func_section_index,
1553 &self.mod_term_func_section_index,
1554 &self.data_const_section_index,
1555 &self.objc_cfstring_section_index,
1556 &self.objc_classlist_section_index,
1557 &self.objc_imageinfo_section_index,
1558 };
1559 for (indices) |maybe_index| {
1560 const new_index: u16 = if (maybe_index.*) |index| blk: {
1561 const idx = @intCast(u16, seg.sections.items.len);
1562 seg.sections.appendAssumeCapacity(sections[index]);
1563 try data_const_index_mapping.putNoClobber(index, idx);
1564 break :blk idx;
1565 } else continue;
1566 maybe_index.* = new_index;
1567 }
1568 }
1569
1570 {
1571 // __DATA segment
1572 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1573 var sections = seg.sections.toOwnedSlice(self.base.allocator);
1574 defer self.base.allocator.free(sections);
1575 try seg.sections.ensureCapacity(self.base.allocator, sections.len);
1576
1577 // __DATA segment
1578 const indices = &[_]*?u16{
1579 &self.la_symbol_ptr_section_index,
1580 &self.objc_const_section_index,
1581 &self.objc_selrefs_section_index,
1582 &self.objc_classrefs_section_index,
1583 &self.objc_data_section_index,
1584 &self.data_section_index,
1585 &self.tlv_section_index,
1586 &self.tlv_data_section_index,
1587 &self.tlv_bss_section_index,
1588 &self.bss_section_index,
1589 };
1590 for (indices) |maybe_index| {
1591 const new_index: u16 = if (maybe_index.*) |index| blk: {
1592 const idx = @intCast(u16, seg.sections.items.len);
1593 seg.sections.appendAssumeCapacity(sections[index]);
1594 try data_index_mapping.putNoClobber(index, idx);
1595 break :blk idx;
1596 } else continue;
1597 maybe_index.* = new_index;
1598 }
1599 }
1600
1601 {
1602 var transient: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{};
1603 try transient.ensureCapacity(self.base.allocator, self.blocks.count());
1604
1605 var it = self.blocks.iterator();
1606 while (it.next()) |entry| {
1607 const old = entry.key_ptr.*;
1608 const sect = if (old.seg == self.text_segment_cmd_index.?)
1609 text_index_mapping.get(old.sect).?
1610 else if (old.seg == self.data_const_segment_cmd_index.?)
1611 data_const_index_mapping.get(old.sect).?
1612 else
1613 data_index_mapping.get(old.sect).?;
1614 transient.putAssumeCapacityNoClobber(.{
1615 .seg = old.seg,
1616 .sect = sect,
1617 }, entry.value_ptr.*);
1618 }
1619
1620 self.blocks.clearAndFree(self.base.allocator);
1621 self.blocks.deinit(self.base.allocator);
1622 self.blocks = transient;
1623 }
1624
1625 {
1626 // Create new section ordinals.
1627 self.section_ordinals.clearRetainingCapacity();
1628 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1629 for (text_seg.sections.items) |_, sect_id| {
1630 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
1631 .seg = self.text_segment_cmd_index.?,
1632 .sect = @intCast(u16, sect_id),
1633 });
1634 assert(!res.found_existing);
1635 }
1636 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1637 for (data_const_seg.sections.items) |_, sect_id| {
1638 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
1639 .seg = self.data_const_segment_cmd_index.?,
1640 .sect = @intCast(u16, sect_id),
1641 });
1642 assert(!res.found_existing);
1643 }
1644 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1645 for (data_seg.sections.items) |_, sect_id| {
1646 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
1647 .seg = self.data_segment_cmd_index.?,
1648 .sect = @intCast(u16, sect_id),
1649 });
1650 assert(!res.found_existing);
1651 }
1652 }
1653}
1654
16551502fn allocateTextSegment(self: *MachO) !void {
16561503 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
16571504 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
......@@ -1894,7 +1741,7 @@ fn writeTextBlocks(self: *MachO) !void {
18941741 }
18951742}
18961743
1897fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {
1744pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {
18981745 const code = try self.base.allocator.alloc(u8, size);
18991746 defer self.base.allocator.free(code);
19001747 mem.set(u8, code, 0);
......@@ -1924,8 +1771,12 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64
19241771 const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment);
19251772 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
19261773
1927 // TODO we should check if we need to expand the section or not like we
1928 // do in `allocateTextBlock`.
1774 const expand_section = true;
1775 if (expand_section) {
1776 // Expand the section, possibly shifting all the atoms for the sections following it.
1777 // It might also be needed to shift entire segments too if there is not enough
1778 // padding left.
1779 }
19291780 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
19301781 sym.n_value = vaddr;
19311782 sym.n_sect = n_sect;
src/link/MachO/Object.zig+22-77
......@@ -1,6 +1,7 @@
11const Object = @This();
22
33const std = @import("std");
4const build_options = @import("build_options");
45const assert = std.debug.assert;
56const dwarf = std.dwarf;
67const fs = std.fs;
......@@ -405,15 +406,9 @@ const TextBlockParser = struct {
405406 break :blk .static;
406407 } else null;
407408
408 const block = try context.allocator.create(TextBlock);
409 block.* = TextBlock.empty;
410 block.local_sym_index = senior_nlist.index;
409 const block = try context.macho_file.createEmptyAtom(senior_nlist.index, size, actual_align);
411410 block.stab = stab;
412 block.size = size;
413 block.alignment = actual_align;
414 try context.macho_file.managed_blocks.append(context.allocator, block);
415
416 try block.code.appendSlice(context.allocator, code);
411 mem.copy(u8, block.code.items, code);
417412
418413 try block.aliases.ensureTotalCapacity(context.allocator, aliases.items.len);
419414 for (aliases.items) |alias| {
......@@ -458,6 +453,7 @@ pub fn parseTextBlocks(
458453 object_id: u16,
459454 macho_file: *MachO,
460455) !void {
456 const use_stage1 = build_options.is_stage1 and macho_file.base.options.use_stage1;
461457 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
462458
463459 log.debug("analysing {s}", .{self.name});
......@@ -508,6 +504,7 @@ pub fn parseTextBlocks(
508504 log.debug("unhandled section", .{});
509505 continue;
510506 };
507 // TODO allocate section here.
511508
512509 // Read section's code
513510 var code = try allocator.alloc(u8, @intCast(usize, sect.size));
......@@ -568,18 +565,17 @@ pub fn parseTextBlocks(
568565 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);
569566 break :blk block_local_sym_index;
570567 };
571
572568 const block_code = code[0 .. first_nlist.n_value - sect.addr];
573569 const block_size = block_code.len;
570 const block = try macho_file.createEmptyAtom(block_local_sym_index, block_size, sect.@"align");
574571
575 const block = try allocator.create(TextBlock);
576 block.* = TextBlock.empty;
577 block.local_sym_index = block_local_sym_index;
578 block.size = block_size;
579 block.alignment = sect.@"align";
580 try macho_file.managed_blocks.append(allocator, block);
572 if (use_stage1) {
573 try macho_file.allocateAtomStage1(block, match);
574 } else {
575 _ = try macho_file.allocateAtom(block, match);
576 }
581577
582 try block.code.appendSlice(allocator, block_code);
578 mem.copy(u8, block.code.items, block_code);
583579
584580 try block.parseRelocs(relocs, .{
585581 .base_addr = 0,
......@@ -601,25 +597,6 @@ pub fn parseTextBlocks(
601597 }
602598 }
603599
604 // Update target section's metadata
605 // TODO should we update segment's size here too?
606 // How does it tie with incremental space allocs?
607 const tseg = &macho_file.load_commands.items[match.seg].Segment;
608 const tsect = &tseg.sections.items[match.sect];
609 const new_alignment = math.max(tsect.@"align", block.alignment);
610 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
611 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
612 tsect.size = new_size;
613 tsect.@"align" = new_alignment;
614
615 if (macho_file.blocks.getPtr(match)) |last| {
616 last.*.next = block;
617 block.prev = last.*;
618 last.* = block;
619 } else {
620 try macho_file.blocks.putNoClobber(allocator, match, block);
621 }
622
623600 try self.text_blocks.append(allocator, block);
624601 }
625602
......@@ -666,23 +643,10 @@ pub fn parseTextBlocks(
666643 }
667644 }
668645
669 // Update target section's metadata
670 // TODO should we update segment's size here too?
671 // How does it tie with incremental space allocs?
672 const tseg = &macho_file.load_commands.items[match.seg].Segment;
673 const tsect = &tseg.sections.items[match.sect];
674 const new_alignment = math.max(tsect.@"align", block.alignment);
675 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
676 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
677 tsect.size = new_size;
678 tsect.@"align" = new_alignment;
679
680 if (macho_file.blocks.getPtr(match)) |last| {
681 last.*.next = block;
682 block.prev = last.*;
683 last.* = block;
646 if (use_stage1) {
647 try macho_file.allocateAtomStage1(block, match);
684648 } else {
685 try macho_file.blocks.putNoClobber(allocator, match, block);
649 _ = try macho_file.allocateAtom(block, match);
686650 }
687651
688652 try self.text_blocks.append(allocator, block);
......@@ -713,15 +677,15 @@ pub fn parseTextBlocks(
713677 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);
714678 break :blk block_local_sym_index;
715679 };
680 const block = try macho_file.createEmptyAtom(block_local_sym_index, sect.size, sect.@"align");
716681
717 const block = try allocator.create(TextBlock);
718 block.* = TextBlock.empty;
719 block.local_sym_index = block_local_sym_index;
720 block.size = sect.size;
721 block.alignment = sect.@"align";
722 try macho_file.managed_blocks.append(allocator, block);
682 if (use_stage1) {
683 try macho_file.allocateAtomStage1(block, match);
684 } else {
685 _ = try macho_file.allocateAtom(block, match);
686 }
723687
724 try block.code.appendSlice(allocator, code);
688 mem.copy(u8, block.code.items, code);
725689
726690 try block.parseRelocs(relocs, .{
727691 .base_addr = 0,
......@@ -779,25 +743,6 @@ pub fn parseTextBlocks(
779743 });
780744 }
781745
782 // Update target section's metadata
783 // TODO should we update segment's size here too?
784 // How does it tie with incremental space allocs?
785 const tseg = &macho_file.load_commands.items[match.seg].Segment;
786 const tsect = &tseg.sections.items[match.sect];
787 const new_alignment = math.max(tsect.@"align", block.alignment);
788 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
789 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
790 tsect.size = new_size;
791 tsect.@"align" = new_alignment;
792
793 if (macho_file.blocks.getPtr(match)) |last| {
794 last.*.next = block;
795 block.prev = last.*;
796 last.* = block;
797 } else {
798 try macho_file.blocks.putNoClobber(allocator, match, block);
799 }
800
801746 try self.text_blocks.append(allocator, block);
802747 }
803748 }