Add C symbol support to name mangling Ghida script

This commit is contained in:
KeybadeBlox 2026-02-17 20:19:14 -05:00
parent d435282a8b
commit 92179ea9bd

View file

@ -11,6 +11,9 @@
// appear in objdiff, replacing spaces with underscores, e.g. "operator_new" // appear in objdiff, replacing spaces with underscores, e.g. "operator_new"
// and "`scalar_deleting_destructor'" (notice the ` and '). // and "`scalar_deleting_destructor'" (notice the ` and ').
// //
// MSVC also applies minor name mangling to C symbols. This can be enabled for
// a given symbol by placing it in a top-level namespace named extern_"C".
//
// This script can be called in headless mode with the address ranges to mangle // This script can be called in headless mode with the address ranges to mangle
// as arguments, e.g. 0x1234-0x5678. Any symbols referenced by functions being // as arguments, e.g. 0x1234-0x5678. Any symbols referenced by functions being
// mangled will also be mangled in this mode (so that the references are // mangled will also be mangled in this mode (so that the references are
@ -135,21 +138,56 @@ public class MSVC7Mangle extends GhidraScript{
/* Generate a mangled name for a function */ /* Generate a mangled name for a function */
final String nameRaw = f.getName(true); final String nameRaw = f.getName(true);
// Internal symbols like intrinsics aren't mangled // main() and extern "C" symbols get C name mangling
if (nameRaw.startsWith("_")) return nameRaw; // (some other things, do, too, but just use extern "C" instead
// of making me find and list them all...)
// Other special cases return nameRaw == "main" ||
switch (nameRaw) { nameRaw.startsWith("extern_\"C\"::") ? mangleCFn (f)
case "atexit": return "_atexit"; : mangleCppFn(f);
case "main" : return "_main" ;
default : {}
} }
private static String mangleCFn(final Function f) throws Exception {
/* Produce a C function mangled name
(MSVC does indeed do this despite the folk wisdom that only C++ gets
name mangling; it is certainly simpler than the C++ sort, at least)
*/
return switch (f.getCallingConventionName()) {
case "__cdecl" -> "_" + f.getName(false);
case "__stdcall" -> "_" + f.getName(false) + argSize(f);
case "__fastcall" -> "@" + f.getName(false) + argSize(f);
case "__thiscall" -> throw new Exception(
f.getName() +
"(): __thiscall not allowed for C symbols"
);
default -> throw new Exception(
f.getName() +
"(): Need to specify calling convention"
);
};
}
private static String argSize(final Function f) {
/* Produce the argument size suffix for a C function
The format is "@123" where "123" is however many bytes the arguments
occupy (each argument occupies at least four bytes).
*/
return "@" + Arrays.stream(f.getSignature(true).getArguments())
.map(ParameterDefinition::getDataType)
.map(t -> Math.max(t.getLength(), 4))
.reduce(0, Integer::sum)
.toString();
}
private String mangleCppFn(final Function f) throws Exception {
/* Produce a C++ function mangled name */
final String nameRaw = f.getName(true);
final ArrayList<String> dict = new ArrayList<>(); final ArrayList<String> dict = new ArrayList<>();
final List<String> nameParts = Arrays.asList(nameRaw.split("::")); final List<String> nameParts = Arrays.asList(nameRaw.split("::"));
Collections.reverse(nameParts); Collections.reverse(nameParts);
final boolean isMethod = f.getCallingConventionName().equals("__thiscall") && final boolean isMethod = f.getCallingConventionName()
.equals("__thiscall") &&
nameParts.size() >= 2; nameParts.size() >= 2;
final String name = mangleIdentifier(nameRaw, isMethod, f.getReturnType(), dict); final String name = mangleIdentifier(nameRaw, isMethod, f.getReturnType(), dict);
@ -500,6 +538,11 @@ public class MSVC7Mangle extends GhidraScript{
); );
// Other data // Other data
if (name.startsWith("extern_\"C\"::")) {
final String[] nameParts = name.split("::");
return "_" + nameParts[nameParts.length - 1];
}
final ArrayList<String> dict = new ArrayList<>(); final ArrayList<String> dict = new ArrayList<>();
final String ident = mangleIdentifier(name, false, null, dict); final String ident = mangleIdentifier(name, false, null, dict);