| ... | @@ -37,6 +37,10 @@ page_size: u16, | ... | @@ -37,6 +37,10 @@ page_size: u16, |
| 37 | | 37 | |
| 38 | /// Mach-O header | 38 | /// Mach-O header |
| 39 | header: ?macho.mach_header_64 = null, | 39 | header: ?macho.mach_header_64 = null, |
| | 40 | /// We commit 0x1000 = 4096 bytes of space to the header and |
| | 41 | /// the table of load commands. This should be plenty for any |
| | 42 | /// potential future extensions. |
| | 43 | header_pad: u16 = 0x1000, |
| 40 | | 44 | |
| 41 | /// Table of all load commands | 45 | /// Table of all load commands |
| 42 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 46 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| ... | @@ -75,7 +79,7 @@ code_signature_cmd_index: ?u16 = null, | ... | @@ -75,7 +79,7 @@ code_signature_cmd_index: ?u16 = null, |
| 75 | | 79 | |
| 76 | /// Index into __TEXT,__text section. | 80 | /// Index into __TEXT,__text section. |
| 77 | text_section_index: ?u16 = null, | 81 | text_section_index: ?u16 = null, |
| 78 | /// Index into __TEXT,__got section. | 82 | /// Index into __TEXT,__ziggot section. |
| 79 | got_section_index: ?u16 = null, | 83 | got_section_index: ?u16 = null, |
| 80 | /// The absolute address of the entry point. | 84 | /// The absolute address of the entry point. |
| 81 | entry_addr: ?u64 = null, | 85 | entry_addr: ?u64 = null, |
| ... | @@ -150,8 +154,8 @@ pub const PieFixup = struct { | ... | @@ -150,8 +154,8 @@ pub const PieFixup = struct { |
| 150 | }; | 154 | }; |
| 151 | | 155 | |
| 152 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | 156 | /// `alloc_num / alloc_den` is the factor of padding when allocating. |
| 153 | const alloc_num = 4; | 157 | pub const alloc_num = 4; |
| 154 | const alloc_den = 3; | 158 | pub const alloc_den = 3; |
| 155 | | 159 | |
| 156 | /// Default path to dyld | 160 | /// Default path to dyld |
| 157 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths | 161 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths |
| ... | @@ -1295,15 +1299,23 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1295,15 +1299,23 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1295 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 1299 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1296 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; | 1300 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| 1297 | const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE; | 1301 | const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE; |
| | 1302 | |
| | 1303 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| | 1304 | const offset_table_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| | 1305 | const ideal_size = self.header_pad + program_code_size_hint + offset_table_size_hint; |
| | 1306 | const needed_size = mem.alignForwardGeneric(u64, satMul(ideal_size, alloc_num) / alloc_den, self.page_size); |
| | 1307 | |
| | 1308 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}\n", .{ 0, needed_size }); |
| | 1309 | |
| 1298 | try self.load_commands.append(self.base.allocator, .{ | 1310 | try self.load_commands.append(self.base.allocator, .{ |
| 1299 | .Segment = SegmentCommand.empty(.{ | 1311 | .Segment = SegmentCommand.empty(.{ |
| 1300 | .cmd = macho.LC_SEGMENT_64, | 1312 | .cmd = macho.LC_SEGMENT_64, |
| 1301 | .cmdsize = @sizeOf(macho.segment_command_64), | 1313 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1302 | .segname = makeStaticString("__TEXT"), | 1314 | .segname = makeStaticString("__TEXT"), |
| 1303 | .vmaddr = 0x100000000, // always starts at 4GB | 1315 | .vmaddr = 0x100000000, // always starts at 4GB |
| 1304 | .vmsize = 0, | 1316 | .vmsize = needed_size, |
| 1305 | .fileoff = 0, | 1317 | .fileoff = 0, |
| 1306 | .filesize = 0, | 1318 | .filesize = needed_size, |
| 1307 | .maxprot = maxprot, | 1319 | .maxprot = maxprot, |
| 1308 | .initprot = initprot, | 1320 | .initprot = initprot, |
| 1309 | .nsects = 0, | 1321 | .nsects = 0, |
| ... | @@ -1316,31 +1328,31 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1316,31 +1328,31 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1316 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1328 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1317 | self.text_section_index = @intCast(u16, text_segment.sections.items.len); | 1329 | self.text_section_index = @intCast(u16, text_segment.sections.items.len); |
| 1318 | | 1330 | |
| 1319 | const program_code_size_hint = self.base.options.program_code_size_hint; | 1331 | const alignment: u32 = switch (self.base.options.target.cpu.arch) { |
| 1320 | const file_size = mem.alignForwardGeneric(u64, program_code_size_hint, self.page_size); | 1332 | .x86_64 => 0, |
| 1321 | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); // TODO maybe findFreeSpace should return u32 directly? | 1333 | .aarch64 => 2, |
| | 1334 | else => unreachable, // unhandled architecture type |
| | 1335 | }; |
| | 1336 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| | 1337 | const needed_size = self.base.options.program_code_size_hint; |
| | 1338 | const off = self.header_pad; |
| 1322 | | 1339 | |
| 1323 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1340 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); |
| 1324 | | 1341 | |
| 1325 | try text_segment.sections.append(self.base.allocator, .{ | 1342 | try text_segment.addSection(self.base.allocator, .{ |
| 1326 | .sectname = makeStaticString("__text"), | 1343 | .sectname = makeStaticString("__text"), |
| 1327 | .segname = makeStaticString("__TEXT"), | 1344 | .segname = makeStaticString("__TEXT"), |
| 1328 | .addr = text_segment.inner.vmaddr + off, | 1345 | .addr = text_segment.inner.vmaddr + off, |
| 1329 | .size = file_size, | 1346 | .size = @intCast(u32, needed_size), |
| 1330 | .offset = off, | 1347 | .offset = off, |
| 1331 | .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, // 2^2 for aarch64, 2^0 for x86_64 | 1348 | .@"align" = alignment, |
| 1332 | .reloff = 0, | 1349 | .reloff = 0, |
| 1333 | .nreloc = 0, | 1350 | .nreloc = 0, |
| 1334 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 1351 | .flags = flags, |
| 1335 | .reserved1 = 0, | 1352 | .reserved1 = 0, |
| 1336 | .reserved2 = 0, | 1353 | .reserved2 = 0, |
| 1337 | .reserved3 = 0, | 1354 | .reserved3 = 0, |
| 1338 | }); | 1355 | }); |
| 1339 | | | |
| 1340 | text_segment.inner.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section. | | |
| 1341 | text_segment.inner.filesize = file_size + off; | | |
| 1342 | text_segment.inner.cmdsize += @sizeOf(macho.section_64); | | |
| 1343 | text_segment.inner.nsects += 1; | | |
| 1344 | self.cmd_table_dirty = true; | 1356 | self.cmd_table_dirty = true; |
| 1345 | } | 1357 | } |
| 1346 | if (self.got_section_index == null) { | 1358 | if (self.got_section_index == null) { |
| ... | @@ -1348,48 +1360,48 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1348,48 +1360,48 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1348 | const text_section = &text_segment.sections.items[self.text_section_index.?]; | 1360 | const text_section = &text_segment.sections.items[self.text_section_index.?]; |
| 1349 | self.got_section_index = @intCast(u16, text_segment.sections.items.len); | 1361 | self.got_section_index = @intCast(u16, text_segment.sections.items.len); |
| 1350 | | 1362 | |
| 1351 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1363 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1352 | // TODO looking for free space should be done *within* a segment it belongs to | 1364 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1353 | const off = @intCast(u32, text_section.offset + text_section.size); | 1365 | const off = text_segment.findFreeSpace(needed_size, @sizeOf(u64)); |
| 1354 | | 1366 | |
| 1355 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1367 | // TODO Audit this. Is it possible to not find free space? We need to grow __TEXT then. |
| | 1368 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); |
| 1356 | | 1369 | |
| 1357 | try text_segment.sections.append(self.base.allocator, .{ | 1370 | log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); |
| 1358 | .sectname = makeStaticString("__got"), | 1371 | |
| | 1372 | try text_segment.addSection(self.base.allocator, .{ |
| | 1373 | .sectname = makeStaticString("__ziggot"), |
| 1359 | .segname = makeStaticString("__TEXT"), | 1374 | .segname = makeStaticString("__TEXT"), |
| 1360 | .addr = text_section.addr + text_section.size, | 1375 | .addr = text_segment.inner.vmaddr + off, |
| 1361 | .size = file_size, | 1376 | .size = needed_size, |
| 1362 | .offset = off, | 1377 | .offset = off, |
| 1363 | .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, | 1378 | .@"align" = @sizeOf(u64), |
| 1364 | .reloff = 0, | 1379 | .reloff = 0, |
| 1365 | .nreloc = 0, | 1380 | .nreloc = 0, |
| 1366 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 1381 | .flags = flags, |
| 1367 | .reserved1 = 0, | 1382 | .reserved1 = 0, |
| 1368 | .reserved2 = 0, | 1383 | .reserved2 = 0, |
| 1369 | .reserved3 = 0, | 1384 | .reserved3 = 0, |
| 1370 | }); | 1385 | }); |
| 1371 | | | |
| 1372 | const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size); | | |
| 1373 | text_segment.inner.vmsize += added_size; | | |
| 1374 | text_segment.inner.filesize += added_size; | | |
| 1375 | text_segment.inner.cmdsize += @sizeOf(macho.section_64); | | |
| 1376 | text_segment.inner.nsects += 1; | | |
| 1377 | self.cmd_table_dirty = true; | 1386 | self.cmd_table_dirty = true; |
| 1378 | } | 1387 | } |
| 1379 | if (self.linkedit_segment_cmd_index == null) { | 1388 | if (self.linkedit_segment_cmd_index == null) { |
| 1380 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 1389 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1381 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1390 | |
| 1382 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; | 1391 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| 1383 | const initprot = macho.VM_PROT_READ; | 1392 | const initprot = macho.VM_PROT_READ; |
| 1384 | const off = text_segment.inner.fileoff + text_segment.inner.filesize; | 1393 | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| | 1394 | |
| | 1395 | log.debug("found __LINKEDIT segment free space at 0x{x}\n", .{address_and_offset.offset}); |
| | 1396 | |
| 1385 | try self.load_commands.append(self.base.allocator, .{ | 1397 | try self.load_commands.append(self.base.allocator, .{ |
| 1386 | .Segment = SegmentCommand.empty(.{ | 1398 | .Segment = SegmentCommand.empty(.{ |
| 1387 | .cmd = macho.LC_SEGMENT_64, | 1399 | .cmd = macho.LC_SEGMENT_64, |
| 1388 | .cmdsize = @sizeOf(macho.segment_command_64), | 1400 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1389 | .segname = makeStaticString("__LINKEDIT"), | 1401 | .segname = makeStaticString("__LINKEDIT"), |
| 1390 | .vmaddr = text_segment.inner.vmaddr + text_segment.inner.vmsize, | 1402 | .vmaddr = address_and_offset.address, |
| 1391 | .vmsize = 0, | 1403 | .vmsize = 0, |
| 1392 | .fileoff = off, | 1404 | .fileoff = address_and_offset.offset, |
| 1393 | .filesize = 0, | 1405 | .filesize = 0, |
| 1394 | .maxprot = maxprot, | 1406 | .maxprot = maxprot, |
| 1395 | .initprot = initprot, | 1407 | .initprot = initprot, |
| ... | @@ -1397,7 +1409,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1397,7 +1409,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1397 | .flags = 0, | 1409 | .flags = 0, |
| 1398 | }), | 1410 | }), |
| 1399 | }); | 1411 | }); |
| 1400 | self.linkedit_segment_next_offset = @intCast(u32, off); | 1412 | self.linkedit_segment_next_offset = @intCast(u32, address_and_offset.offset); |
| 1401 | self.cmd_table_dirty = true; | 1413 | self.cmd_table_dirty = true; |
| 1402 | } | 1414 | } |
| 1403 | if (self.dyld_info_cmd_index == null) { | 1415 | if (self.dyld_info_cmd_index == null) { |
| ... | @@ -1631,9 +1643,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -1631,9 +1643,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 1631 | | 1643 | |
| 1632 | const expand_text_section = block_placement == null or block_placement.?.next == null; | 1644 | const expand_text_section = block_placement == null or block_placement.?.next == null; |
| 1633 | if (expand_text_section) { | 1645 | if (expand_text_section) { |
| 1634 | const text_capacity = self.allocatedSize(text_section.offset); | | |
| 1635 | const needed_size = (vaddr + new_block_size) - text_section.addr; | 1646 | const needed_size = (vaddr + new_block_size) - text_section.addr; |
| 1636 | assert(needed_size <= text_capacity); // TODO must move the entire text section. | 1647 | assert(needed_size <= text_segment.inner.filesize); // TODO must move the entire text section. |
| 1637 | | 1648 | |
| 1638 | self.last_text_block = text_block; | 1649 | self.last_text_block = text_block; |
| 1639 | text_section.size = needed_size; | 1650 | text_section.size = needed_size; |
| ... | @@ -1692,95 +1703,28 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { | ... | @@ -1692,95 +1703,28 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { |
| 1692 | return self.makeString(new_name); | 1703 | return self.makeString(new_name); |
| 1693 | } | 1704 | } |
| 1694 | | 1705 | |
| 1695 | fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | 1706 | const NextSegmentAddressAndOffset = struct { |
| 1696 | const hdr_size: u64 = @sizeOf(macho.mach_header_64); | 1707 | address: u64, |
| 1697 | if (start < hdr_size) return hdr_size; | 1708 | offset: u64, |
| 1698 | const end = start + satMul(size, alloc_num) / alloc_den; | 1709 | }; |
| 1699 | { | | |
| 1700 | const off = @sizeOf(macho.mach_header_64); | | |
| 1701 | var tight_size: u64 = 0; | | |
| 1702 | for (self.load_commands.items) |cmd| { | | |
| 1703 | tight_size += cmd.cmdsize(); | | |
| 1704 | } | | |
| 1705 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | | |
| 1706 | const test_end = off + increased_size; | | |
| 1707 | if (end > off and start < test_end) { | | |
| 1708 | return test_end; | | |
| 1709 | } | | |
| 1710 | } | | |
| 1711 | if (self.text_segment_cmd_index) |text_index| { | | |
| 1712 | const text_segment = self.load_commands.items[text_index].Segment; | | |
| 1713 | for (text_segment.sections.items) |section| { | | |
| 1714 | const increased_size = satMul(section.size, alloc_num) / alloc_den; | | |
| 1715 | const test_end = section.offset + increased_size; | | |
| 1716 | if (end > section.offset and start < test_end) { | | |
| 1717 | return test_end; | | |
| 1718 | } | | |
| 1719 | } | | |
| 1720 | } | | |
| 1721 | if (self.dyld_info_cmd_index) |dyld_info_index| { | | |
| 1722 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfoOnly; | | |
| 1723 | const tight_size = dyld_info.export_size; | | |
| 1724 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | | |
| 1725 | const test_end = dyld_info.export_off + increased_size; | | |
| 1726 | if (end > dyld_info.export_off and start < test_end) { | | |
| 1727 | return test_end; | | |
| 1728 | } | | |
| 1729 | } | | |
| 1730 | if (self.symtab_cmd_index) |symtab_index| { | | |
| 1731 | const symtab = self.load_commands.items[symtab_index].Symtab; | | |
| 1732 | { | | |
| 1733 | const tight_size = @sizeOf(macho.nlist_64) * symtab.nsyms; | | |
| 1734 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | | |
| 1735 | const test_end = symtab.symoff + increased_size; | | |
| 1736 | if (end > symtab.symoff and start < test_end) { | | |
| 1737 | return test_end; | | |
| 1738 | } | | |
| 1739 | } | | |
| 1740 | { | | |
| 1741 | const increased_size = satMul(symtab.strsize, alloc_num) / alloc_den; | | |
| 1742 | const test_end = symtab.stroff + increased_size; | | |
| 1743 | if (end > symtab.stroff and start < test_end) { | | |
| 1744 | return test_end; | | |
| 1745 | } | | |
| 1746 | } | | |
| 1747 | } | | |
| 1748 | return null; | | |
| 1749 | } | | |
| 1750 | | 1710 | |
| 1751 | fn allocatedSize(self: *MachO, start: u64) u64 { | 1711 | fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 1752 | if (start == 0) | 1712 | const prev_segment_idx = blk: { |
| 1753 | return 0; | 1713 | if (self.data_segment_cmd_index) |idx| { |
| 1754 | var min_pos: u64 = std.math.maxInt(u64); | 1714 | break :blk idx; |
| 1755 | { | 1715 | } else if (self.text_segment_cmd_index) |idx| { |
| 1756 | const off = @sizeOf(macho.mach_header_64); | 1716 | break :blk idx; |
| 1757 | if (off > start and off < min_pos) min_pos = off; | 1717 | } else { |
| 1758 | } | 1718 | unreachable; // unhandled LC_SEGMENT_64 load command before __TEXT |
| 1759 | if (self.text_segment_cmd_index) |text_index| { | | |
| 1760 | const text_segment = self.load_commands.items[text_index].Segment; | | |
| 1761 | for (text_segment.sections.items) |section| { | | |
| 1762 | if (section.offset <= start) continue; | | |
| 1763 | if (section.offset < min_pos) min_pos = section.offset; | | |
| 1764 | } | 1719 | } |
| 1765 | } | 1720 | }; |
| 1766 | if (self.dyld_info_cmd_index) |dyld_info_index| { | 1721 | const prev_segment = self.load_commands.items[prev_segment_idx].Segment; |
| 1767 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfoOnly; | 1722 | const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize; |
| 1768 | if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off; | 1723 | const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize; |
| 1769 | } | 1724 | return .{ |
| 1770 | if (self.symtab_cmd_index) |symtab_index| { | 1725 | .address = address, |
| 1771 | const symtab = self.load_commands.items[symtab_index].Symtab; | 1726 | .offset = offset, |
| 1772 | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff; | 1727 | }; |
| 1773 | if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff; | | |
| 1774 | } | | |
| 1775 | return min_pos - start; | | |
| 1776 | } | | |
| 1777 | | | |
| 1778 | fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 { | | |
| 1779 | var start: u64 = 0; | | |
| 1780 | while (self.detectAllocCollision(start, object_size)) |item_end| { | | |
| 1781 | start = mem.alignForwardGeneric(u64, item_end, min_alignment); | | |
| 1782 | } | | |
| 1783 | return start; | | |
| 1784 | } | 1728 | } |
| 1785 | | 1729 | |
| 1786 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 1730 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| ... | @@ -2068,12 +2012,6 @@ fn writeHeader(self: *MachO) !void { | ... | @@ -2068,12 +2012,6 @@ fn writeHeader(self: *MachO) !void { |
| 2068 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(slice[0..1]), 0); | 2012 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(slice[0..1]), 0); |
| 2069 | } | 2013 | } |
| 2070 | | 2014 | |
| 2071 | /// Saturating multiplication | | |
| 2072 | fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { | | |
| 2073 | const T = @TypeOf(a, b); | | |
| 2074 | return std.math.mul(T, a, b) catch std.math.maxInt(T); | | |
| 2075 | } | | |
| 2076 | | | |
| 2077 | /// Parse MachO contents from existing binary file. | 2015 | /// Parse MachO contents from existing binary file. |
| 2078 | /// TODO This method is incomplete and currently parses only the header | 2016 | /// TODO This method is incomplete and currently parses only the header |
| 2079 | /// plus the load commands. | 2017 | /// plus the load commands. |
| ... | @@ -2148,7 +2086,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { | ... | @@ -2148,7 +2086,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 2148 | self.header = header; | 2086 | self.header = header; |
| 2149 | } | 2087 | } |
| 2150 | | 2088 | |
| 2151 | fn parseAndCmpName(name: []const u8, needle: []const u8) bool { | 2089 | pub fn parseAndCmpName(name: []const u8, needle: []const u8) bool { |
| 2152 | const len = mem.indexOfScalar(u8, name[0..], @as(u8, 0)) orelse name.len; | 2090 | const len = mem.indexOfScalar(u8, name[0..], @as(u8, 0)) orelse name.len; |
| 2153 | return mem.eql(u8, name[0..len], needle); | 2091 | return mem.eql(u8, name[0..len], needle); |
| 2154 | } | 2092 | } |
| ... | @@ -2204,3 +2142,9 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { | ... | @@ -2204,3 +2142,9 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { |
| 2204 | var stream = std.io.fixedBufferStream(buffer); | 2142 | var stream = std.io.fixedBufferStream(buffer); |
| 2205 | try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); | 2143 | try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); |
| 2206 | } | 2144 | } |
| | 2145 | |
| | 2146 | /// Saturating multiplication |
| | 2147 | pub fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { |
| | 2148 | const T = @TypeOf(a, b); |
| | 2149 | return std.math.mul(T, a, b) catch std.math.maxInt(T); |
| | 2150 | } |