| ... | @@ -1925,7 +1925,7 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 | ... | @@ -1925,7 +1925,7 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 |
| 1925 | var atom_placement: ?*TextBlock = null; | 1925 | var atom_placement: ?*TextBlock = null; |
| 1926 | | 1926 | |
| 1927 | // TODO converge with `allocateTextBlock` and handle free list | 1927 | // TODO converge with `allocateTextBlock` and handle free list |
| 1928 | const vaddr = if (self.blocks.get(match)) |last| blk: { | 1928 | var vaddr = if (self.blocks.get(match)) |last| blk: { |
| 1929 | const last_atom_sym = self.locals.items[last.local_sym_index]; | 1929 | const last_atom_sym = self.locals.items[last.local_sym_index]; |
| 1930 | const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size; | 1930 | const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size; |
| 1931 | const ideal_capacity_end_vaddr = last_atom_sym.n_value + ideal_capacity; | 1931 | const ideal_capacity_end_vaddr = last_atom_sym.n_value + ideal_capacity; |
| ... | @@ -1939,6 +1939,7 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 | ... | @@ -1939,6 +1939,7 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 |
| 1939 | | 1939 | |
| 1940 | const expand_section = atom_placement == null or atom_placement.?.next == null; | 1940 | const expand_section = atom_placement == null or atom_placement.?.next == null; |
| 1941 | if (expand_section) { | 1941 | if (expand_section) { |
| | 1942 | const needed_size = (vaddr + atom.size) - sect.addr; |
| 1942 | const sect_offset: u64 = blk: { | 1943 | const sect_offset: u64 = blk: { |
| 1943 | if (self.data_segment_cmd_index.? == match.seg) { | 1944 | if (self.data_segment_cmd_index.? == match.seg) { |
| 1944 | if (self.bss_section_index) |idx| { | 1945 | if (self.bss_section_index) |idx| { |
| ... | @@ -1952,8 +1953,35 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 | ... | @@ -1952,8 +1953,35 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 |
| 1952 | }; | 1953 | }; |
| 1953 | const file_offset = sect_offset + vaddr - sect.addr; | 1954 | const file_offset = sect_offset + vaddr - sect.addr; |
| 1954 | const max_size = seg.allocatedSize(file_offset); | 1955 | const max_size = seg.allocatedSize(file_offset); |
| 1955 | log.debug(" (atom size 0x{x}, max available size 0x{x})", .{ atom.size, max_size }); | 1956 | log.debug(" (section {s},{s} needed size 0x{x}, max available size 0x{x})", .{ |
| 1956 | assert(atom.size <= max_size); // TODO must expand the section | 1957 | commands.segmentName(sect.*), |
| | 1958 | commands.sectionName(sect.*), |
| | 1959 | needed_size, |
| | 1960 | max_size, |
| | 1961 | }); |
| | 1962 | |
| | 1963 | if (needed_size > max_size) { |
| | 1964 | const old_base_addr = sect.addr; |
| | 1965 | sect.size = 0; |
| | 1966 | const padding: ?u64 = if (match.seg == self.text_segment_cmd_index.?) self.header_pad else null; |
| | 1967 | const new_offset = @intCast(u32, seg.findFreeSpace(needed_size, atom.alignment, padding)); |
| | 1968 | sect.offset = new_offset; |
| | 1969 | sect.addr = seg.inner.vmaddr + sect.offset - seg.inner.fileoff; |
| | 1970 | log.debug(" (found new {s},{s} free space from 0x{x} to 0x{x})", .{ |
| | 1971 | commands.segmentName(sect.*), |
| | 1972 | commands.sectionName(sect.*), |
| | 1973 | new_offset, |
| | 1974 | new_offset + needed_size, |
| | 1975 | }); |
| | 1976 | try self.allocateLocalSymbols(match, old_base_addr); |
| | 1977 | vaddr = @intCast( |
| | 1978 | u64, |
| | 1979 | @intCast(i64, vaddr) + @intCast(i64, sect.addr) - @intCast(i64, old_base_addr), |
| | 1980 | ); |
| | 1981 | } |
| | 1982 | |
| | 1983 | sect.size = needed_size; |
| | 1984 | self.load_commands_dirty = true; |
| 1957 | } | 1985 | } |
| 1958 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | 1986 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 1959 | sym.n_value = vaddr; | 1987 | sym.n_value = vaddr; |
| ... | @@ -2017,6 +2045,32 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { | ... | @@ -2017,6 +2045,32 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 2017 | try self.writeLocalSymbol(atom.local_sym_index); | 2045 | try self.writeLocalSymbol(atom.local_sym_index); |
| 2018 | } | 2046 | } |
| 2019 | | 2047 | |
| | 2048 | fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void { |
| | 2049 | var atom = self.blocks.get(match) orelse return; |
| | 2050 | const seg = self.load_commands.items[match.seg].Segment; |
| | 2051 | const sect = seg.sections.items[match.sect]; |
| | 2052 | const offset = @intCast(i64, sect.addr) - @intCast(i64, old_base_addr); |
| | 2053 | |
| | 2054 | while (true) { |
| | 2055 | const atom_sym = &self.locals.items[atom.local_sym_index]; |
| | 2056 | atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset); |
| | 2057 | |
| | 2058 | for (atom.aliases.items) |index| { |
| | 2059 | const alias_sym = &self.locals.items[index]; |
| | 2060 | alias_sym.n_value = @intCast(u64, @intCast(i64, alias_sym.n_value) + offset); |
| | 2061 | } |
| | 2062 | |
| | 2063 | for (atom.contained.items) |sym_at_off| { |
| | 2064 | const contained_sym = &self.locals.items[sym_at_off.local_sym_index]; |
| | 2065 | contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset); |
| | 2066 | } |
| | 2067 | |
| | 2068 | if (atom.prev) |prev| { |
| | 2069 | atom = prev; |
| | 2070 | } else break; |
| | 2071 | } |
| | 2072 | } |
| | 2073 | |
| 2020 | fn allocateGlobalSymbols(self: *MachO) !void { | 2074 | fn allocateGlobalSymbols(self: *MachO) !void { |
| 2021 | // TODO should we do this in `allocateAtom` (or similar)? Then, we would need to | 2075 | // TODO should we do this in `allocateAtom` (or similar)? Then, we would need to |
| 2022 | // store the link atom -> globals somewhere. | 2076 | // store the link atom -> globals somewhere. |
| ... | @@ -3943,8 +3997,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3943,8 +3997,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3943 | if (self.text_segment_cmd_index == null) { | 3997 | if (self.text_segment_cmd_index == null) { |
| 3944 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 3998 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3945 | const program_code_size_hint = self.base.options.program_code_size_hint; | 3999 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| | 4000 | // const program_code_size_hint = 10; |
| 3946 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; | 4001 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3947 | const ideal_size = self.header_pad + program_code_size_hint + 3 * got_size_hint; | 4002 | const ideal_size = self.header_pad + program_code_size_hint + got_size_hint; |
| 3948 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); | 4003 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3949 | | 4004 | |
| 3950 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); | 4005 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); |
| ... | @@ -3971,6 +4026,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3971,6 +4026,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3971 | else => unreachable, // unhandled architecture type | 4026 | else => unreachable, // unhandled architecture type |
| 3972 | }; | 4027 | }; |
| 3973 | const needed_size = self.base.options.program_code_size_hint; | 4028 | const needed_size = self.base.options.program_code_size_hint; |
| | 4029 | // const needed_size = 10; |
| 3974 | self.text_section_index = try self.allocateSection( | 4030 | self.text_section_index = try self.allocateSection( |
| 3975 | self.text_segment_cmd_index.?, | 4031 | self.text_segment_cmd_index.?, |
| 3976 | "__text", | 4032 | "__text", |
| ... | @@ -4521,7 +4577,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4521,7 +4577,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4521 | | 4577 | |
| 4522 | // First we look for an appropriately sized free list node. | 4578 | // First we look for an appropriately sized free list node. |
| 4523 | // The list is unordered. We'll just take the first thing that works. | 4579 | // The list is unordered. We'll just take the first thing that works. |
| 4524 | const vaddr = blk: { | 4580 | var vaddr = blk: { |
| 4525 | var i: usize = 0; | 4581 | var i: usize = 0; |
| 4526 | while (i < text_block_free_list.items.len) { | 4582 | while (i < text_block_free_list.items.len) { |
| 4527 | const big_block = text_block_free_list.items[i]; | 4583 | const big_block = text_block_free_list.items[i]; |
| ... | @@ -4576,8 +4632,31 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4576,8 +4632,31 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4576 | if (expand_text_section) { | 4632 | if (expand_text_section) { |
| 4577 | const needed_size = (vaddr + new_block_size) - text_section.addr; | 4633 | const needed_size = (vaddr + new_block_size) - text_section.addr; |
| 4578 | const max_size = text_segment.allocatedSize(vaddr - pagezero_vmsize); | 4634 | const max_size = text_segment.allocatedSize(vaddr - pagezero_vmsize); |
| 4579 | log.debug(" (atom needed size 0x{x}, max available size 0x{x})", .{ needed_size, max_size }); | 4635 | log.debug(" (section __TEXT,__text needed size 0x{x}, max available size 0x{x})", .{ needed_size, max_size }); |
| 4580 | assert(needed_size <= max_size); // TODO must expand the section | 4636 | |
| | 4637 | if (needed_size > max_size) { |
| | 4638 | const old_base_addr = text_section.addr; |
| | 4639 | text_section.size = 0; |
| | 4640 | const new_offset = @intCast(u32, text_segment.findFreeSpace(needed_size, alignment, self.header_pad)); |
| | 4641 | text_section.offset = new_offset; |
| | 4642 | text_section.addr = text_segment.inner.vmaddr + text_section.offset - text_segment.inner.fileoff; |
| | 4643 | log.debug(" (found new __TEXT,__text free space from 0x{x} to 0x{x})", .{ |
| | 4644 | new_offset, |
| | 4645 | new_offset + needed_size, |
| | 4646 | }); |
| | 4647 | try self.allocateLocalSymbols(.{ |
| | 4648 | .seg = self.text_segment_cmd_index.?, |
| | 4649 | .sect = self.text_section_index.?, |
| | 4650 | }, old_base_addr); |
| | 4651 | vaddr = @intCast( |
| | 4652 | u64, |
| | 4653 | @intCast(i64, vaddr) + @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr), |
| | 4654 | ); |
| | 4655 | } |
| | 4656 | |
| | 4657 | text_section.size = needed_size; |
| | 4658 | self.load_commands_dirty = true; |
| | 4659 | |
| 4581 | _ = try self.blocks.put(self.base.allocator, match, text_block); | 4660 | _ = try self.blocks.put(self.base.allocator, match, text_block); |
| 4582 | } | 4661 | } |
| 4583 | text_block.size = new_block_size; | 4662 | text_block.size = new_block_size; |