| author | |
| committer | |
| log | a14e98fcaceed92be8b1859d7ae331176d4e4d84 |
| tree | 4cf097c9ba5a21fb6c997f6f2380497f9bde2a34 |
| parent | ad4a8e76654cbb6cab8b2de49a3b83c941bb26c7 |
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 | } |
| 783 | 783 | ||
| 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 | } |
| 1502 | 1501 | ||
| 1503 | fn 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 | |||
| 1655 | fn allocateTextSegment(self: *MachO) !void { | 1502 | fn 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 | } |
| 1896 | 1743 | ||
| 1897 | fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock { | 1744 | pub 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 }); |
| 1926 | 1773 | ||
| 1927 | // TODO we should check if we need to expand the section or not like we | 1774 | 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 @@ |
| 1 | const Object = @This(); | 1 | const Object = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const build_options = @import("build_options"); | ||
| 4 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 5 | const dwarf = std.dwarf; | 6 | const dwarf = std.dwarf; |
| 6 | const fs = std.fs; | 7 | const 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; |
| 407 | 408 | ||
| 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); | ||
| 417 | 412 | ||
| 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; |
| 462 | 458 | ||
| 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. | ||
| 511 | 508 | ||
| 512 | // Read section's code | 509 | // 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"); | ||
| 574 | 571 | ||
| 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); | ||
| 581 | 577 | ||
| 582 | try block.code.appendSlice(allocator, block_code); | 578 | mem.copy(u8, block.code.items, block_code); |
| 583 | 579 | ||
| 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 | } |
| 603 | 599 | ||
| 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 | } |
| 625 | 602 | ||
| ... | @@ -666,23 +643,10 @@ pub fn parseTextBlocks( | ... | @@ -666,23 +643,10 @@ pub fn parseTextBlocks( |
| 666 | } | 643 | } |
| 667 | } | 644 | } |
| 668 | 645 | ||
| 669 | // Update target section's metadata | 646 | 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 | } |
| 687 | 651 | ||
| 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"); | ||
| 716 | 681 | ||
| 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); | ||
| 723 | 687 | ||
| 724 | try block.code.appendSlice(allocator, code); | 688 | mem.copy(u8, block.code.items, code); |
| 725 | 689 | ||
| 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 | } |
| 781 | 745 | ||
| 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 | } |