Wrong argument register is used
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 2.9k
- Forks
- 231
- Avg merge
- 19h 55m
- Merged PRs (30d)
- 67
Description
On a mips-elf target, (what I hope) equivalent C and Rust code produce different results, namely, the Rust version is trying to take the first argument from the second argument register
Build setup
FROM ubuntu:noble
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \
PATH=/usr/local/cargo/bin:$PATH \
RUST_VERSION=nightly-2025-06-28-x86_64-unknown-linux-gnu \
CCACHE_DIR=/w/ccache CC="ccache gcc" CXX="ccache g++"
RUN <<EOF
apt-get update
apt-get install -y build-essential libgmp-dev libmpfr-dev libmpc-dev libncurses5-dev flex bison autogen dejagnu git ccache wget
ccache --set-config max_size=0
# stolen from rust docker
wget https://static.rust-lang.org/rustup/archive/1.28.2/x86_64-unknown-linux-gnu/rustup-init
chmod +x ./rustup-init
./rustup-init -y --no-modify-path --profile complete --default-toolchain $RUST_VERSION --default-host x86_64-unknown-linux-gnu
chmod -R a+w $RUSTUP_HOME $CARGO_HOME
EOF
Compile binutils 2.44 with ./configure --disable-werror --target=mips-elf and install
Compile gccrs fcc21680857077d01a0d6b9336eea3999da351d1 with ../gccrs/configure --enable-languages=rust --disable-shared --disable-nls --target=mips-elf : (reconfigured) ../gccrs/configure --enable-languages=rust --disable-shared --disable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx --disable-nls --disable-libgcc --disable-libgomp --disable-libatomic --target=mips-elf --without-headers and install
Compiling with -frust-incomplete-and-experimental-compiler-do-not-use -O2 -S
void start(unsigned char *ptr) {
void call_with_a0(unsigned char *ptr);
call_with_a0(ptr);
}
#[no_mangle]
pub extern "C" fn start(ptr: *mut u8) {
extern "C" {
fn call_with_a0(ptr: *mut u8);
}
unsafe {
call_with_a0(ptr);
}
}
Full output assembly
.file 1 "a0.c"
.section .mdebug.abi32
.previous
.nan legacy
.module fp=32
.module nooddspreg
.module arch=mips1
.text
.align 2
.globl start
.set nomips16
.set nomicromips
.ent start
.type start, @function
start:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
.set noreorder
.set nomacro
j call_with_a0
nop
.set macro
.set reorder
.end start
.size start, .-start
.ident "GCC: (GNU) 16.0.0 20250604 (experimental)"
.file 1 "a0.rs"
.section .mdebug.abi32
.previous
.nan legacy
.module fp=32
.module nooddspreg
.module arch=mips1
.text
.align 2
.globl start
$LFB0 = .
.cfi_startproc
.set nomips16
.set nomicromips
.ent start
.type start, @function
start:
.frame $sp,24,$31 # vars= 0, regs= 1/0, args= 16, gp= 0
.mask 0x80000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
addiu $sp,$sp,-24
.cfi_def_cfa_offset 24
sw $4,24($sp)
sw $31,20($sp)
.cfi_offset 31, -4
jal call_with_a0
move $4,$5 # <---- notable: move $a0, $a1 ..?
lw $31,20($sp)
lw $2,24($sp)
jr $31
addiu $sp,$sp,24
.cfi_def_cfa_offset 0
.cfi_restore 31
.set macro
.set reorder
.end start
.cfi_endproc
$LFE0:
.size start, .-start
.ident "GCC: (GNU) 16.0.0 20250604 (experimental)"
diff --git a/c.s b/r.s
index f27ce13..350c65d 100644
--- a/c.s
+++ b/r.s
@@ -1,4 +1,4 @@
- .file 1 "a0.c"
+ .file 1 "a0.rs"
.section .mdebug.abi32
.previous
.nan legacy
@@ -8,21 +8,37 @@
.text
.align 2
.globl start
+$LFB0 = .
+ .cfi_startproc
.set nomips16
.set nomicromips
.ent start
.type start, @function
start:
- .frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
- .mask 0x00000000,0
+ .frame $sp,24,$31 # vars= 0, regs= 1/0, args= 16, gp= 0
+ .mask 0x80000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
- j call_with_a0
- nop
+ addiu $sp,$sp,-24
+ .cfi_def_cfa_offset 24
+ sw $4,24($sp)
+ sw $31,20($sp)
+ .cfi_offset 31, -4
+ jal call_with_a0
+ move $4,$5 # <---- notable: move $a0, $a1 ..?
+ lw $31,20($sp)
+ lw $2,24($sp)
+ jr $31
+ addiu $sp,$sp,24
+
+ .cfi_def_cfa_offset 0
+ .cfi_restore 31
.set macro
.set reorder
.end start
+ .cfi_endproc
+$LFE0:
.size start, .-start
.ident "GCC: (GNU) 16.0.0 20250604 (experimental)"
EDIT 1: Switch target from mips-unknown-netbsd to mips-elf, same results
EDIT 2: Remove c_void, use u8 pointers
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the reduced C and Rust examples with gccrs on the mips-elf target using the shown build and compiler flags. Compare the generated a0.c and a0.rs assembly, focusing on the call to call_with_a0 and its argument registers. Done means the Rust output passes the pointer in the same register as the equivalent C output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100