Skip to content

Add MIPS64 (n64 ABI) Linux support#1631

Draft
retrocpugeek wants to merge 3 commits into
qilingframework:devfrom
retrocpugeek:feature/mips64be
Draft

Add MIPS64 (n64 ABI) Linux support#1631
retrocpugeek wants to merge 3 commits into
qilingframework:devfrom
retrocpugeek:feature/mips64be

Conversation

@retrocpugeek

Copy link
Copy Markdown

Summary

Adds QL_ARCH.MIPS64 so Qiling can emulate MIPS64 Linux user-space code in both big- and little-endian. The native backends already support MIPS64 (Unicorn UC_MODE_MIPS64, Capstone/Keystone CS/KS_MODE_MIPS64); this wires it through the framework.

What's included

  • QlArchMIPS64 (qiling/arch/mips64.py) — 64-bit arch class reusing the shared MIPS register map.
  • n64 calling convention & syscall ABI — the first eight arguments are passed in registers (a0-a3 and a4-a7, i.e. the physical registers $8-$11) with no on-stack shadow space, unlike o32.
  • n64 syscall table (base 5000) generated from the Linux uapi header asm/unistd_n64.h.
  • Wiring through the Linux/blob OS layers, ELF machine detection (EM_MIPS + ELFCLASS64), and n64 doubleword stack alignment.
  • Big- and little-endian MIPS64 shellcode tests in tests/test_shellcode.py.

Testing

python3 -m unittest test_shellcode passes, including the new test_linux_mips64eb / test_linux_mips64el (a write + exit_group shellcode assembled with binutils mips64-linux-gnuabi64-as).

Scope

This is user-space shellcode-level support. Full MIPS64 ELF binary loading and rootfs samples are not part of this PR.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Introduce QL_ARCH.MIPS64 so Qiling can emulate MIPS64 Linux user-space
shellcode in both big- and little-endian. The native backends already
support it (Unicorn UC_MODE_MIPS64, Capstone/Keystone CS/KS_MODE_MIPS64).

  - QlArchMIPS64: 64-bit arch class reusing the shared MIPS register map
  - n64 calling convention and syscall ABI: the first eight arguments are
    passed in registers (a0-a3 and a4-a7, the physical registers $8-$11)
    with no on-stack shadow space, unlike o32
  - n64 syscall table (base 5000) generated from the Linux uapi header
    asm/unistd_n64.h
  - wire MIPS64 through the Linux/blob OS layers, ELF machine detection
    (EM_MIPS + ELFCLASS64) and n64 doubleword stack alignment
  - add big- and little-endian MIPS64 shellcode tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@retrocpugeek

Copy link
Copy Markdown
Author

Follow-up note: reconcile with #1630

This PR and #1630 both modify the MIPS branch in qiling/os/linux/linux.py, so whichever merges second will need a small reconciliation.

#1630 introduces a shared hook_cpu_exception handler (faithful SIGILL on illegal instructions) and a MIPS_EXCP enum, and registers them for MIPS32. To keep this PR self-contained against dev, MIPS64 here mirrors dev's current MIPS32 convention — it hooks the syscall exception with the literal number 17 and does not register the RI illegal-instruction handler.

Once both land, MIPS64 should also be wired to hook_cpu_exception on MIPS_EXCP.RI (and switch 17MIPS_EXCP.SYSCALL), so it terminates cleanly on illegal instructions the same way MIPS32 will. The MIPS64 shellcode test here (write + exit_group) doesn't exercise that path, which is why it's safe to defer.

Demonstrate MIPS64 (n64 ABI) Linux shellcode emulation in both big- and
little-endian, using a write/exit_group shellcode that prints to stdout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@retrocpugeek retrocpugeek marked this pull request as draft June 21, 2026 11:00
The Linux/POSIX syscall layer has several arch-specific code paths keyed on
QL_ARCH.MIPS (open flags, socket type/domain/level/option/ip-option tables,
mmap flags, SHMLBA, the sigset/sigaction layout, SIGSTOP=23, the MIPS
sigprocmask variant, the MIPS stat struct, the pipe()-returns-in-registers
convention and set_thread_area). These values are MIPS-arch-specific and
shared by the n64 ABI, so MIPS64 must take the same paths.

Notably the MIPS64 stat struct already existed but was reached via
QL_ARCH.MIPS + bits==64; with a distinct QL_ARCH.MIPS64 type that branch was
missed and stat fell back to the x86 layout. The struct definitions are
parameterised on arch.bits/native_type, so the n64 layouts fall out correctly
once the branch fires.

pread64's o32 stack-offset hack is intentionally left MIPS-only: under n64 the
64-bit offset arrives in a register, so the generic argument handling is
already correct.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant