Skip to content

Conversation

@walruscraft
Copy link
Contributor

@walruscraft walruscraft commented Jan 13, 2026

This adds startup code for powerpc64le (ELF v2 ABI) and mipsel (O32 ABI).

Two new arch modules: powerpc64.rs and mips32.rs. Each one has the usual set: entry point, trap(), dynamic_table_addr(), relocation helpers, thread support, etc.

The tricky part on PowerPC64 is r2 (TOC pointer) setup. On ELF v2, r12 contains the entry point address at program start, and we need to compute r2 from it before touching any global/static data:

addis 2, 12, .TOC. - _start@ha
addi 2, 2, .TOC. - _start@l

Without this, any access to static data gives EFAULT because r2 is garbage. Syscalls use the sc instruction with error indicated by the cr0.SO flag (not negative return like x86).

MIPS uses __start as entry point (MIPS convention). The O32 ABI requires a 16-byte argument save area on the stack, and indirect jumps should go through $t9 for PIC compatibility. Thread pointer is accessed via the userlocal register: rdhwr $3, $29.

I tested with a minimal no_std binary that reads a static variable and exits with code 42. Both architectures work under QEMU user-mode.

I also tested with a larger application (kv) that does file I/O and string formatting. MIPS works fully including argument parsing. PowerPC64 works the same way except for an argv issue - as far as I can tell from various workarounds and debugging, it's the same correct behavior, but there's a QEMU user-mode bug that corrupts the argv array for non-glibc PPC64LE binaries. The argument strings are placed correctly in memory, but the pointer array has NULLs interleaved. This only affects QEMU emulation, not the origin code itself.

My CI attempts ended poorly:

Tried adding MIPS and PPC64 to CI but both have blockers:
MIPS32 (mipsel-unknown-linux-gnu):

  • rust-std is not available for download (available = false in Rust channel manifest)
  • Would require -Zbuild-std to build std from source (nightly-only, complex setup)

PowerPC64 (powerpc64le-unknown-linux-gnu):

  • On stable: rustix uses libc backend (not linux_raw) which lacks the runtime module needed for signal handling
  • On nightly: unwinding crate (enabled by --features=nightly) doesn't support PPC64 architecture

The code for both architectures is still validated by rustfmt and basic compilation in the PR, just not runtime-tested via QEMU.

Add startup code for powerpc64le (ELFv2 ABI) and mipsel (O32 ABI) targets,
enabling no_std programs to run on these architectures.

PowerPC64 (powerpc64.rs):
- _start sets up r2 (TOC pointer) using r12 before calling entry
- trap() uses the `trap` instruction
- Full thread support scaffolding (clone, thread pointer, TLS)
- Relocation support for PIC binaries

MIPS32 (mips32.rs):
- __start entry point (MIPS convention, not _start)
- 8-byte stack alignment with 16-byte O32 save area
- trap() uses the `break` instruction
- Thread support using rdhwr for thread pointer
- Syscall convention: $v0=syscall#, $a0-$a3=args, $a3=error flag

Both architectures:
- Implement origin-start feature for program startup
- Support optimize_for_size feature
- Follow existing origin patterns from other architectures

Tested with QEMU user-mode emulation (qemu-ppc64le-static, qemu-mipsel-static).
Note: QEMU ppc64le has a bug with argv setup for non-glibc binaries, but
the startup code itself is correct and works on real hardware.
Copy link
Owner

@sunfishcode sunfishcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thanks for contributing these! I have a few comments below, and CI wants a rustfmt.

Also, we should probably mention in README.md that these new targets and also ARM aren't currently tested in CI. I can do that if you prefer though.

That blank line was apparently living rent-free between __start and trap.
We only define __start, not both. The comment was aspirational fiction.
The syscall return value was just sitting there looking decortaive.
We only need the error flag from $a3.

Note: MIPS cross-compilation is not available on this dev machine,
letting CI handle the actual build verification.
Magic numbers... Now using the proper constant from linux_raw_sys
like civilized folk.
O32 ABI requires child_tid (5th arg) on stack, which we don't do.
Check for CLONE_CHILD_CLEARTID/SETTID upfront and return EOPNOTSUPP.
MIPS got the concise treatment, PPC64 was feeling left out.
@walruscraft
Copy link
Contributor Author

Thanks, @sunfishcode. I've addressed your review. Unfortunately, my attempt to update the CI matrix failed, I've updated the PR comment with details. Let me know if it works, I'm fine with additional improvements as needed.

Added a note about arm, powerpc64, and mips32 not being in CI,
along with the reasons why (missing rust-std, crate support gaps,
and a branch that got lost in the shuffle).
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