| ... | @@ -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(); |
| 589 | | 589 | |
| 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 { |
| 1927 | | 1928 | |
| 1928 | fn getSegmentRank(segname: []const u8) u8 { | 1929 | fn 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 | } |
| 1937 | | 1938 | |
| 1938 | fn getSectionRank(self: *MachO, sect_index: u8) u8 { | 1939 | fn 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, | 1949 | fn 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; |
| 1951 | | 1952 | 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, |
| 1957 | | 1958 | => 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 | |
| | 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 | }; | 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 | } |
| 1968 | | 1986 | |
| 1969 | pub fn sortSections(self: *MachO) !void { | 1987 | pub 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, |
| 1972 | | 1990 | |
| 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 | }; |
| 1977 | | 1999 | |
| ... | @@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void { | ... | @@ -2235,8 +2257,7 @@ fn initSegments(self: *MachO) !void { |
| 2235 | // Sort segments | 2257 | // 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].vmsize | 2298 | self.segments.items[index].vmaddr + self.segments.items[index].vmsize |
| 2278 | else | 2299 | 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; |
| 2290 | | 2304 | |
| 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 { |
| 2296 | | 2310 | |
| 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 | } |
| 2308 | | 2316 | |
| 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 | } |
| 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 | 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 | } |
| 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 | pub fn allocateAtoms(self: *MachO) void { | 2399 | pub 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| { |