mirror of
https://github.com/ziglang/zig.git
synced 2026-01-12 10:25:13 +00:00
macho: add logic for segment expansion
This commit is contained in:
parent
d92b5416e8
commit
ea8808f87b
@ -133,8 +133,8 @@ objc_selrefs_section_index: ?u16 = null,
|
||||
objc_classrefs_section_index: ?u16 = null,
|
||||
objc_data_section_index: ?u16 = null,
|
||||
|
||||
bss_file_offset: ?u64 = null,
|
||||
tlv_bss_file_offset: ?u64 = null,
|
||||
bss_file_offset: ?u32 = null,
|
||||
tlv_bss_file_offset: ?u32 = null,
|
||||
|
||||
locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
@ -1693,6 +1693,84 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64
|
||||
const padding: ?u64 = if (match.seg == self.text_segment_cmd_index.?) self.header_pad else null;
|
||||
const atom_alignment = try math.powi(u64, 2, atom.alignment);
|
||||
const new_offset = @intCast(u32, seg.findFreeSpace(needed_size, atom_alignment, padding));
|
||||
|
||||
if (new_offset + needed_size >= seg.inner.fileoff + seg.inner.filesize) {
|
||||
// Bummer, need to move all segments below down...
|
||||
// TODO is this the right estimate?
|
||||
const new_seg_size = mem.alignForwardGeneric(
|
||||
u64,
|
||||
padToIdeal(seg.inner.filesize + needed_size),
|
||||
self.page_size,
|
||||
);
|
||||
// TODO actually, we're always required to move in a number of pages so I guess all we need
|
||||
// to know here is the number of pages to shift downwards.
|
||||
const offset_amt = @intCast(u32, @intCast(i64, new_seg_size) - @intCast(i64, seg.inner.filesize));
|
||||
seg.inner.filesize = new_seg_size;
|
||||
seg.inner.vmsize = new_seg_size;
|
||||
log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
|
||||
seg.inner.segname,
|
||||
seg.inner.fileoff,
|
||||
seg.inner.fileoff + seg.inner.filesize,
|
||||
seg.inner.vmaddr,
|
||||
seg.inner.vmaddr + seg.inner.vmsize,
|
||||
});
|
||||
// TODO We should probably nop the expanded by distance, or put 0s.
|
||||
|
||||
// TODO copyRangeAll doesn't automatically extend the file on macOS.
|
||||
const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize;
|
||||
try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1);
|
||||
|
||||
var next: usize = match.seg + 1;
|
||||
while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) {
|
||||
const next_seg = &self.load_commands.items[next].Segment;
|
||||
_ = try self.base.file.?.copyRangeAll(
|
||||
next_seg.inner.fileoff,
|
||||
self.base.file.?,
|
||||
next_seg.inner.fileoff + offset_amt,
|
||||
next_seg.inner.filesize,
|
||||
);
|
||||
next_seg.inner.fileoff += offset_amt;
|
||||
next_seg.inner.vmaddr += offset_amt;
|
||||
log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
|
||||
next_seg.inner.segname,
|
||||
next_seg.inner.fileoff,
|
||||
next_seg.inner.fileoff + next_seg.inner.filesize,
|
||||
next_seg.inner.vmaddr,
|
||||
next_seg.inner.vmaddr + next_seg.inner.vmsize,
|
||||
});
|
||||
|
||||
for (next_seg.sections.items) |*moved_sect, moved_sect_id| {
|
||||
// TODO put below snippet in a function.
|
||||
const moved_sect_offset = blk: {
|
||||
if (self.data_segment_cmd_index.? == next) {
|
||||
if (self.bss_section_index) |idx| {
|
||||
if (idx == moved_sect_id) break :blk &self.bss_file_offset.?;
|
||||
}
|
||||
if (self.tlv_bss_section_index) |idx| {
|
||||
if (idx == moved_sect_id) break :blk &self.tlv_bss_file_offset.?;
|
||||
}
|
||||
}
|
||||
break :blk &moved_sect.offset;
|
||||
};
|
||||
moved_sect_offset.* += offset_amt;
|
||||
moved_sect.addr += offset_amt;
|
||||
log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
|
||||
commands.segmentName(moved_sect.*),
|
||||
commands.sectionName(moved_sect.*),
|
||||
moved_sect_offset.*,
|
||||
moved_sect_offset.* + moved_sect.size,
|
||||
moved_sect.addr,
|
||||
moved_sect.addr + moved_sect.size,
|
||||
});
|
||||
|
||||
try self.allocateLocalSymbols(.{
|
||||
.seg = @intCast(u16, next),
|
||||
.sect = @intCast(u16, moved_sect_id),
|
||||
}, offset_amt);
|
||||
}
|
||||
}
|
||||
}
|
||||
sect.offset = new_offset;
|
||||
sect.addr = seg.inner.vmaddr + sect.offset - seg.inner.fileoff;
|
||||
log.debug(" (found new {s},{s} free space from 0x{x} to 0x{x})", .{
|
||||
@ -1701,11 +1779,9 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64
|
||||
new_offset,
|
||||
new_offset + needed_size,
|
||||
});
|
||||
try self.allocateLocalSymbols(match, old_base_addr);
|
||||
vaddr = @intCast(
|
||||
u64,
|
||||
@intCast(i64, vaddr) + @intCast(i64, sect.addr) - @intCast(i64, old_base_addr),
|
||||
);
|
||||
const offset_amt = @intCast(i64, sect.addr) - @intCast(i64, old_base_addr);
|
||||
try self.allocateLocalSymbols(match, offset_amt);
|
||||
vaddr = @intCast(u64, @intCast(i64, vaddr) + offset_amt);
|
||||
}
|
||||
|
||||
sect.size = needed_size;
|
||||
@ -1761,11 +1837,8 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
|
||||
try self.base.file.?.pwriteAll(atom.code.items, file_offset);
|
||||
}
|
||||
|
||||
fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void {
|
||||
fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void {
|
||||
var atom = self.blocks.get(match) orelse return;
|
||||
const seg = self.load_commands.items[match.seg].Segment;
|
||||
const sect = seg.sections.items[match.sect];
|
||||
const offset = @intCast(i64, sect.addr) - @intCast(i64, old_base_addr);
|
||||
|
||||
while (true) {
|
||||
const atom_sym = &self.locals.items[atom.local_sym_index];
|
||||
@ -3317,9 +3390,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
|
||||
if (self.text_segment_cmd_index == null) {
|
||||
self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
|
||||
const program_code_size_hint = self.base.options.program_code_size_hint;
|
||||
// const program_code_size_hint = 10;
|
||||
const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
|
||||
const ideal_size = self.header_pad + (program_code_size_hint + got_size_hint) * 5;
|
||||
const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
|
||||
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
|
||||
|
||||
log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
|
||||
@ -3413,7 +3485,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
|
||||
if (self.data_const_segment_cmd_index == null) {
|
||||
self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
|
||||
const address_and_offset = self.nextSegmentAddressAndOffset();
|
||||
const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint * 1000;
|
||||
const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
|
||||
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
|
||||
|
||||
log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
|
||||
@ -3454,7 +3526,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
|
||||
if (self.data_segment_cmd_index == null) {
|
||||
self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
|
||||
const address_and_offset = self.nextSegmentAddressAndOffset();
|
||||
const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint * 1000;
|
||||
const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
|
||||
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), 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 });
|
||||
@ -3905,20 +3977,99 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
|
||||
const old_base_addr = text_section.addr;
|
||||
text_section.size = 0;
|
||||
const new_offset = @intCast(u32, text_segment.findFreeSpace(needed_size, alignment, self.header_pad));
|
||||
|
||||
if (new_offset + needed_size >= text_segment.inner.fileoff + text_segment.inner.filesize) {
|
||||
// Bummer, need to move all segments below down...
|
||||
// TODO is this the right estimate?
|
||||
const new_seg_size = mem.alignForwardGeneric(
|
||||
u64,
|
||||
padToIdeal(text_segment.inner.filesize + needed_size),
|
||||
self.page_size,
|
||||
);
|
||||
// TODO actually, we're always required to move in a number of pages so I guess all we need
|
||||
// to know here is the number of pages to shift downwards.
|
||||
const offset_amt = @intCast(
|
||||
u32,
|
||||
@intCast(i64, new_seg_size) - @intCast(i64, text_segment.inner.filesize),
|
||||
);
|
||||
text_segment.inner.filesize = new_seg_size;
|
||||
text_segment.inner.vmsize = new_seg_size;
|
||||
log.debug(" (new __TEXT segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
|
||||
text_segment.inner.fileoff,
|
||||
text_segment.inner.fileoff + text_segment.inner.filesize,
|
||||
text_segment.inner.vmaddr,
|
||||
text_segment.inner.vmaddr + text_segment.inner.vmsize,
|
||||
});
|
||||
// TODO We should probably nop the expanded by distance, or put 0s.
|
||||
|
||||
// TODO copyRangeAll doesn't automatically extend the file on macOS.
|
||||
const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize;
|
||||
try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1);
|
||||
|
||||
var next: usize = match.seg + 1;
|
||||
while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) {
|
||||
const next_seg = &self.load_commands.items[next].Segment;
|
||||
_ = try self.base.file.?.copyRangeAll(
|
||||
next_seg.inner.fileoff,
|
||||
self.base.file.?,
|
||||
next_seg.inner.fileoff + offset_amt,
|
||||
next_seg.inner.filesize,
|
||||
);
|
||||
next_seg.inner.fileoff += offset_amt;
|
||||
next_seg.inner.vmaddr += offset_amt;
|
||||
log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
|
||||
next_seg.inner.segname,
|
||||
next_seg.inner.fileoff,
|
||||
next_seg.inner.fileoff + next_seg.inner.filesize,
|
||||
next_seg.inner.vmaddr,
|
||||
next_seg.inner.vmaddr + next_seg.inner.vmsize,
|
||||
});
|
||||
|
||||
for (next_seg.sections.items) |*moved_sect, moved_sect_id| {
|
||||
// TODO put below snippet in a function.
|
||||
const moved_sect_offset = blk: {
|
||||
if (self.data_segment_cmd_index.? == next) {
|
||||
if (self.bss_section_index) |idx| {
|
||||
if (idx == moved_sect_id) break :blk &self.bss_file_offset.?;
|
||||
}
|
||||
if (self.tlv_bss_section_index) |idx| {
|
||||
if (idx == moved_sect_id) break :blk &self.tlv_bss_file_offset.?;
|
||||
}
|
||||
}
|
||||
break :blk &moved_sect.offset;
|
||||
};
|
||||
moved_sect_offset.* += offset_amt;
|
||||
moved_sect.addr += offset_amt;
|
||||
log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
|
||||
commands.segmentName(moved_sect.*),
|
||||
commands.sectionName(moved_sect.*),
|
||||
moved_sect_offset.*,
|
||||
moved_sect_offset.* + moved_sect.size,
|
||||
moved_sect.addr,
|
||||
moved_sect.addr + moved_sect.size,
|
||||
});
|
||||
|
||||
try self.allocateLocalSymbols(.{
|
||||
.seg = @intCast(u16, next),
|
||||
.sect = @intCast(u16, moved_sect_id),
|
||||
}, offset_amt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text_section.offset = new_offset;
|
||||
text_section.addr = text_segment.inner.vmaddr + text_section.offset - text_segment.inner.fileoff;
|
||||
log.debug(" (found new __TEXT,__text free space from 0x{x} to 0x{x})", .{
|
||||
new_offset,
|
||||
new_offset + needed_size,
|
||||
});
|
||||
const offset_amt = @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr);
|
||||
try self.allocateLocalSymbols(.{
|
||||
.seg = self.text_segment_cmd_index.?,
|
||||
.sect = self.text_section_index.?,
|
||||
}, old_base_addr);
|
||||
vaddr = @intCast(
|
||||
u64,
|
||||
@intCast(i64, vaddr) + @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr),
|
||||
);
|
||||
}, offset_amt);
|
||||
vaddr = @intCast(u64, @intCast(i64, vaddr) + offset_amt);
|
||||
}
|
||||
|
||||
text_section.size = needed_size;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user