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 {...@@ -782,7 +782,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
782 }782 }
783783
784 try self.parseTextBlocks();784 try self.parseTextBlocks();
785 // try self.sortSections();
786 try self.allocateTextSegment();785 try self.allocateTextSegment();
787 try self.allocateDataConstSegment();786 try self.allocateDataConstSegment();
788 try self.allocateDataSegment();787 try self.allocateDataSegment();
...@@ -1500,158 +1499,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1500,158 +1499,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1500 return res;1499 return res;
1501}1500}
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
1655fn allocateTextSegment(self: *MachO) !void {1502fn allocateTextSegment(self: *MachO) !void {
1656 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1503 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1657 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;1504 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
...@@ -1894,7 +1741,7 @@ fn writeTextBlocks(self: *MachO) !void {...@@ -1894,7 +1741,7 @@ fn writeTextBlocks(self: *MachO) !void {
1894 }1741 }
1895}1742}
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 {
1898 const code = try self.base.allocator.alloc(u8, size);1745 const code = try self.base.allocator.alloc(u8, size);
1899 defer self.base.allocator.free(code);1746 defer self.base.allocator.free(code);
1900 mem.set(u8, code, 0);1747 mem.set(u8, code, 0);
...@@ -1924,8 +1771,12 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64...@@ -1924,8 +1771,12 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64
1924 const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment);1771 const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment);
1925 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });1772 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 we1774 const expand_section = true;
1928 // do in `allocateTextBlock`.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 }
1929 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);1780 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1930 sym.n_value = vaddr;1781 sym.n_value = vaddr;
1931 sym.n_sect = n_sect;1782 sym.n_sect = n_sect;
src/link/MachO/Object.zig+22-77
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const Object = @This();1const Object = @This();
22
3const std = @import("std");3const std = @import("std");
4const build_options = @import("build_options");
4const assert = std.debug.assert;5const assert = std.debug.assert;
5const dwarf = std.dwarf;6const dwarf = std.dwarf;
6const fs = std.fs;7const fs = std.fs;
...@@ -405,15 +406,9 @@ const TextBlockParser = struct {...@@ -405,15 +406,9 @@ const TextBlockParser = struct {
405 break :blk .static;406 break :blk .static;
406 } else null;407 } else null;
407408
408 const block = try context.allocator.create(TextBlock);409 const block = try context.macho_file.createEmptyAtom(senior_nlist.index, size, actual_align);
409 block.* = TextBlock.empty;
410 block.local_sym_index = senior_nlist.index;
411 block.stab = stab;410 block.stab = stab;
412 block.size = size;411 mem.copy(u8, block.code.items, code);
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);
417412
418 try block.aliases.ensureTotalCapacity(context.allocator, aliases.items.len);413 try block.aliases.ensureTotalCapacity(context.allocator, aliases.items.len);
419 for (aliases.items) |alias| {414 for (aliases.items) |alias| {
...@@ -458,6 +453,7 @@ pub fn parseTextBlocks(...@@ -458,6 +453,7 @@ pub fn parseTextBlocks(
458 object_id: u16,453 object_id: u16,
459 macho_file: *MachO,454 macho_file: *MachO,
460) !void {455) !void {
456 const use_stage1 = build_options.is_stage1 and macho_file.base.options.use_stage1;
461 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;457 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
462458
463 log.debug("analysing {s}", .{self.name});459 log.debug("analysing {s}", .{self.name});
...@@ -508,6 +504,7 @@ pub fn parseTextBlocks(...@@ -508,6 +504,7 @@ pub fn parseTextBlocks(
508 log.debug("unhandled section", .{});504 log.debug("unhandled section", .{});
509 continue;505 continue;
510 };506 };
507 // TODO allocate section here.
511508
512 // Read section's code509 // Read section's code
513 var code = try allocator.alloc(u8, @intCast(usize, sect.size));510 var code = try allocator.alloc(u8, @intCast(usize, sect.size));
...@@ -568,18 +565,17 @@ pub fn parseTextBlocks(...@@ -568,18 +565,17 @@ pub fn parseTextBlocks(
568 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);565 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);
569 break :blk block_local_sym_index;566 break :blk block_local_sym_index;
570 };567 };
571
572 const block_code = code[0 .. first_nlist.n_value - sect.addr];568 const block_code = code[0 .. first_nlist.n_value - sect.addr];
573 const block_size = block_code.len;569 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);572 if (use_stage1) {
576 block.* = TextBlock.empty;573 try macho_file.allocateAtomStage1(block, match);
577 block.local_sym_index = block_local_sym_index;574 } else {
578 block.size = block_size;575 _ = try macho_file.allocateAtom(block, match);
579 block.alignment = sect.@"align";576 }
580 try macho_file.managed_blocks.append(allocator, block);
581577
582 try block.code.appendSlice(allocator, block_code);578 mem.copy(u8, block.code.items, block_code);
583579
584 try block.parseRelocs(relocs, .{580 try block.parseRelocs(relocs, .{
585 .base_addr = 0,581 .base_addr = 0,
...@@ -601,25 +597,6 @@ pub fn parseTextBlocks(...@@ -601,25 +597,6 @@ pub fn parseTextBlocks(
601 }597 }
602 }598 }
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
623 try self.text_blocks.append(allocator, block);600 try self.text_blocks.append(allocator, block);
624 }601 }
625602
...@@ -666,23 +643,10 @@ pub fn parseTextBlocks(...@@ -666,23 +643,10 @@ pub fn parseTextBlocks(
666 }643 }
667 }644 }
668645
669 // Update target section's metadata646 if (use_stage1) {
670 // TODO should we update segment's size here too?647 try macho_file.allocateAtomStage1(block, match);
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;
684 } else {648 } else {
685 try macho_file.blocks.putNoClobber(allocator, match, block);649 _ = try macho_file.allocateAtom(block, match);
686 }650 }
687651
688 try self.text_blocks.append(allocator, block);652 try self.text_blocks.append(allocator, block);
...@@ -713,15 +677,15 @@ pub fn parseTextBlocks(...@@ -713,15 +677,15 @@ pub fn parseTextBlocks(
713 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);677 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);
714 break :blk block_local_sym_index;678 break :blk block_local_sym_index;
715 };679 };
680 const block = try macho_file.createEmptyAtom(block_local_sym_index, sect.size, sect.@"align");
716681
717 const block = try allocator.create(TextBlock);682 if (use_stage1) {
718 block.* = TextBlock.empty;683 try macho_file.allocateAtomStage1(block, match);
719 block.local_sym_index = block_local_sym_index;684 } else {
720 block.size = sect.size;685 _ = try macho_file.allocateAtom(block, match);
721 block.alignment = sect.@"align";686 }
722 try macho_file.managed_blocks.append(allocator, block);
723687
724 try block.code.appendSlice(allocator, code);688 mem.copy(u8, block.code.items, code);
725689
726 try block.parseRelocs(relocs, .{690 try block.parseRelocs(relocs, .{
727 .base_addr = 0,691 .base_addr = 0,
...@@ -779,25 +743,6 @@ pub fn parseTextBlocks(...@@ -779,25 +743,6 @@ pub fn parseTextBlocks(
779 });743 });
780 }744 }
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
801 try self.text_blocks.append(allocator, block);746 try self.text_blocks.append(allocator, block);
802 }747 }
803 }748 }