| ... | ... | @@ -588,6 +588,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 588 | 588 | try self.initSegments(); |
| 589 | 589 | |
| 590 | 590 | try self.allocateSections(); |
| 591 | self.allocateSegments(); |
| 591 | 592 | self.allocateAtoms(); |
| 592 | 593 | self.allocateSyntheticSymbols(); |
| 593 | 594 | try self.allocateLinkeditSegment(); |
| ... | ... | @@ -1927,43 +1928,60 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t { |
| 1927 | 1928 | |
| 1928 | 1929 | fn getSegmentRank(segname: []const u8) u8 { |
| 1929 | 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 | 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 | 1936 | return 0x4; |
| 1936 | 1937 | } |
| 1937 | 1938 | |
| 1938 | | fn 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 | | }, |
| 1939 | fn 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 | |
| 1949 | fn 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 | |
| 1975 | fn 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 | | }; |
| 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()); |
| 1967 | 1985 | } |
| 1968 | 1986 | |
| 1969 | 1987 | pub fn sortSections(self: *MachO) !void { |
| ... | ... | @@ -1971,7 +1989,11 @@ pub fn sortSections(self: *MachO) !void { |
| 1971 | 1989 | index: u8, |
| 1972 | 1990 | |
| 1973 | 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 | }; |
| 1977 | 1999 | |
| ... | ... | @@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void { |
| 2235 | 2257 | // Sort segments |
| 2236 | 2258 | const sortFn = struct { |
| 2237 | 2259 | 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()); |
| 2240 | 2261 | } |
| 2241 | 2262 | }.sortFn; |
| 2242 | 2263 | mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn); |
| ... | ... | @@ -2277,16 +2298,9 @@ fn allocateSections(self: *MachO) !void { |
| 2277 | 2298 | self.segments.items[index].vmaddr + self.segments.items[index].vmsize |
| 2278 | 2299 | else |
| 2279 | 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 | 2301 | vmaddr += headerpad; |
| 2289 | 2302 | var fileoff = headerpad; |
| 2303 | var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0; |
| 2290 | 2304 | |
| 2291 | 2305 | const page_size = self.getPageSize(); |
| 2292 | 2306 | const slice = self.sections.slice(); |
| ... | ... | @@ -2296,14 +2310,8 @@ fn allocateSections(self: *MachO) !void { |
| 2296 | 2310 | |
| 2297 | 2311 | for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| { |
| 2298 | 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 | 2313 | vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| 2304 | 2314 | fileoff = mem.alignForward(u32, fileoff, page_size); |
| 2305 | | curr_seg.vmaddr = vmaddr; |
| 2306 | | curr_seg.fileoff = fileoff; |
| 2307 | 2315 | } |
| 2308 | 2316 | |
| 2309 | 2317 | const alignment = try math.powi(u32, 2, header.@"align"); |
| ... | ... | @@ -2321,14 +2329,6 @@ fn allocateSections(self: *MachO) !void { |
| 2321 | 2329 | prev_seg_id = curr_seg_id; |
| 2322 | 2330 | } |
| 2323 | 2331 | |
| 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 | 2332 | fileoff = mem.alignForward(u32, fileoff, page_size); |
| 2333 | 2333 | for (slice.items(.header)[last_index..], slice.items(.segment_id)[last_index..]) |*header, seg_id| { |
| 2334 | 2334 | if (header.isZerofill()) continue; |
| ... | ... | @@ -2355,6 +2355,47 @@ fn allocateSections(self: *MachO) !void { |
| 2355 | 2355 | } |
| 2356 | 2356 | } |
| 2357 | 2357 | |
| 2358 | /// We allocate segments in a separate step to also consider segments that have no sections. |
| 2359 | fn 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 | |
| 2358 | 2399 | pub fn allocateAtoms(self: *MachO) void { |
| 2359 | 2400 | const slice = self.sections.slice(); |
| 2360 | 2401 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { |