diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-01-05 21:58:33 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-01-13 23:53:25 +0100 |
| commit | 3d07f057b1ccbc20258114fde762969bcfddf1d3 (patch) | |
| tree | 2fe6b681762e8f5c6a4ec88ef229459460b0a618 /src | |
| parent | 5487dd13ea23ad7e547995b9a088ba37bfe17737 (diff) | |
| download | zig-3d07f057b1ccbc20258114fde762969bcfddf1d3.tar.gz zig-3d07f057b1ccbc20258114fde762969bcfddf1d3.zip | |
macho: prealloc DATA_CONST and DATA segments
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 77 |
1 files changed, 68 insertions, 9 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index dbc982f5e2..8252d6925d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -52,6 +52,8 @@ load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, pagezero_segment_cmd_index: ?u16 = null, /// __TEXT segment text_segment_cmd_index: ?u16 = null, +/// __DATA_CONST segment +data_const_segment_cmd_index: ?u16 = null, /// __DATA segment data_segment_cmd_index: ?u16 = null, /// __LINKEDIT segment @@ -1519,6 +1521,64 @@ pub fn populateMissingMetadata(self: *MachO) !void { self.header_dirty = true; self.load_commands_dirty = true; } + if (self.data_const_segment_cmd_index == null) { + self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); + const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; + const initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE; + const address_and_offset = self.nextSegmentAddressAndOffset(); + + const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint; + const needed_size = mem.alignForwardGeneric(u64, satMul(ideal_size, alloc_num) / alloc_den, self.page_size); + + log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); + + try self.load_commands.append(self.base.allocator, .{ + .Segment = SegmentCommand.empty(.{ + .cmd = macho.LC_SEGMENT_64, + .cmdsize = @sizeOf(macho.segment_command_64), + .segname = makeStaticString("__DATA_CONST"), + .vmaddr = address_and_offset.address, + .vmsize = needed_size, + .fileoff = address_and_offset.offset, + .filesize = needed_size, + .maxprot = maxprot, + .initprot = initprot, + .nsects = 0, + .flags = 0, + }), + }); + self.header_dirty = true; + self.load_commands_dirty = true; + } + if (self.data_segment_cmd_index == null) { + self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); + const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; + const initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE; + const address_and_offset = self.nextSegmentAddressAndOffset(); + + const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint; + const needed_size = mem.alignForwardGeneric(u64, satMul(ideal_size, alloc_num) / alloc_den, self.page_size); + + log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); + + try self.load_commands.append(self.base.allocator, .{ + .Segment = SegmentCommand.empty(.{ + .cmd = macho.LC_SEGMENT_64, + .cmdsize = @sizeOf(macho.segment_command_64), + .segname = makeStaticString("__DATA"), + .vmaddr = address_and_offset.address, + .vmsize = needed_size, + .fileoff = address_and_offset.offset, + .filesize = needed_size, + .maxprot = maxprot, + .initprot = initprot, + .nsects = 0, + .flags = 0, + }), + }); + self.header_dirty = true; + self.load_commands_dirty = true; + } if (self.linkedit_segment_cmd_index == null) { self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); @@ -1907,16 +1967,13 @@ const NextSegmentAddressAndOffset = struct { }; fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { - const prev_segment_idx = blk: { - if (self.data_segment_cmd_index) |idx| { - break :blk idx; - } else if (self.text_segment_cmd_index) |idx| { - break :blk idx; - } else { - unreachable; // unhandled LC_SEGMENT_64 load command before __TEXT + var prev_segment_idx: ?usize = null; // We use optional here for safety. + for (self.load_commands.items) |cmd, i| { + if (cmd == .Segment) { + prev_segment_idx = i; } - }; - const prev_segment = self.load_commands.items[prev_segment_idx].Segment; + } + const prev_segment = self.load_commands.items[prev_segment_idx.?].Segment; const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize; const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize; return .{ @@ -2464,6 +2521,8 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { } } else if (parseAndCmpName(&x.inner.segname, "__DATA")) { self.data_segment_cmd_index = i; + } else if (parseAndCmpName(&x.inner.segname, "__DATA_CONST")) { + self.data_const_segment_cmd_index = i; } }, macho.LC_DYLD_INFO_ONLY => { |
