authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-22 11:25:43+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:42+01:00
logfe19d1e09b283c8f09afa49abb0f3835fdc40aaa
tree7b66aff880f20cb9a153e5ebd8ec1dd63d97e2aa
parentc57e77a45553a6570e6e278475ff45408f59d1b4

macho: allocate segments in sep step and tweak sorting logic


1 files changed, 98 insertions(+), 57 deletions(-)

src/link/MachO.zig+98-57
......@@ -588,6 +588,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
588588 try self.initSegments();
589589
590590 try self.allocateSections();
591 self.allocateSegments();
591592 self.allocateAtoms();
592593 self.allocateSyntheticSymbols();
593594 try self.allocateLinkeditSegment();
......@@ -1927,43 +1928,60 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t {
19271928
19281929fn getSegmentRank(segname: []const u8) u8 {
19291930 if (mem.eql(u8, segname, "__PAGEZERO")) return 0x0;
1930 if (mem.eql(u8, segname, "__TEXT")) return 0x1;
1931 if (mem.eql(u8, segname, "__DATA_CONST")) return 0x2;
1932 if (mem.eql(u8, segname, "__DATA")) return 0x3;
1933 if (mem.indexOf(u8, segname, "ZIG")) |_| return 0xe;
19341931 if (mem.eql(u8, segname, "__LINKEDIT")) return 0xf;
1932 if (mem.indexOf(u8, segname, "ZIG")) |_| return 0xe;
1933 if (mem.startsWith(u8, segname, "__TEXT")) return 0x1;
1934 if (mem.startsWith(u8, segname, "__DATA_CONST")) return 0x2;
1935 if (mem.startsWith(u8, segname, "__DATA")) return 0x3;
19351936 return 0x4;
19361937}
19371938
1938fn getSectionRank(self: *MachO, sect_index: u8) u8 {
1939 const header = self.sections.items(.header)[sect_index];
1940 const segment_rank = getSegmentRank(header.segName());
1941 const section_rank: u4 = blk: {
1942 if (header.isCode()) {
1943 if (mem.eql(u8, "__text", header.sectName())) break :blk 0x0;
1944 if (header.type() == macho.S_SYMBOL_STUBS) break :blk 0x1;
1945 break :blk 0x2;
1946 }
1947 switch (header.type()) {
1948 macho.S_NON_LAZY_SYMBOL_POINTERS,
1949 macho.S_LAZY_SYMBOL_POINTERS,
1950 => break :blk 0x0,
1951
1952 macho.S_MOD_INIT_FUNC_POINTERS => break :blk 0x1,
1953 macho.S_MOD_TERM_FUNC_POINTERS => break :blk 0x2,
1954 macho.S_ZEROFILL => break :blk 0xf,
1955 macho.S_THREAD_LOCAL_REGULAR => break :blk 0xd,
1956 macho.S_THREAD_LOCAL_ZEROFILL => break :blk 0xe,
1957
1958 else => {
1959 if (mem.eql(u8, "__unwind_info", header.sectName())) break :blk 0xe;
1960 if (mem.eql(u8, "__compact_unwind", header.sectName())) break :blk 0xe;
1961 if (mem.eql(u8, "__eh_frame", header.sectName())) break :blk 0xf;
1962 break :blk 0x3;
1963 },
1939fn segmentLessThan(ctx: void, lhs: []const u8, rhs: []const u8) bool {
1940 _ = ctx;
1941 const lhs_rank = getSegmentRank(lhs);
1942 const rhs_rank = getSegmentRank(rhs);
1943 if (lhs_rank == rhs_rank) {
1944 return mem.order(u8, lhs, rhs) == .lt;
1945 }
1946 return lhs_rank < rhs_rank;
1947}
1948
1949fn getSectionRank(section: macho.section_64) u8 {
1950 if (section.isCode()) {
1951 if (mem.eql(u8, "__text", section.sectName())) return 0x0;
1952 if (section.type() == macho.S_SYMBOL_STUBS) return 0x1;
1953 return 0x2;
1954 }
1955 switch (section.type()) {
1956 macho.S_NON_LAZY_SYMBOL_POINTERS,
1957 macho.S_LAZY_SYMBOL_POINTERS,
1958 => return 0x0,
1959
1960 macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
1961 macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
1962 macho.S_ZEROFILL => return 0xf,
1963 macho.S_THREAD_LOCAL_REGULAR => return 0xd,
1964 macho.S_THREAD_LOCAL_ZEROFILL => return 0xe,
1965
1966 else => {
1967 if (mem.eql(u8, "__unwind_info", section.sectName())) return 0xe;
1968 if (mem.eql(u8, "__compact_unwind", section.sectName())) return 0xe;
1969 if (mem.eql(u8, "__eh_frame", section.sectName())) return 0xf;
1970 return 0x3;
1971 },
1972 }
1973}
1974
1975fn sectionLessThan(ctx: void, lhs: macho.section_64, rhs: macho.section_64) bool {
1976 if (mem.eql(u8, lhs.segName(), rhs.segName())) {
1977 const lhs_rank = getSectionRank(lhs);
1978 const rhs_rank = getSectionRank(rhs);
1979 if (lhs_rank == rhs_rank) {
1980 return mem.order(u8, lhs.sectName(), rhs.sectName()) == .lt;
19641981 }
1965 };
1966 return (@as(u8, @intCast(segment_rank)) << 4) + section_rank;
1982 return lhs_rank < rhs_rank;
1983 }
1984 return segmentLessThan(ctx, lhs.segName(), rhs.segName());
19671985}
19681986
19691987pub fn sortSections(self: *MachO) !void {
......@@ -1971,7 +1989,11 @@ pub fn sortSections(self: *MachO) !void {
19711989 index: u8,
19721990
19731991 pub fn lessThan(macho_file: *MachO, lhs: @This(), rhs: @This()) bool {
1974 return macho_file.getSectionRank(lhs.index) < macho_file.getSectionRank(rhs.index);
1992 return sectionLessThan(
1993 {},
1994 macho_file.sections.items(.header)[lhs.index],
1995 macho_file.sections.items(.header)[rhs.index],
1996 );
19751997 }
19761998 };
19771999
......@@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void {
22352257 // Sort segments
22362258 const sortFn = struct {
22372259 fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool {
2238 _ = ctx;
2239 return getSegmentRank(lhs.segName()) < getSegmentRank(rhs.segName());
2260 return segmentLessThan(ctx, lhs.segName(), rhs.segName());
22402261 }
22412262 }.sortFn;
22422263 mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn);
......@@ -2277,16 +2298,9 @@ fn allocateSections(self: *MachO) !void {
22772298 self.segments.items[index].vmaddr + self.segments.items[index].vmsize
22782299 else
22792300 0;
2280
2281 var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
2282 {
2283 const seg = &self.segments.items[prev_seg_id];
2284 seg.vmaddr = vmaddr;
2285 seg.fileoff = 0;
2286 }
2287
22882301 vmaddr += headerpad;
22892302 var fileoff = headerpad;
2303 var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
22902304
22912305 const page_size = self.getPageSize();
22922306 const slice = self.sections.slice();
......@@ -2296,14 +2310,8 @@ fn allocateSections(self: *MachO) !void {
22962310
22972311 for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| {
22982312 if (prev_seg_id != curr_seg_id) {
2299 const prev_seg = &self.segments.items[prev_seg_id];
2300 const curr_seg = &self.segments.items[curr_seg_id];
2301 prev_seg.vmsize = vmaddr - prev_seg.vmaddr;
2302 prev_seg.filesize = fileoff - prev_seg.fileoff;
23032313 vmaddr = mem.alignForward(u64, vmaddr, page_size);
23042314 fileoff = mem.alignForward(u32, fileoff, page_size);
2305 curr_seg.vmaddr = vmaddr;
2306 curr_seg.fileoff = fileoff;
23072315 }
23082316
23092317 const alignment = try math.powi(u32, 2, header.@"align");
......@@ -2321,14 +2329,6 @@ fn allocateSections(self: *MachO) !void {
23212329 prev_seg_id = curr_seg_id;
23222330 }
23232331
2324 {
2325 const prev_seg = &self.segments.items[prev_seg_id];
2326 prev_seg.vmsize = vmaddr - prev_seg.vmaddr;
2327 prev_seg.filesize = fileoff - prev_seg.fileoff;
2328 }
2329
2330 // TODO iterate over sections again, but consider only zig sections
2331 // and move them if they are allocated in file below page-aligned fileoff
23322332 fileoff = mem.alignForward(u32, fileoff, page_size);
23332333 for (slice.items(.header)[last_index..], slice.items(.segment_id)[last_index..]) |*header, seg_id| {
23342334 if (header.isZerofill()) continue;
......@@ -2355,6 +2355,47 @@ fn allocateSections(self: *MachO) !void {
23552355 }
23562356}
23572357
2358/// We allocate segments in a separate step to also consider segments that have no sections.
2359fn allocateSegments(self: *MachO) void {
2360 const first_index = if (self.pagezero_seg_index) |index| index + 1 else 0;
2361 const last_index = for (self.segments.items, 0..) |seg, i| {
2362 if (mem.indexOf(u8, seg.segName(), "ZIG")) |_| break i;
2363 } else self.segments.items.len;
2364
2365 var vmaddr: u64 = if (self.pagezero_seg_index) |index|
2366 self.segments.items[index].vmaddr + self.segments.items[index].vmsize
2367 else
2368 0;
2369 var fileoff: u64 = 0;
2370
2371 const page_size = self.getPageSize();
2372 const slice = self.sections.slice();
2373
2374 var next_sect_id: u8 = 0;
2375 for (self.segments.items[first_index..last_index], first_index..last_index) |*seg, seg_id| {
2376 seg.vmaddr = vmaddr;
2377 seg.fileoff = fileoff;
2378
2379 while (next_sect_id < slice.items(.header).len) : (next_sect_id += 1) {
2380 const header = slice.items(.header)[next_sect_id];
2381 const sid = slice.items(.segment_id)[next_sect_id];
2382
2383 if (seg_id != sid) break;
2384
2385 vmaddr = header.addr + header.size;
2386 if (!header.isZerofill()) {
2387 fileoff = header.offset + header.size;
2388 }
2389 }
2390
2391 seg.vmsize = vmaddr - seg.vmaddr;
2392 seg.filesize = fileoff - seg.fileoff;
2393
2394 vmaddr = mem.alignForward(u64, vmaddr, page_size);
2395 fileoff = mem.alignForward(u64, fileoff, page_size);
2396 }
2397}
2398
23582399pub fn allocateAtoms(self: *MachO) void {
23592400 const slice = self.sections.slice();
23602401 for (slice.items(.header), slice.items(.atoms)) |header, atoms| {