Skip to content

[AUTOMATED] fix(analysis): select generic MIPS ELF ISA and ABI models - #1423

Open
phix33 wants to merge 4 commits into
Noelo-Lab:mainfrom
phix33:fix/mips-elf-isa-abi
Open

phix33 wants to merge 4 commits into
Noelo-Lab:mainfrom
phix33:fix/mips-elf-isa-abi

Conversation

@phix33

@phix33 phix33 commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

An ELF32 N32 image fails automatic loading even though its decoder and compiler model are bundled.

python3 - <<'PY'
import struct
code = struct.pack('>III', 0x64820001, 0x03e00008, 0)
header = b'\x7fELF\x01\x02\x01' + bytes(9)
header += struct.pack('>HHIIIIIHHHHHH', 2, 8, 1, 0x1000, 52, 0,
                      0x80000020, 52, 32, 1, 40, 0, 0)
segment = struct.pack('>8I', 1, 0x100, 0x1000, 0x1000, 12, 12, 5, 4)
open('n32.elf', 'wb').write((header + segment).ljust(0x100, b'\0') + code)
PY
kuna decompile n32.elf 0x1000 --mode fast 2>&1 | sed 's/.*unsupported machine/unsupported machine/'
unsupported machine Mips64_N32 (no kuna SLEIGH language; pass an explicit --target language id)

Fix

  • Select generic MIPS register width, instruction release and ABI from ELF declarations; preserve explicit overrides and leave processor-specific selection separate.
  • Read FPR width independently and preserve O32 word slots and byte-order-specific aggregate placement in wider registers.
  • Accept R6 with microMIPS while rejecting contradictory mode declarations.

Tests

Loader and CLI cases in both byte orders cover selection, overrides, segment-only metadata, mixed modes, FPR widths and aggregate register/stack placement. Stage cases pin O32 word-slot reads and big-endian one-byte aggregates; each fails without its correction.

@phix33
phix33 force-pushed the fix/mips-elf-isa-abi branch from 519d23f to 267d1d2 Compare November 1, 2026 22:38
@mahaloz

mahaloz commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

[AUTOMATED] The N32 repro works, and so do microMIPS, ELF32 O64, EABI32 and R6 -mfp64, all of which main mis-decodes or cannot load. Non-MIPS output and every O32 image main already loads are byte-identical across 516 images. Three problems remain. All use Debian/Ubuntu's gcc-mipsel-linux-gnu (GCC 10).

1. Two kinds of O32 image that main decompiles no longer load.

printf 'int neg(int a) { return a < 0; }\nvoid __start(void) { for (;;); }\n' > t.c
F='-O1 -nostdlib -static -fno-pic -mno-abicalls'
mipsel-linux-gnu-gcc -EB -mabi=32 -march=mips32r6 $F -o r6.elf t.c                    # FP ABI FPXX, CPR1 size 32
mipsel-linux-gnu-gcc -EB -mabi=32 -march=mips32r2 -mfp64 -mhard-float $F -o fp64.elf t.c
kuna decompile r6.elf neg
kuna decompile fp64.elf neg

Both fail with no bundled MIPS language for the declared ISA, ABI and FPR width; pass an explicit --target language id.

  • R6: This is plain GCC output for -march=mips32r6. --target MIPS:BE:32:R6:default decodes it correctly (return a0 >> 0x1f;). Under FPXX, the CPR1 size of 32 is the minimum the code needs, not the hardware width, and R6 FPRs are always 64-bit. So registers = Some(4) should not trip r6 && fpr != 8.
  • Pre-R6 FP64: main prints return a0 >> 0x1f;. Rejecting these images turns them into hard failures. Falling back to the MIPS32 selection main uses, with a [kuna target] note like the O64 one, would keep them loading.

2. The wide-register O32 models drop every integer argument at call sites.

printf 'int __attribute__((noinline)) add2(int a, int b) { return a + b; }\nint call(void) { return add2(4, 5) + 1; }\nvoid __start(void) { for (;;); }\n' > c.c
mipsel-linux-gnu-gcc -EB -mabi=32 -march=mips64r2 -fno-inline -O1 -nostdlib -static -fno-pic -mno-abicalls -o c.elf c.c
kuna decompile-all c.elf --target MIPS:BE:64:64-32addr:o32

main prints long long add2(int a0,int a1) and return (int)add2(4,5) + 1;. This PR prints int add2(int a0,int a1), which is better, but return add2() + 1;.

  • The same happens with MIPS:BE:64:64-32addr-fp32:o32.
  • It also happens without --target once EF_MIPS_32BITMODE is cleared (python3 -c "b=bytearray(open('c.elf','rb').read()); b[38]&=~1; open('c2.elf','wb').write(b)"). main prints add2(4,5) there.
  • In a caller with ten calls, every call loses its arguments (mkp(); setg(); first_b1(); ...).

The new stage and CLI tests check callee inputs and call results, but not caller-side arguments.

3. Overlap with #1394. #1394 adds the identical kuna_mipsabi.rs and a second mod kuna_mipsabi; in loader/mod.rs. That line auto-merges into a duplicate-module compile error. The two PRs also conflict in kuna_floatabi.rs, mips_markers.rs, loadimage_object.rs and spec chapter 01. Whichever lands second needs a rebase.

@phix33

phix33 commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, all three reproduce here.

  1. Fixed. Under FPXX the CPR1 size is now a minimum, so r6.elf selects MIPS:BE:32:R6:default. Pre-R6 O32 -mfp64 images fall back to the MIPS32 language main uses, with a [kuna target] note. Both print return a0 >> 0x1f;.
  2. Fixed. A call now passes the declared four-byte slot of each argument register the caller writes. The incoming-argument extension is only added for registers the function reads, so untouched registers are not passed. c.elf prints int add2(int a0,int a1) and return add2(4,5) + 1; with both wide O32 targets and with EF_MIPS_32BITMODE cleared. A ten-call caller matches main's calls. A new stage case and CLI test check caller-side arguments.
  3. kuna_mipsabi.rs is byte-identical to [AUTOMATED] Recover Octeon ELF targets and N32/N64 ABI values #1394's. Its mod line now sits next to [AUTOMATED] Recover Octeon ELF targets and N32/N64 ABI values #1394's, so merging both conflicts there instead of compiling a duplicate module. Whichever lands second will be rebased.

@phix33
phix33 force-pushed the fix/mips-elf-isa-abi branch from 1c07d18 to 9dbe3cd Compare November 3, 2026 10:04

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants