mirror of
https://github.com/ziglang/zig.git
synced 2025-12-25 23:53:15 +00:00
macho: allocate segments in sep step and tweak sorting logic
This commit is contained in:
parent
c57e77a455
commit
fe19d1e09b
@ -588,6 +588,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
|
||||
try self.initSegments();
|
||||
|
||||
try self.allocateSections();
|
||||
self.allocateSegments();
|
||||
self.allocateAtoms();
|
||||
self.allocateSyntheticSymbols();
|
||||
try self.allocateLinkeditSegment();
|
||||
@ -1927,43 +1928,60 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t {
|
||||
|
||||
fn getSegmentRank(segname: []const u8) u8 {
|
||||
if (mem.eql(u8, segname, "__PAGEZERO")) return 0x0;
|
||||
if (mem.eql(u8, segname, "__TEXT")) return 0x1;
|
||||
if (mem.eql(u8, segname, "__DATA_CONST")) return 0x2;
|
||||
if (mem.eql(u8, segname, "__DATA")) return 0x3;
|
||||
if (mem.indexOf(u8, segname, "ZIG")) |_| return 0xe;
|
||||
if (mem.eql(u8, segname, "__LINKEDIT")) return 0xf;
|
||||
if (mem.indexOf(u8, segname, "ZIG")) |_| return 0xe;
|
||||
if (mem.startsWith(u8, segname, "__TEXT")) return 0x1;
|
||||
if (mem.startsWith(u8, segname, "__DATA_CONST")) return 0x2;
|
||||
if (mem.startsWith(u8, segname, "__DATA")) return 0x3;
|
||||
return 0x4;
|
||||
}
|
||||
|
||||
fn getSectionRank(self: *MachO, sect_index: u8) u8 {
|
||||
const header = self.sections.items(.header)[sect_index];
|
||||
const segment_rank = getSegmentRank(header.segName());
|
||||
const section_rank: u4 = blk: {
|
||||
if (header.isCode()) {
|
||||
if (mem.eql(u8, "__text", header.sectName())) break :blk 0x0;
|
||||
if (header.type() == macho.S_SYMBOL_STUBS) break :blk 0x1;
|
||||
break :blk 0x2;
|
||||
}
|
||||
switch (header.type()) {
|
||||
macho.S_NON_LAZY_SYMBOL_POINTERS,
|
||||
macho.S_LAZY_SYMBOL_POINTERS,
|
||||
=> break :blk 0x0,
|
||||
fn segmentLessThan(ctx: void, lhs: []const u8, rhs: []const u8) bool {
|
||||
_ = ctx;
|
||||
const lhs_rank = getSegmentRank(lhs);
|
||||
const rhs_rank = getSegmentRank(rhs);
|
||||
if (lhs_rank == rhs_rank) {
|
||||
return mem.order(u8, lhs, rhs) == .lt;
|
||||
}
|
||||
return lhs_rank < rhs_rank;
|
||||
}
|
||||
|
||||
macho.S_MOD_INIT_FUNC_POINTERS => break :blk 0x1,
|
||||
macho.S_MOD_TERM_FUNC_POINTERS => break :blk 0x2,
|
||||
macho.S_ZEROFILL => break :blk 0xf,
|
||||
macho.S_THREAD_LOCAL_REGULAR => break :blk 0xd,
|
||||
macho.S_THREAD_LOCAL_ZEROFILL => break :blk 0xe,
|
||||
fn getSectionRank(section: macho.section_64) u8 {
|
||||
if (section.isCode()) {
|
||||
if (mem.eql(u8, "__text", section.sectName())) return 0x0;
|
||||
if (section.type() == macho.S_SYMBOL_STUBS) return 0x1;
|
||||
return 0x2;
|
||||
}
|
||||
switch (section.type()) {
|
||||
macho.S_NON_LAZY_SYMBOL_POINTERS,
|
||||
macho.S_LAZY_SYMBOL_POINTERS,
|
||||
=> return 0x0,
|
||||
|
||||
else => {
|
||||
if (mem.eql(u8, "__unwind_info", header.sectName())) break :blk 0xe;
|
||||
if (mem.eql(u8, "__compact_unwind", header.sectName())) break :blk 0xe;
|
||||
if (mem.eql(u8, "__eh_frame", header.sectName())) break :blk 0xf;
|
||||
break :blk 0x3;
|
||||
},
|
||||
macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
|
||||
macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
|
||||
macho.S_ZEROFILL => return 0xf,
|
||||
macho.S_THREAD_LOCAL_REGULAR => return 0xd,
|
||||
macho.S_THREAD_LOCAL_ZEROFILL => return 0xe,
|
||||
|
||||
else => {
|
||||
if (mem.eql(u8, "__unwind_info", section.sectName())) return 0xe;
|
||||
if (mem.eql(u8, "__compact_unwind", section.sectName())) return 0xe;
|
||||
if (mem.eql(u8, "__eh_frame", section.sectName())) return 0xf;
|
||||
return 0x3;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn sectionLessThan(ctx: void, lhs: macho.section_64, rhs: macho.section_64) bool {
|
||||
if (mem.eql(u8, lhs.segName(), rhs.segName())) {
|
||||
const lhs_rank = getSectionRank(lhs);
|
||||
const rhs_rank = getSectionRank(rhs);
|
||||
if (lhs_rank == rhs_rank) {
|
||||
return mem.order(u8, lhs.sectName(), rhs.sectName()) == .lt;
|
||||
}
|
||||
};
|
||||
return (@as(u8, @intCast(segment_rank)) << 4) + section_rank;
|
||||
return lhs_rank < rhs_rank;
|
||||
}
|
||||
return segmentLessThan(ctx, lhs.segName(), rhs.segName());
|
||||
}
|
||||
|
||||
pub fn sortSections(self: *MachO) !void {
|
||||
@ -1971,7 +1989,11 @@ pub fn sortSections(self: *MachO) !void {
|
||||
index: u8,
|
||||
|
||||
pub fn lessThan(macho_file: *MachO, lhs: @This(), rhs: @This()) bool {
|
||||
return macho_file.getSectionRank(lhs.index) < macho_file.getSectionRank(rhs.index);
|
||||
return sectionLessThan(
|
||||
{},
|
||||
macho_file.sections.items(.header)[lhs.index],
|
||||
macho_file.sections.items(.header)[rhs.index],
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void {
|
||||
// Sort segments
|
||||
const sortFn = struct {
|
||||
fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool {
|
||||
_ = ctx;
|
||||
return getSegmentRank(lhs.segName()) < getSegmentRank(rhs.segName());
|
||||
return segmentLessThan(ctx, lhs.segName(), rhs.segName());
|
||||
}
|
||||
}.sortFn;
|
||||
mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn);
|
||||
@ -2277,16 +2298,9 @@ fn allocateSections(self: *MachO) !void {
|
||||
self.segments.items[index].vmaddr + self.segments.items[index].vmsize
|
||||
else
|
||||
0;
|
||||
|
||||
var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
|
||||
{
|
||||
const seg = &self.segments.items[prev_seg_id];
|
||||
seg.vmaddr = vmaddr;
|
||||
seg.fileoff = 0;
|
||||
}
|
||||
|
||||
vmaddr += headerpad;
|
||||
var fileoff = headerpad;
|
||||
var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
|
||||
|
||||
const page_size = self.getPageSize();
|
||||
const slice = self.sections.slice();
|
||||
@ -2296,14 +2310,8 @@ fn allocateSections(self: *MachO) !void {
|
||||
|
||||
for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| {
|
||||
if (prev_seg_id != curr_seg_id) {
|
||||
const prev_seg = &self.segments.items[prev_seg_id];
|
||||
const curr_seg = &self.segments.items[curr_seg_id];
|
||||
prev_seg.vmsize = vmaddr - prev_seg.vmaddr;
|
||||
prev_seg.filesize = fileoff - prev_seg.fileoff;
|
||||
vmaddr = mem.alignForward(u64, vmaddr, page_size);
|
||||
fileoff = mem.alignForward(u32, fileoff, page_size);
|
||||
curr_seg.vmaddr = vmaddr;
|
||||
curr_seg.fileoff = fileoff;
|
||||
}
|
||||
|
||||
const alignment = try math.powi(u32, 2, header.@"align");
|
||||
@ -2321,14 +2329,6 @@ fn allocateSections(self: *MachO) !void {
|
||||
prev_seg_id = curr_seg_id;
|
||||
}
|
||||
|
||||
{
|
||||
const prev_seg = &self.segments.items[prev_seg_id];
|
||||
prev_seg.vmsize = vmaddr - prev_seg.vmaddr;
|
||||
prev_seg.filesize = fileoff - prev_seg.fileoff;
|
||||
}
|
||||
|
||||
// TODO iterate over sections again, but consider only zig sections
|
||||
// and move them if they are allocated in file below page-aligned fileoff
|
||||
fileoff = mem.alignForward(u32, fileoff, page_size);
|
||||
for (slice.items(.header)[last_index..], slice.items(.segment_id)[last_index..]) |*header, seg_id| {
|
||||
if (header.isZerofill()) continue;
|
||||
@ -2355,6 +2355,47 @@ fn allocateSections(self: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
/// We allocate segments in a separate step to also consider segments that have no sections.
|
||||
fn allocateSegments(self: *MachO) void {
|
||||
const first_index = if (self.pagezero_seg_index) |index| index + 1 else 0;
|
||||
const last_index = for (self.segments.items, 0..) |seg, i| {
|
||||
if (mem.indexOf(u8, seg.segName(), "ZIG")) |_| break i;
|
||||
} else self.segments.items.len;
|
||||
|
||||
var vmaddr: u64 = if (self.pagezero_seg_index) |index|
|
||||
self.segments.items[index].vmaddr + self.segments.items[index].vmsize
|
||||
else
|
||||
0;
|
||||
var fileoff: u64 = 0;
|
||||
|
||||
const page_size = self.getPageSize();
|
||||
const slice = self.sections.slice();
|
||||
|
||||
var next_sect_id: u8 = 0;
|
||||
for (self.segments.items[first_index..last_index], first_index..last_index) |*seg, seg_id| {
|
||||
seg.vmaddr = vmaddr;
|
||||
seg.fileoff = fileoff;
|
||||
|
||||
while (next_sect_id < slice.items(.header).len) : (next_sect_id += 1) {
|
||||
const header = slice.items(.header)[next_sect_id];
|
||||
const sid = slice.items(.segment_id)[next_sect_id];
|
||||
|
||||
if (seg_id != sid) break;
|
||||
|
||||
vmaddr = header.addr + header.size;
|
||||
if (!header.isZerofill()) {
|
||||
fileoff = header.offset + header.size;
|
||||
}
|
||||
}
|
||||
|
||||
seg.vmsize = vmaddr - seg.vmaddr;
|
||||
seg.filesize = fileoff - seg.fileoff;
|
||||
|
||||
vmaddr = mem.alignForward(u64, vmaddr, page_size);
|
||||
fileoff = mem.alignForward(u64, fileoff, page_size);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocateAtoms(self: *MachO) void {
|
||||
const slice = self.sections.slice();
|
||||
for (slice.items(.header), slice.items(.atoms)) |header, atoms| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user