fix(hopper): make loader selection non-interactive

This commit is contained in:
morluto 2026-07-12 08:33:33 +08:00
parent c6bf2799e6
commit 2b7ef8610d
2 changed files with 37 additions and 13 deletions

View File

@ -88,7 +88,7 @@ const parseThinMachO = (
format: "mach-o",
architecture,
availableArchitectures: [architecture],
loaderArgs: ["-l", "Mach-O"],
loaderArgs: ["-l", "Mach-O", hopperArchitectureFlag(architecture)],
});
};
@ -124,19 +124,17 @@ const parseFatMachO = (
: undefined;
if (preferred === undefined || !architectures.includes(preferred))
return err(`FAT binary has no host-compatible ${host} architecture`);
const flag =
preferred === "arm64"
? "--aarch64"
: preferred === "x86_64"
? "--x86_64"
: preferred === "arm"
? "--arm"
: "--x86";
return ok({
format: "mach-o",
architecture: preferred,
availableArchitectures: architectures,
loaderArgs: ["-l", "FAT", flag, "-l", "Mach-O"],
loaderArgs: [
"-l",
"FAT",
hopperArchitectureFlag(preferred),
"-l",
"Mach-O",
],
});
};
@ -152,7 +150,7 @@ const parseElf = (bytes: Buffer): Result<ExecutableMetadata, string> => {
format: "elf",
architecture,
availableArchitectures: [architecture],
loaderArgs: ["-l", "ELF"],
loaderArgs: ["-l", "ELF", hopperArchitectureFlag(architecture)],
});
};
@ -170,7 +168,7 @@ const parsePe = (bytes: Buffer): Result<ExecutableMetadata, string> => {
format: "pe",
architecture,
availableArchitectures: [architecture],
loaderArgs: ["-l", "PE"],
loaderArgs: ["-l", "WinPE", hopperArchitectureFlag(architecture)],
});
};
@ -215,3 +213,16 @@ const peArchitecture = (machine: number): BinaryArchitecture | undefined => {
}
return undefined;
};
const hopperArchitectureFlag = (architecture: BinaryArchitecture): string => {
switch (architecture) {
case "x86":
return "--intel-32";
case "x86_64":
return "--intel-64";
case "arm":
return "--armv7";
case "arm64":
return "--aarch64";
}
};

View File

@ -33,9 +33,22 @@ describe("executable header parsing", () => {
const arm = parseExecutableHeader(bytes, "arm64");
const intel = parseExecutableHeader(bytes, "x64");
expect(arm.ok && arm.value.loaderArgs).toContain("--aarch64");
expect(intel.ok && intel.value.loaderArgs).toContain("--x86_64");
expect(intel.ok && intel.value.loaderArgs).toContain("--intel-64");
});
it.each([
[thinMach(0xfeedfacf, 0x0100000c), ["-l", "Mach-O", "--aarch64"]],
[thinMach(0xcefaedfe, 0x01000007), ["-l", "Mach-O", "--intel-64"]],
[elf(2, 2, 183), ["-l", "ELF", "--aarch64"]],
[pe(0x8664), ["-l", "WinPE", "--intel-64"]],
] as const)(
"emits a complete non-interactive Hopper selection",
(bytes, args) => {
const result = parseExecutableHeader(bytes, "arm64");
expect(result.ok && result.value.loaderArgs).toEqual(args);
},
);
it("rejects FAT files without a host-compatible slice", () => {
expect(parseExecutableHeader(fat([0x01000007]), "arm64")).toMatchObject({
ok: false,