mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #7918 from Kernel-Hunter/fix/rosetta-xsaveopt
fix(relinker): rewrite XSAVEOPT to XSAVE under --to-rosetta
This commit is contained in:
8 files changed
+86
-8
No files matched your search
@@ -42,6 +42,7 @@ inline constexpr Entry kRdseed = {"RDSEED", nullptr, 0};
|
||||
inline constexpr Entry kRdpid = {"RDPID", nullptr, 0};
|
||||
inline constexpr Entry kRdtscp = {"RDTSCP", nullptr, 0};
|
||||
inline constexpr Entry kClwb = {"CLWB", nullptr, 0};
|
||||
inline constexpr Entry kXsaveopt = {"XSAVEOPT", nullptr, 0};
|
||||
inline constexpr Entry kWideStore = {"256-bit store", nullptr, 0};
|
||||
inline constexpr Entry kScalarCompare = {"scalar compare", nullptr, 0};
|
||||
inline constexpr Entry kExtrq = {"EXTRQ", nullptr, 0};
|
||||
|
||||
@@ -27,6 +27,7 @@ struct DecodedInstruction {
|
||||
[[nodiscard]] bool IsRdpid() const;
|
||||
[[nodiscard]] bool IsRdtscp() const;
|
||||
[[nodiscard]] bool IsClwb() const;
|
||||
[[nodiscard]] bool IsXsaveopt() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::size_t _skipPrefixesAndRex(bool* outHasOperandSizePrefix, bool* outHasRepnePrefix, bool* outHasRepPrefix) const;
|
||||
|
||||
@@ -260,6 +260,11 @@ std::optional<Amd64OnlyMatch> Amd64OnlyInstructionMatcher::_matchRosetta(const D
|
||||
}
|
||||
if (instr.IsClwb())
|
||||
return _inPlace(kClwb, instr.Length, {});
|
||||
if (instr.IsXsaveopt()) {
|
||||
std::vector<std::uint8_t> replacement(instr.Data, instr.Data + instr.Length);
|
||||
replacement[instr.OpcodeOffset() + 2] &= static_cast<std::uint8_t>(~(2u << X64OpcodeConstants::ModRmRegShift));
|
||||
return Amd64OnlyMatch{kXsaveopt.Name, instr.Length, Amd64OnlyLowering::InPlace, std::move(replacement), {}, 0};
|
||||
}
|
||||
if (instr.IsRdpid())
|
||||
return _trampoline(kRdpid.Name, instr.Length, _outOfLine(instr.Length, trailing, [&](StubBodyBuilder& body) { body.Raw(_rdpidReplacement(instr)); }), true);
|
||||
if (instr.IsRdtscp())
|
||||
|
||||
@@ -324,6 +324,21 @@ bool DecodedInstruction::IsClwb() const {
|
||||
((modrm >> ModRmModShift) & ModRmModMask) != ModRmModRegister && ((modrm >> ModRmRegShift) & ModRmRegMask) == 6;
|
||||
}
|
||||
|
||||
bool DecodedInstruction::IsXsaveopt() const {
|
||||
bool operandSizeOverride = false;
|
||||
bool repnePrefix = false;
|
||||
bool repPrefix = false;
|
||||
const std::size_t pos = _skipPrefixesAndRex(&operandSizeOverride, &repnePrefix, &repPrefix);
|
||||
|
||||
if (operandSizeOverride || repnePrefix || repPrefix || pos + 2 >= Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modrm = Data[pos + 2];
|
||||
return Data[pos] == TwoByteOpcodeEscape && Data[pos + 1] == TwoByteGrp15 &&
|
||||
((modrm >> ModRmModShift) & ModRmModMask) != ModRmModRegister && ((modrm >> ModRmRegShift) & ModRmRegMask) == 6;
|
||||
}
|
||||
|
||||
bool DecodedInstruction::IsMovntss() const {
|
||||
bool operandSizeOverride = false;
|
||||
bool repnePrefix = false;
|
||||
|
||||
@@ -690,8 +690,8 @@ void rosettaSubstitutions() {
|
||||
const auto intel = Codegen::MakeAmd64OnlyInstructionMatcher();
|
||||
const auto rosetta = Codegen::MakeAmd64OnlyInstructionMatcher(Codegen::Amd64OnlyTarget::Rosetta);
|
||||
const auto match = [](const auto& matcher, const Bytes& bytes) { return matcher->Match(bytes.data(), bytes.size()); };
|
||||
for (const auto& bytes : {Bytes{0x0F, 0xC7, 0xF8}, Bytes{0xF3, 0x0F, 0xC7, 0xF8}, Bytes{0x66, 0x0F, 0xAE, 0x30}, Bytes{0x0F, 0x01, 0xF9}})
|
||||
require(!match(intel, bytes).has_value(), "RDSEED, RDPID, CLWB or RDTSCP was converted for an Intel host");
|
||||
for (const auto& bytes : {Bytes{0x0F, 0xC7, 0xF8}, Bytes{0xF3, 0x0F, 0xC7, 0xF8}, Bytes{0x66, 0x0F, 0xAE, 0x30}, Bytes{0x0F, 0x01, 0xF9}, Bytes{0x0F, 0xAE, 0x37}})
|
||||
require(!match(intel, bytes).has_value(), "RDSEED, RDPID, CLWB, RDTSCP or XSAVEOPT was converted for an Intel host");
|
||||
const auto rdseed = match(rosetta, {0x48, 0x0F, 0xC7, 0xF9});
|
||||
require(rdseed && rdseed->Lowering == Amd64OnlyLowering::InPlace && rdseed->ReplacementBytes == Bytes{0x48, 0x0F, 0xC7, 0xF1} && rdseed->InstructionName == "RDSEED", "RDSEED was not rewritten to RDRAND");
|
||||
const auto rdseed16 = match(rosetta, {0x66, 0x41, 0x0F, 0xC7, 0xFA});
|
||||
@@ -701,6 +701,18 @@ void rosettaSubstitutions() {
|
||||
require(clwb && clwb->Lowering == Amd64OnlyLowering::InPlace && clwb->ReplacementBytes == Bytes{0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00} && clwb->InstructionName == "CLWB", "CLWB was not replaced by a NOP");
|
||||
require(!match(rosetta, {0x66, 0x0F, 0xAE, 0xF1}).has_value(), "TPAUSE (the register form of 66 0F AE /6) was taken for CLWB");
|
||||
require(!match(rosetta, {0x66, 0x0F, 0xAE, 0x38}).has_value(), "CLFLUSHOPT was taken for CLWB");
|
||||
const auto xsaveopt = match(rosetta, {0x0F, 0xAE, 0x37});
|
||||
require(xsaveopt && xsaveopt->Lowering == Amd64OnlyLowering::InPlace && xsaveopt->ReplacementBytes == Bytes{0x0F, 0xAE, 0x27} && xsaveopt->InstructionName == "XSAVEOPT", "XSAVEOPT was not rewritten to XSAVE");
|
||||
const auto xsaveopt64 = match(rosetta, {0x48, 0x0F, 0xAE, 0x74, 0x24, 0x40});
|
||||
require(xsaveopt64 && xsaveopt64->ReplacementBytes == Bytes{0x48, 0x0F, 0xAE, 0x64, 0x24, 0x40}, "XSAVEOPT64 with an RSP-relative operand was not rewritten to XSAVE64");
|
||||
const auto xsaveoptR12 = match(rosetta, {0x41, 0x0F, 0xAE, 0x34, 0x24});
|
||||
require(xsaveoptR12 && xsaveoptR12->ReplacementBytes == Bytes{0x41, 0x0F, 0xAE, 0x24, 0x24}, "XSAVEOPT with an extended base register was not rewritten to XSAVE");
|
||||
const auto xsaveoptRip = match(rosetta, {0x0F, 0xAE, 0x35, 0x00, 0x01, 0x00, 0x00});
|
||||
require(xsaveoptRip && xsaveoptRip->ReplacementBytes == Bytes{0x0F, 0xAE, 0x25, 0x00, 0x01, 0x00, 0x00}, "RIP-relative XSAVEOPT was not rewritten to XSAVE with the same displacement");
|
||||
const auto xsaveoptFs = match(rosetta, {0x64, 0x0F, 0xAE, 0x34, 0x25, 0x40, 0x00, 0x00, 0x00});
|
||||
require(xsaveoptFs && xsaveoptFs->ReplacementBytes == Bytes{0x64, 0x0F, 0xAE, 0x24, 0x25, 0x40, 0x00, 0x00, 0x00}, "FS-relative XSAVEOPT was not rewritten to XSAVE");
|
||||
for (const auto& other : {Bytes{0x0F, 0xAE, 0x27}, Bytes{0x0F, 0xAE, 0x2F}, Bytes{0x0F, 0xAE, 0x3F}, Bytes{0x0F, 0xAE, 0xF0}, Bytes{0xF3, 0x0F, 0xAE, 0xF0}, Bytes{0xF2, 0x0F, 0xAE, 0xF1}, Bytes{0xF3, 0x0F, 0xAE, 0x37}})
|
||||
require(!match(rosetta, other).has_value(), "XSAVE, XRSTOR, CLFLUSH, MFENCE, UMONITOR, UMWAIT or a prefixed 0F AE /6 was taken for XSAVEOPT");
|
||||
const auto rdpid = match(rosetta, {0xF3, 0x41, 0x0F, 0xC7, 0xFB});
|
||||
require(rdpid && rdpid->Lowering == Amd64OnlyLowering::Trampoline && rdpid->Optional && rdpid->InstructionName == "RDPID", "RDPID was not lowered through an optional stub");
|
||||
require(rdpid->ReturnBranchOffset == 6 && Bytes(rdpid->StubBody.begin(), rdpid->StubBody.begin() + 7) == Bytes{0x41, 0xBB, 0, 0, 0, 0, 0xE9}, "RDPID r11 stub does not load 0 before returning");
|
||||
@@ -2008,6 +2020,45 @@ void wideStoreExecution() {
|
||||
munmap(pages, 8192);
|
||||
munmap(code, 4096);
|
||||
}
|
||||
|
||||
void xsaveoptExecution() {
|
||||
const Bytes site = {0x48, 0x0F, 0xAE, 0x37};
|
||||
const auto match = Codegen::MakeAmd64OnlyInstructionMatcher(Codegen::Amd64OnlyTarget::Rosetta)->Match(site.data(), site.size());
|
||||
require(match && match->Lowering == Codegen::Amd64OnlyLowering::InPlace, "XSAVEOPT64 was not rewritten in place");
|
||||
auto body = match->ReplacementBytes;
|
||||
body.push_back(0xC3);
|
||||
void* code = mmap(nullptr, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
require(code != MAP_FAILED, "cannot map executable memory for the XSAVEOPT replacement");
|
||||
std::memcpy(code, body.data(), body.size());
|
||||
alignas(64) std::uint8_t area[1024] = {};
|
||||
alignas(32) std::uint8_t pattern[32];
|
||||
alignas(32) std::uint8_t restored[32] = {};
|
||||
for (std::size_t i = 0; i < sizeof(pattern); ++i)
|
||||
pattern[i] = static_cast<std::uint8_t>(0xA0 + i);
|
||||
asm volatile(
|
||||
"vmovdqu (%[pattern]), %%ymm3\n\t"
|
||||
"mov %[area], %%rdi\n\t"
|
||||
"mov $7, %%eax\n\t"
|
||||
"xor %%edx, %%edx\n\t"
|
||||
"sub $128, %%rsp\n\t"
|
||||
"call *%[code]\n\t"
|
||||
"add $128, %%rsp\n\t"
|
||||
"vpxor %%ymm3, %%ymm3, %%ymm3\n\t"
|
||||
"mov $7, %%eax\n\t"
|
||||
"xor %%edx, %%edx\n\t"
|
||||
"xrstor64 (%%rdi)\n\t"
|
||||
"vmovdqu %%ymm3, (%[restored])\n\t"
|
||||
"vzeroupper\n\t"
|
||||
:
|
||||
: [pattern] "r"(pattern), [area] "r"(area), [code] "r"(code), [restored] "r"(restored)
|
||||
: "rax", "rdx", "rdi", "xmm3", "memory");
|
||||
munmap(code, 4096);
|
||||
std::uint64_t components = 0;
|
||||
std::memcpy(&components, area + 512, sizeof(components));
|
||||
require((components & 6) == 6, "XSAVE did not mark the SSE and AVX state as saved");
|
||||
require(std::memcmp(area + 160 + 3 * 16, pattern, 16) == 0 && std::memcmp(area + 576 + 3 * 16, pattern + 16, 16) == 0, "XSAVE did not store YMM3 in the standard format");
|
||||
require(std::memcmp(restored, pattern, sizeof(pattern)) == 0, "XRSTOR did not restore YMM3 from the area XSAVE wrote");
|
||||
}
|
||||
#else
|
||||
void reciprocalExecution() {}
|
||||
void registerFormExecution() {}
|
||||
@@ -2018,6 +2069,7 @@ void immediateFormExecution() {}
|
||||
void ripRelativeExecution() {}
|
||||
void rdpruExecution() {}
|
||||
void mcommitExecution() {}
|
||||
void xsaveoptExecution() {}
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__) && (defined(__linux__) || defined(__APPLE__))
|
||||
@@ -2106,6 +2158,7 @@ int main() {
|
||||
converterInPlaceFollower();
|
||||
converterClzero();
|
||||
rosettaSubstitutions();
|
||||
xsaveoptExecution();
|
||||
converterRosetta();
|
||||
rosettaScalarCompares();
|
||||
converterRosettaScalarCompare();
|
||||
|
||||
@@ -12,8 +12,10 @@ RDSEED = bytes.fromhex("0fc7f8")
|
||||
RDRAND = bytes.fromhex("0fc7f0")
|
||||
CLWB = bytes.fromhex("660fae37")
|
||||
NOP4 = bytes.fromhex("0f1f4000")
|
||||
SITES = RDSEED + CLWB + b"\xc3"
|
||||
LOWERED = RDRAND + NOP4 + b"\xc3"
|
||||
XSAVEOPT = bytes.fromhex("480fae37")
|
||||
XSAVE = bytes.fromhex("480fae27")
|
||||
SITES = RDSEED + CLWB + XSAVEOPT + b"\xc3"
|
||||
LOWERED = RDRAND + NOP4 + XSAVE + b"\xc3"
|
||||
|
||||
|
||||
def executable(code=SITES):
|
||||
@@ -38,18 +40,18 @@ def main():
|
||||
result, output = relink(relinker, directory, "keep" + "".join(options), *options)
|
||||
assert result.returncode == 0, (options, result.stdout, result.stderr)
|
||||
data = output.read_bytes()
|
||||
assert SITES in data and LOWERED not in data, f"{options or 'a plain relink'} changed RDSEED or CLWB"
|
||||
assert SITES in data and LOWERED not in data, f"{options or 'a plain relink'} changed RDSEED, CLWB or XSAVEOPT"
|
||||
for options in (("--to-rosetta",), ("--to-rosetta", "--to-intel")):
|
||||
result, output = relink(relinker, directory, "lower" + "".join(options), *options)
|
||||
assert result.returncode == 0, (options, result.stdout, result.stderr)
|
||||
data = output.read_bytes()
|
||||
assert LOWERED in data and SITES not in data, f"{options} did not lower RDSEED and CLWB"
|
||||
assert LOWERED in data and SITES not in data, f"{options} did not lower RDSEED, CLWB and XSAVEOPT"
|
||||
for options, lowered in ((("--macos",), False), (("--macos", "--to-intel"), False), (("--macos", "--to-rosetta"), True)):
|
||||
result, output = relink(relinker, directory, "macos" + "".join(options), *options)
|
||||
assert result.returncode == 0, (options, result.stdout, result.stderr)
|
||||
data = output.read_bytes()
|
||||
assert data[:4] == bytes.fromhex("cffaedfe"), f"{options} did not write a Mach-O"
|
||||
assert (LOWERED in data and SITES not in data) if lowered else (SITES in data and LOWERED not in data), f"{options} {'did not lower' if lowered else 'changed'} RDSEED and CLWB"
|
||||
assert (LOWERED in data and SITES not in data) if lowered else (SITES in data and LOWERED not in data), f"{options} {'did not lower' if lowered else 'changed'} RDSEED, CLWB and XSAVEOPT"
|
||||
result, _ = relink(relinker, directory, "windows", "--to-rosetta", "--windows")
|
||||
assert result.returncode != 0 and "--to-rosetta conflicts with --windows" in result.stdout + result.stderr, "--to-rosetta together with --windows was accepted"
|
||||
andn = bytes.fromhex("c4e2f0f2c6c3")
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
- `--to-rosetta` lowers what Rosetta lacks on top of `--to-intel` ([matcher](../../../core/relinker/codegen/src/x86/Amd64OnlyInstructionMatcher.cpp)). AVX2, FMA, BMI1/2, F16C and MOVBE were observed to execute on an M5 Max without being reported through CPUID; this is not a guarantee for other Rosetta hosts. ANDN and RDRAND fault on an M1 running macOS 15.3.1 and execute on an M1 running macOS 26.6.2, so on the M1 the difference follows the macOS version; on that host BEXTR, BLSI, BLSMSK, BLSR, TZCNT, LZCNT, POPCNT, BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX, MOVBE, FMA, AVX2 and F16C execute as well, its CPUID leaf 1 reports none of MOVBE, FMA, AVX or F16C, and RDSEED, RDPID, CLWB, ADCX and ADOX raise SIGILL. They also execute on an M5 running macOS 26.4, where the rest of BMI1 and BMI2, LZCNT, PREFETCHW, CLFLUSHOPT, AVX, AVX2, FMA, F16C and MOVBE execute as well although CPUID leaf 7 reads zero and leaves 1 and 0x80000001 report none of them, and where RDSEED, CLWB, RDPID, ADCX and ADOX raise an illegal instruction. ANDN is lowered, but RDRAND and other BMI instructions still depend on the host. RDSEED becomes RDRAND and CLWB a NOP. RDPID returns processor 0, and RDTSCP runs unchanged with ECX set to 0 after it, because Rosetta's TSC_AUX is the constant 0xAAAAAAAB (also measured on an M5, macOS 27.0.1). An RDPID or RDTSCP site with no movable instruction after it for the jump is kept; a kept RDTSCP reports 0xAAAAAAAB. ADCX/ADOX fault under Rosetta and are not converted: compilers do not emit them, and code that checks CPUID sees no ADX. The conversions are covered by the converter tests. ANDN lowering is also executed by an x86-64 test build under Rosetta on the M1; the other conversions were originally checked on an M5 Max, outside this repository's CI.
|
||||
- `--to-rosetta` output faults on an M2 running macOS 14.8.9 when it reaches AVX, AVX2, FMA, F16C, RDRAND or a BMI1/BMI2 instruction other than ANDN, TZCNT and LZCNT: Rosetta on that host raises SIGILL for them and for RDSEED, RDPID, CLWB, ADCX and ADOX ([matcher](../../../core/relinker/codegen/src/x86/Amd64OnlyInstructionMatcher.cpp)). Only TZCNT, LZCNT, POPCNT, MOVBE, CLFLUSHOPT, PREFETCHW and RDTSCP execute, and RDTSCP sets ECX to 0xAAAAAAAB. CPUID leaf 1 reports POPCNT and none of MOVBE, AVX, FMA, F16C or RDRAND, leaf 7 reads zero, and leaf 0x80000001 reports RDTSCP but neither LZCNT nor PREFETCHW. An M2 Max on macOS 27.2 reports the same CPUID but executes everything except RDSEED, RDPID, CLWB, ADCX and ADOX, so the faults follow the macOS version, not the chip.
|
||||
- `--to-intel` replaces the approximate legacy SSE and VEX.128 register forms of RSQRTPS/RCPPS and VRSQRTPS/VRCPPS with [correctly rounded](../../../core/relinker/codegen/src/x86/ReciprocalLowering.cpp) 1/sqrt(x) and 1/x, not with the AMD approximation: its tables are not public. Intel's approximation of 1/sqrt(1.0) is 0x3F7FF000, and two Newton-Raphson steps on it settle on 0.99999994 instead of 1.0; a renormalised identity quaternion then turns into a NaN axis in PPSA21564, which the console does not show. Refined results now reach the exact value; unrefined ones can still differ from the console in the low bits. Each site costs an out-of-line stub (two jumps, a spill below the red zone, SQRTPS/DIVPS). Legacy SSE forms preserve the destination's upper YMM bits; VEX forms clear them. The 256-bit, scalar and memory forms keep the native instruction, as does a site shorter than 5 bytes with no movable instruction after it for the jump (5 sites in PPSA21564, counted before a following RIP-relative instruction could move into the stub; not recounted).
|
||||
- XSAVEC raises an illegal instruction under Rosetta and is not converted, because it writes the compacted format. XSAVEOPT, which also faults there, is rewritten to XSAVE in place by the [matcher](../../../core/relinker/codegen/src/x86/Amd64OnlyInstructionMatcher.cpp) under `--to-rosetta` (`0F AE /6` becomes `/4`; prefixes and operand are kept). The two differ only in the init and modified optimizations, which let XSAVEOPT skip writing unchanged or initial state ([Intel SDM volume 1](https://cdrdv2-public.intel.com/812382/253665-sdm-vol-1.pdf), chapter 13), so XRSTOR restores the same state from either area. Measured on one M5 with macOS 27.0.1: XSAVE and XRSTOR handle x87, SSE and AVX state in the standard format, although CPUID leaf 1 reports neither XSAVE nor OSXSAVE and leaf 0xD sub-leaf 1 reports neither XSAVEOPT nor XSAVEC. The converter tests' x86-64 build executes the replacement XSAVE under Rosetta on that host.
|
||||
- `--trace-imports` ([Windows entry stub](../../../core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp), [Linux entry stub](../../../core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp)) exists for Windows and Linux output, not macOS. Only imports bound through a PLT slot, or through a GOT slot whose symbol is a function, are traced; a function reached through any other relocation, or looked up at run time with `sceKernelDlsym`, is not, and neither are weak imports or the imports of modules loaded at run time. On Linux the entry stub makes the page of every traced slot readable, writable and executable with `mprotect` before it stores the thunk, so a slot inside `PT_GNU_RELRO` can be replaced; those pages stay writable, and data pages become executable, while tracing is on
|
||||
|
||||
- [ANDN lowering](../../../core/relinker/codegen/src/x86/AndnLowering.cpp) uses scalar NOT and AND for 32- and 64-bit register and memory operands under `--to-rosetta`, following the ANDN entry in [Intel SDM volume 2A](https://cdrdv2-public.intel.com/812383/253666-sdm-vol-2a.pdf). SF and ZF follow the result, CF and OF clear, and AF and PF are undefined. The scratch register is saved below the 128-byte red zone. A 64-bit stack-relative displacement that exceeds signed disp32 after reserving the spill frame throws; other BMI instructions are not lowered. The M1 test covers register overlap, RSP operands, memory addressing, RIP relocation, flags and red-zone preservation; precise fault delivery inside a spill sequence has not been verified.
|
||||
+1
-1
@@ -69,7 +69,7 @@ All switches are disabled by default. `unused-filter` defaults to `0`; `--rpath`
|
||||
| `--linux-fixed-base <address>` | Load the Linux executable at this fixed address instead of the default `0x400000`, given in decimal or hexadecimal (`0x`): every virtual address of the image is offset by it, so virtual address 0 is placed at the address, as the console places an executable. Requires a 64 KiB-aligned address from `0x10000` through `0x7fffffff0000` that is a multiple of every `PT_LOAD` alignment, and an image that ends in the user address space. The executable is written as `ET_EXEC`, without ASLR, as it is at the default address. Bundled modules keep their normal placement. Conflicts with `--windows`, `--macos` and `--lazy-binding`. |
|
||||
| `--macos-fixed-base <address>` | Map the lowest ELF load page of the macOS executable at this fixed address, given in decimal or hexadecimal (`0x`). Requires `--macos`, a 64 KiB-aligned address from `0x20000` through `0x7fffffff0000`, and an image that ends in the macOS user address space. `__PAGEZERO` ends 64 KiB below the address and the Mach-O header occupies those 64 KiB. The executable has no ASLR; an address the process cannot map fails to load. Bundled modules keep their normal placement. |
|
||||
| `--to-intel` | Convert supported AMD-only instructions in the executable and bundled modules. Unsupported instructions or unreachable conversion stubs cause an error. |
|
||||
| `--to-rosetta` | Convert as `--to-intel` does and also lower what Rosetta lacks: ANDN becomes scalar NOT/AND, RDSEED becomes RDRAND, CLWB a NOP, and RDPID and the ECX of RDTSCP return processor 0. Implies `--to-intel`. Independent of `--macos`: `--macos` alone leaves these instructions as they are. Conflicts with `--windows`. |
|
||||
| `--to-rosetta` | Convert as `--to-intel` does and also lower what Rosetta lacks: ANDN becomes scalar NOT/AND, RDSEED becomes RDRAND, CLWB a NOP, XSAVEOPT becomes XSAVE, and RDPID and the ECX of RDTSCP return processor 0. Implies `--to-intel`. Independent of `--macos`: `--macos` alone leaves these instructions as they are. Conflicts with `--windows`. |
|
||||
| `unused-filter=0` | Keep all imported NID references. |
|
||||
| `unused-filter=1` | Filter unused non-PLT imports using control-flow and GOT access analysis, treating address-taken code as reachable; preserve PLT imports. |
|
||||
| `unused-filter=2` | Apply strict unused-import analysis and compact the PLT. Unsupported analysis cases cause an error. |
|
||||
|
||||
Reference in new issue
Block a user