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...@@ -588,6 +588,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
588 try self.initSegments();588 try self.initSegments();
589589
590 try self.allocateSections();590 try self.allocateSections();
591 self.allocateSegments();
591 self.allocateAtoms();592 self.allocateAtoms();
592 self.allocateSyntheticSymbols();593 self.allocateSyntheticSymbols();
593 try self.allocateLinkeditSegment();594 try self.allocateLinkeditSegment();
...@@ -1927,43 +1928,60 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t {...@@ -1927,43 +1928,60 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t {
19271928
1928fn getSegmentRank(segname: []const u8) u8 {1929fn getSegmentRank(segname: []const u8) u8 {
1929 if (mem.eql(u8, segname, "__PAGEZERO")) return 0x0;1930 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;
1934 if (mem.eql(u8, segname, "__LINKEDIT")) return 0xf;1931 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;
1935 return 0x4;1936 return 0x4;
1936}1937}
19371938
1938fn getSectionRank(self: *MachO, sect_index: u8) u8 {1939fn segmentLessThan(ctx: void, lhs: []const u8, rhs: []const u8) bool {
1939 const header = self.sections.items(.header)[sect_index];1940 _ = ctx;
1940 const segment_rank = getSegmentRank(header.segName());1941 const lhs_rank = getSegmentRank(lhs);
1941 const section_rank: u4 = blk: {1942 const rhs_rank = getSegmentRank(rhs);
1942 if (header.isCode()) {1943 if (lhs_rank == rhs_rank) {
1943 if (mem.eql(u8, "__text", header.sectName())) break :blk 0x0;1944 return mem.order(u8, lhs, rhs) == .lt;
1944 if (header.type() == macho.S_SYMBOL_STUBS) break :blk 0x1;1945 }
1945 break :blk 0x2;1946 return lhs_rank < rhs_rank;
1946 }1947}
1947 switch (header.type()) {1948
1948 macho.S_NON_LAZY_SYMBOL_POINTERS,1949fn getSectionRank(section: macho.section_64) u8 {
1949 macho.S_LAZY_SYMBOL_POINTERS,1950 if (section.isCode()) {
1950 => break :blk 0x0,1951 if (mem.eql(u8, "__text", section.sectName())) return 0x0;
19511952 if (section.type() == macho.S_SYMBOL_STUBS) return 0x1;
1952 macho.S_MOD_INIT_FUNC_POINTERS => break :blk 0x1,1953 return 0x2;
1953 macho.S_MOD_TERM_FUNC_POINTERS => break :blk 0x2,1954 }
1954 macho.S_ZEROFILL => break :blk 0xf,1955 switch (section.type()) {
1955 macho.S_THREAD_LOCAL_REGULAR => break :blk 0xd,1956 macho.S_NON_LAZY_SYMBOL_POINTERS,
1956 macho.S_THREAD_LOCAL_ZEROFILL => break :blk 0xe,1957 macho.S_LAZY_SYMBOL_POINTERS,
19571958 => return 0x0,
1958 else => {1959
1959 if (mem.eql(u8, "__unwind_info", header.sectName())) break :blk 0xe;1960 macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
1960 if (mem.eql(u8, "__compact_unwind", header.sectName())) break :blk 0xe;1961 macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
1961 if (mem.eql(u8, "__eh_frame", header.sectName())) break :blk 0xf;1962 macho.S_ZEROFILL => return 0xf,
1962 break :blk 0x3;1963 macho.S_THREAD_LOCAL_REGULAR => return 0xd,
1963 },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;
1964 }1981 }
1965 };1982 return lhs_rank < rhs_rank;
1966 return (@as(u8, @intCast(segment_rank)) << 4) + section_rank;1983 }
1984 return segmentLessThan(ctx, lhs.segName(), rhs.segName());
1967}1985}
19681986
1969pub fn sortSections(self: *MachO) !void {1987pub fn sortSections(self: *MachO) !void {
...@@ -1971,7 +1989,11 @@ pub fn sortSections(self: *MachO) !void {...@@ -1971,7 +1989,11 @@ pub fn sortSections(self: *MachO) !void {
1971 index: u8,1989 index: u8,
19721990
1973 pub fn lessThan(macho_file: *MachO, lhs: @This(), rhs: @This()) bool {1991 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 );
1975 }1997 }
1976 };1998 };
19771999
...@@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void {...@@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void {
2235 // Sort segments2257 // Sort segments
2236 const sortFn = struct {2258 const sortFn = struct {
2237 fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool {2259 fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool {
2238 _ = ctx;2260 return segmentLessThan(ctx, lhs.segName(), rhs.segName());
2239 return getSegmentRank(lhs.segName()) < getSegmentRank(rhs.segName());
2240 }2261 }
2241 }.sortFn;2262 }.sortFn;
2242 mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn);2263 mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn);
...@@ -2277,16 +2298,9 @@ fn allocateSections(self: *MachO) !void {...@@ -2277,16 +2298,9 @@ fn allocateSections(self: *MachO) !void {
2277 self.segments.items[index].vmaddr + self.segments.items[index].vmsize2298 self.segments.items[index].vmaddr + self.segments.items[index].vmsize
2278 else2299 else
2279 0;2300 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
2288 vmaddr += headerpad;2301 vmaddr += headerpad;
2289 var fileoff = headerpad;2302 var fileoff = headerpad;
2303 var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
22902304
2291 const page_size = self.getPageSize();2305 const page_size = self.getPageSize();
2292 const slice = self.sections.slice();2306 const slice = self.sections.slice();
...@@ -2296,14 +2310,8 @@ fn allocateSections(self: *MachO) !void {...@@ -2296,14 +2310,8 @@ fn allocateSections(self: *MachO) !void {
22962310
2297 for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| {2311 for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| {
2298 if (prev_seg_id != curr_seg_id) {2312 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;
2303 vmaddr = mem.alignForward(u64, vmaddr, page_size);2313 vmaddr = mem.alignForward(u64, vmaddr, page_size);
2304 fileoff = mem.alignForward(u32, fileoff, page_size);2314 fileoff = mem.alignForward(u32, fileoff, page_size);
2305 curr_seg.vmaddr = vmaddr;
2306 curr_seg.fileoff = fileoff;
2307 }2315 }
23082316
2309 const alignment = try math.powi(u32, 2, header.@"align");2317 const alignment = try math.powi(u32, 2, header.@"align");
...@@ -2321,14 +2329,6 @@ fn allocateSections(self: *MachO) !void {...@@ -2321,14 +2329,6 @@ fn allocateSections(self: *MachO) !void {
2321 prev_seg_id = curr_seg_id;2329 prev_seg_id = curr_seg_id;
2322 }2330 }
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
2332 fileoff = mem.alignForward(u32, fileoff, page_size);2332 fileoff = mem.alignForward(u32, fileoff, page_size);
2333 for (slice.items(.header)[last_index..], slice.items(.segment_id)[last_index..]) |*header, seg_id| {2333 for (slice.items(.header)[last_index..], slice.items(.segment_id)[last_index..]) |*header, seg_id| {
2334 if (header.isZerofill()) continue;2334 if (header.isZerofill()) continue;
...@@ -2355,6 +2355,47 @@ fn allocateSections(self: *MachO) !void {...@@ -2355,6 +2355,47 @@ fn allocateSections(self: *MachO) !void {
2355 }2355 }
2356}2356}
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
2358pub fn allocateAtoms(self: *MachO) void {2399pub fn allocateAtoms(self: *MachO) void {
2359 const slice = self.sections.slice();2400 const slice = self.sections.slice();
2360 for (slice.items(.header), slice.items(.atoms)) |header, atoms| {2401 for (slice.items(.header), slice.items(.atoms)) |header, atoms| {