diff --git a/scripts/lib/real-ghidra-entry-aliases.mjs b/scripts/lib/real-ghidra-entry-aliases.mjs index dc68ab1250..d628c3172c 100644 --- a/scripts/lib/real-ghidra-entry-aliases.mjs +++ b/scripts/lib/real-ghidra-entry-aliases.mjs @@ -22,20 +22,10 @@ export async function verifyGhidraEntryAliases({ ); const path = join(workspace, "entry-aliases"); try { - // Mach-O function-start metadata would promote the interior control label. - await exec( - compiler, - [ - "-O0", - "-g", - "-fno-inline", - ...(process.platform === "darwin" ? ["-Wl,-no_function_starts"] : []), - source, - "-o", - path, - ], - { env, timeout: 30000 }, - ); + await exec(compiler, ["-O0", "-g", "-fno-inline", source, "-o", path], { + env, + timeout: 30000, + }); const bytes = await readFile(path); await call("close_binary"); const imported = await call("open_binary", { path, provider_id: "ghidra" }); @@ -101,6 +91,18 @@ export async function verifyGhidraEntryAliases({ ); assert.ok(interior); assert.notEqual(interior.address, alias.address); + assert.equal( + interior.symbol.type, + "label", + "Fixture interior control must remain an imported label", + ); + assert.equal( + (await call("list_procedures")).some( + ({ address }) => address === interior.address, + ), + false, + "Fixture interior control must not be a Ghidra procedure entry", + ); const failure = await reject("procedure_address", { procedure: interior.value, }); diff --git a/tests/conformance/ghidra/entry-aliases.c b/tests/conformance/ghidra/entry-aliases.c index af152827a5..554dfc77b9 100644 --- a/tests/conformance/ghidra/entry-aliases.c +++ b/tests/conformance/ghidra/entry-aliases.c @@ -9,10 +9,23 @@ volatile int rea_xrefs_data = 17; __attribute__((used)) volatile int rea_xrefs_unreferenced = 41; __attribute__((noinline, used)) int rea_alias_target(void) { - // ARM64 leaf functions may have no prologue; keep the control past entry. - __asm__ volatile("nop\n.globl " REA_SYMBOL("rea_interior") "\n" - REA_SYMBOL("rea_interior") ":"); - return rea_xrefs_data; + int value = rea_xrefs_data; + // Preserve normal function-start metadata. Imported symbols at instruction + // boundaries can become procedure entries, so keep this label inside a NOP. +#if defined(__aarch64__) + __asm__ volatile(".globl " REA_SYMBOL("rea_interior") "\n" + ".byte 0x1f\n" + REA_SYMBOL("rea_interior") ":\n" + ".byte 0x20,0x03,0xd5\n" : : "r"(value)); +#elif defined(__x86_64__) + __asm__ volatile(".byte 0x0f\n" + ".globl " REA_SYMBOL("rea_interior") "\n" + REA_SYMBOL("rea_interior") ":\n" + ".byte 0x1f,0x00\n" : : "r"(value)); +#else +#error "The Ghidra entry-alias fixture supports only x86_64 and arm64" +#endif + return value; } __asm__(".globl " REA_SYMBOL("rea_entry_alias") "\n"