[PR #1949] [MERGED] feat(ghidra): admit soft-float MIPS32r2 ELF with integer-register float storage #4930

Closed
opened 2026-10-31 00:57:00 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1949
Author: @AurelioB
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @morluto

Base: main ← Head: feat/mips-soft-float


📝 Commits (3)

  • b992aa6 feat(ghidra): admit soft-float MIPS32r2 ELF with integer-register float storage
  • 5965eae fix(ghidra): model soft-float MIPS as a prototype for every typed callable
  • c5d346c test(ghidra): pin ODDSPREG acceptance for soft-float MIPS ABI records

📊 Changes

17 files changed (+958 additions, -34 deletions)

View changed files

📝 bridge/ghidra/ReaGhidraBridge.java (+5 -0)
➕ bridge/ghidra/ReaGhidraMipsSoftFloat.java (+176 -0)
📝 docs/ghidra-mips.md (+49 -8)
📝 package.json (+1 -0)
📝 scripts/verify-real-ghidra-mips.mjs (+83 -7)
📝 src/ghidra/GhidraLauncher.ts (+23 -0)
📝 src/ghidra/GhidraMipsProfile.test.ts (+153 -0)
📝 src/ghidra/GhidraMipsProfile.ts (+58 -4)
📝 src/ghidra/GhidraProviderClient.ts (+47 -2)
📝 src/ghidra/GhidraSessionValues.test.ts (+34 -0)
📝 src/ghidra/GhidraSessionValues.ts (+9 -0)
📝 tests/boundary/providers/ghidra/ghidraLauncher.test.ts (+39 -0)
➕ tests/conformance/c/mips-soft-float.c (+53 -0)
📝 tests/conformance/ghidra/mips-checks.d.mts (+8 -8)
📝 tests/conformance/ghidra/mips-checks.mjs (+83 -3)
📝 tests/conformance/ghidra/mips-checks.test.ts (+115 -0)
📝 tests/conformance/ghidra/mips-fixture.mjs (+22 -2)

📄 Description

Closes #1937.

Behavior

  • Admission: ELF32 ET_EXEC o32 MIPS32r2 with an ABI record declaring either 32-bit CPR1 + double/FPXX (unchanged) or no CPR1 + soft-float (new). Single-float, FP64, unspecified and inconsistent combinations stay refused.
  • Profile: soft-float targets commit mips_soft_float_storage: "o32-soft-float-prototype-v1". Hard-float profiles are unchanged (digests stable).
  • bridge/ghidra/ReaGhidraMipsSoftFloat.java (post-script after ReaGhidraNoReturnFix, before the bridge):
    • encodes the program's own default o32 prototype, removes its floating-point pentrys and the rules that consume float storage, and installs the result as a program-specific __rea_soft_float prototype through a Ghidra specification extension. Deriving it keeps the byte-order-specific aggregate rules and the hidden struct-return pointer;
    • assigns that prototype, with dynamic storage, to every non-thunk function, every external function and every function-pointer definition whose formal types use float/double. Thunks follow their targets. Declared types are kept everywhere;
    • fails without writing its report if the derived prototype, or any reassigned function, still places a value in an FPU register.
  • Handshake: the script writes {policy, functions, definitions} to PROGRAM_INFO last; the bridge reports it as mips_soft_float_storage; the provider client requires it exactly when the profile commits the policy and refuses the session before any operation (soft-float) or at health (unexpected report on hard-float). The counts become session limitations.
  • package.json#files ships the new script.

The first revision rewrote storage per Function; review pointed out that externals and indirect calls through typed function pointers kept the hard-float prototype (see the thread on ReaGhidraMipsSoftFloat.java). The second commit replaces that with the prototype model above.

Verification

Host: Linux x64, Ghidra 12.1.4, OpenJDK 21.0.12, Clang 21 + LLD, GNU readelf.

  • npm run verify:ghidra:mips: 4 fixtures (LE/BE × hard/soft) passed, carved variants passed, process lineage verified. Soft-float fixtures check exact inspect_native_api types and storage for float, double, mixed (d → a2:a3, f → Stack[0x10], e → Stack[0x18]) and struct-return (__return_storage_ptr__ → a0 (auto), float scale → a1) functions; that the caller's pseudocode carries all nine source float constants with no in_fN inputs, including an indirect call through a typed function pointer; the snapshot policy; and the Evidence outcome counts.
  • Negative control: with function-pointer definitions left on the default prototype, the indirect call decompiles as (*rea_mips_soft_callback)(in_f12,in_f14,…); the lane rejects that.
  • npm run test:fast: 392 files, 4607 passed, 3 skipped. check:fast and oxfmt --check . clean.
  • npm run verify:package and an installed-tarball run passed on the first revision (the file list is unchanged since).

External functions are not reachable from a static ET_EXEC fixture; #1950's relocatable fixture covers an archive-typed external (powf). Not run: --psp (no Allegrex extension on this host); Windows lanes (MIPS is not admitted on Windows P0).


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1949 **Author:** [@AurelioB](https://github.com/AurelioB) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `feat/mips-soft-float` --- ### 📝 Commits (3) - [`b992aa6`](https://github.com/morluto/rea/commit/b992aa67058a21daca0bf1fba002f15c371256b1) feat(ghidra): admit soft-float MIPS32r2 ELF with integer-register float storage - [`5965eae`](https://github.com/morluto/rea/commit/5965eae85b45b9db601984487ff7346129c1a141) fix(ghidra): model soft-float MIPS as a prototype for every typed callable - [`c5d346c`](https://github.com/morluto/rea/commit/c5d346c029c4e952caf6c40c42ba87e58715281d) test(ghidra): pin ODDSPREG acceptance for soft-float MIPS ABI records ### 📊 Changes **17 files changed** (+958 additions, -34 deletions) <details> <summary>View changed files</summary> 📝 `bridge/ghidra/ReaGhidraBridge.java` (+5 -0) ➕ `bridge/ghidra/ReaGhidraMipsSoftFloat.java` (+176 -0) 📝 `docs/ghidra-mips.md` (+49 -8) 📝 `package.json` (+1 -0) 📝 `scripts/verify-real-ghidra-mips.mjs` (+83 -7) 📝 `src/ghidra/GhidraLauncher.ts` (+23 -0) 📝 `src/ghidra/GhidraMipsProfile.test.ts` (+153 -0) 📝 `src/ghidra/GhidraMipsProfile.ts` (+58 -4) 📝 `src/ghidra/GhidraProviderClient.ts` (+47 -2) 📝 `src/ghidra/GhidraSessionValues.test.ts` (+34 -0) 📝 `src/ghidra/GhidraSessionValues.ts` (+9 -0) 📝 `tests/boundary/providers/ghidra/ghidraLauncher.test.ts` (+39 -0) ➕ `tests/conformance/c/mips-soft-float.c` (+53 -0) 📝 `tests/conformance/ghidra/mips-checks.d.mts` (+8 -8) 📝 `tests/conformance/ghidra/mips-checks.mjs` (+83 -3) 📝 `tests/conformance/ghidra/mips-checks.test.ts` (+115 -0) 📝 `tests/conformance/ghidra/mips-fixture.mjs` (+22 -2) </details> ### 📄 Description Closes #1937. ## Behavior - Admission: ELF32 `ET_EXEC` o32 MIPS32r2 with an ABI record declaring either 32-bit CPR1 + double/FPXX (unchanged) or no CPR1 + soft-float (new). Single-float, FP64, unspecified and inconsistent combinations stay refused. - Profile: soft-float targets commit `mips_soft_float_storage: "o32-soft-float-prototype-v1"`. Hard-float profiles are unchanged (digests stable). - `bridge/ghidra/ReaGhidraMipsSoftFloat.java` (post-script after `ReaGhidraNoReturnFix`, before the bridge): - encodes the program's own default o32 prototype, removes its floating-point `pentry`s and the rules that consume float storage, and installs the result as a program-specific `__rea_soft_float` prototype through a Ghidra specification extension. Deriving it keeps the byte-order-specific aggregate rules and the hidden struct-return pointer; - assigns that prototype, with dynamic storage, to every non-thunk function, every external function and every function-pointer definition whose formal types use `float`/`double`. Thunks follow their targets. Declared types are kept everywhere; - fails without writing its report if the derived prototype, or any reassigned function, still places a value in an FPU register. - Handshake: the script writes `{policy, functions, definitions}` to `PROGRAM_INFO` last; the bridge reports it as `mips_soft_float_storage`; the provider client requires it exactly when the profile commits the policy and refuses the session before any operation (soft-float) or at `health` (unexpected report on hard-float). The counts become session limitations. - `package.json#files` ships the new script. The first revision rewrote storage per `Function`; review pointed out that externals and indirect calls through typed function pointers kept the hard-float prototype (see the thread on `ReaGhidraMipsSoftFloat.java`). The second commit replaces that with the prototype model above. ## Verification Host: Linux x64, Ghidra 12.1.4, OpenJDK 21.0.12, Clang 21 + LLD, GNU readelf. - `npm run verify:ghidra:mips`: 4 fixtures (LE/BE × hard/soft) passed, carved variants passed, process lineage verified. Soft-float fixtures check exact `inspect_native_api` types and storage for float, double, mixed (`d` → `a2:a3`, `f` → `Stack[0x10]`, `e` → `Stack[0x18]`) and struct-return (`__return_storage_ptr__` → `a0 (auto)`, `float scale` → `a1`) functions; that the caller's pseudocode carries all nine source float constants with no `in_fN` inputs, including an indirect call through a typed function pointer; the snapshot policy; and the Evidence outcome counts. - Negative control: with function-pointer definitions left on the default prototype, the indirect call decompiles as `(*rea_mips_soft_callback)(in_f12,in_f14,…)`; the lane rejects that. - `npm run test:fast`: 392 files, 4607 passed, 3 skipped. `check:fast` and `oxfmt --check .` clean. - `npm run verify:package` and an installed-tarball run passed on the first revision (the file list is unchanged since). External functions are not reachable from a static `ET_EXEC` fixture; #1950's relocatable fixture covers an archive-typed external (`powf`). Not run: `--psp` (no Allegrex extension on this host); Windows lanes (MIPS is not admitted on Windows P0). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:57:00 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4930
No description provided.