| ... | @@ -152,8 +152,8 @@ pub const PieFixup = struct { | ... | @@ -152,8 +152,8 @@ pub const PieFixup = struct { |
| 152 | }; | 152 | }; |
| 153 | | 153 | |
| 154 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | 154 | /// `alloc_num / alloc_den` is the factor of padding when allocating. |
| 155 | pub const alloc_num = 4; | 155 | const alloc_num = 4; |
| 156 | pub const alloc_den = 3; | 156 | const alloc_den = 3; |
| 157 | | 157 | |
| 158 | /// Default path to dyld | 158 | /// Default path to dyld |
| 159 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths | 159 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths |
| ... | @@ -1305,21 +1305,21 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1305,21 +1305,21 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1305 | | 1305 | |
| 1306 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}\n", .{ 0, needed_size }); | 1306 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}\n", .{ 0, needed_size }); |
| 1307 | | 1307 | |
| 1308 | var segment = SegmentCommand.empty(.{ | 1308 | try self.load_commands.append(self.base.allocator, .{ |
| 1309 | .cmd = macho.LC_SEGMENT_64, | 1309 | .Segment = SegmentCommand.empty(.{ |
| 1310 | .cmdsize = @sizeOf(macho.segment_command_64), | 1310 | .cmd = macho.LC_SEGMENT_64, |
| 1311 | .segname = makeStaticString("__TEXT"), | 1311 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1312 | .vmaddr = 0x100000000, // always starts at 4GB | 1312 | .segname = makeStaticString("__TEXT"), |
| 1313 | .vmsize = needed_size, | 1313 | .vmaddr = 0x100000000, // always starts at 4GB |
| 1314 | .fileoff = 0, | 1314 | .vmsize = needed_size, |
| 1315 | .filesize = needed_size, | 1315 | .fileoff = 0, |
| 1316 | .maxprot = maxprot, | 1316 | .filesize = needed_size, |
| 1317 | .initprot = initprot, | 1317 | .maxprot = maxprot, |
| 1318 | .nsects = 0, | 1318 | .initprot = initprot, |
| 1319 | .flags = 0, | 1319 | .nsects = 0, |
| | 1320 | .flags = 0, |
| | 1321 | }), |
| 1320 | }); | 1322 | }); |
| 1321 | segment.header_pad = self.header_pad; | | |
| 1322 | try self.load_commands.append(self.base.allocator, .{ .Segment = segment }); | | |
| 1323 | self.cmd_table_dirty = true; | 1323 | self.cmd_table_dirty = true; |
| 1324 | } | 1324 | } |
| 1325 | if (self.text_section_index == null) { | 1325 | if (self.text_section_index == null) { |
| ... | @@ -1333,7 +1333,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1333,7 +1333,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1333 | }; | 1333 | }; |
| 1334 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 1334 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1335 | const needed_size = self.base.options.program_code_size_hint; | 1335 | const needed_size = self.base.options.program_code_size_hint; |
| 1336 | const off = text_segment.findFreeSpace(needed_size, @as(u16, 1) << alignment); | 1336 | const off = self.findFreeSpace(text_segment, needed_size, @as(u16, 1) << alignment); |
| 1337 | | 1337 | |
| 1338 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); | 1338 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); |
| 1339 | | 1339 | |
| ... | @@ -1342,7 +1342,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1342,7 +1342,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1342 | .segname = makeStaticString("__TEXT"), | 1342 | .segname = makeStaticString("__TEXT"), |
| 1343 | .addr = text_segment.inner.vmaddr + off, | 1343 | .addr = text_segment.inner.vmaddr + off, |
| 1344 | .size = @intCast(u32, needed_size), | 1344 | .size = @intCast(u32, needed_size), |
| 1345 | .offset = off, | 1345 | .offset = @intCast(u32, off), |
| 1346 | .@"align" = alignment, | 1346 | .@"align" = alignment, |
| 1347 | .reloff = 0, | 1347 | .reloff = 0, |
| 1348 | .nreloc = 0, | 1348 | .nreloc = 0, |
| ... | @@ -1360,10 +1360,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1360,10 +1360,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1360 | | 1360 | |
| 1361 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 1361 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1362 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1362 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1363 | const off = text_segment.findFreeSpace(needed_size, @sizeOf(u64)); | 1363 | const off = self.findFreeSpace(text_segment, needed_size, @sizeOf(u64)); |
| 1364 | | 1364 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. |
| 1365 | // TODO Audit this. Is it possible to not find free space? We need to grow __TEXT then. | | |
| 1366 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); | | |
| 1367 | | 1365 | |
| 1368 | log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); | 1366 | log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); |
| 1369 | | 1367 | |
| ... | @@ -1372,7 +1370,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1372,7 +1370,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1372 | .segname = makeStaticString("__TEXT"), | 1370 | .segname = makeStaticString("__TEXT"), |
| 1373 | .addr = text_segment.inner.vmaddr + off, | 1371 | .addr = text_segment.inner.vmaddr + off, |
| 1374 | .size = needed_size, | 1372 | .size = needed_size, |
| 1375 | .offset = off, | 1373 | .offset = @intCast(u32, off), |
| 1376 | .@"align" = @sizeOf(u64), | 1374 | .@"align" = @sizeOf(u64), |
| 1377 | .reloff = 0, | 1375 | .reloff = 0, |
| 1378 | .nreloc = 0, | 1376 | .nreloc = 0, |
| ... | @@ -1725,6 +1723,32 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { | ... | @@ -1725,6 +1723,32 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 1725 | }; | 1723 | }; |
| 1726 | } | 1724 | } |
| 1727 | | 1725 | |
| | 1726 | fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 { |
| | 1727 | const end = start + satMul(size, alloc_num) / alloc_den; |
| | 1728 | for (segment.sections.items) |section| { |
| | 1729 | const increased_size = satMul(section.size, alloc_num) / alloc_den; |
| | 1730 | const test_end = section.offset + increased_size; |
| | 1731 | if (end > section.offset and start < test_end) { |
| | 1732 | return test_end; |
| | 1733 | } |
| | 1734 | } |
| | 1735 | return null; |
| | 1736 | } |
| | 1737 | |
| | 1738 | fn findFreeSpace(self: *MachO, segment: *const SegmentCommand, object_size: u64, min_alignment: u16) u64 { |
| | 1739 | var start: u64 = if (parseAndCmpName(&segment.inner.segname, "__TEXT")) self.header_pad else 0; |
| | 1740 | while (self.detectAllocCollision(segment, start, object_size)) |item_end| { |
| | 1741 | start = mem.alignForwardGeneric(u64, item_end, min_alignment); |
| | 1742 | } |
| | 1743 | return start; |
| | 1744 | } |
| | 1745 | |
| | 1746 | /// Saturating multiplication |
| | 1747 | fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { |
| | 1748 | const T = @TypeOf(a, b); |
| | 1749 | return std.math.mul(T, a, b) catch std.math.maxInt(T); |
| | 1750 | } |
| | 1751 | |
| 1728 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 1752 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1729 | const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1753 | const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1730 | const sect = &text_semgent.sections.items[self.got_section_index.?]; | 1754 | const sect = &text_semgent.sections.items[self.got_section_index.?]; |
| ... | @@ -2140,9 +2164,3 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { | ... | @@ -2140,9 +2164,3 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { |
| 2140 | var stream = std.io.fixedBufferStream(buffer); | 2164 | var stream = std.io.fixedBufferStream(buffer); |
| 2141 | try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); | 2165 | try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); |
| 2142 | } | 2166 | } |
| 2143 | | | |
| 2144 | /// Saturating multiplication | | |
| 2145 | pub fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { | | |
| 2146 | const T = @TypeOf(a, b); | | |
| 2147 | return std.math.mul(T, a, b) catch std.math.maxInt(T); | | |
| 2148 | } | | |