strace
is wrong, your process isn't actually running in 32-bit mode, just using the 32-bit int 0x80
system call ABI.
You can check with gdb ./main
and use starti
. info regs
will show that the register state is 64-bit, including 16x 64-bit registers, not 8x 32-bit registers. Or more simply, layout reg
.
I see the same strace bug(?) when building a program with NASM that uses the 32-bit int 0x80
ABI in 64-bit mode to make an exit
system call.
I added a delay loop before the first system call and I see strace
doesn't print out the bitness of the target process until it makes a system call. So apparently strace
infers that from whether it uses the 64-bit syscall
ABI or the 32-bit int 0x80
/ sysenter
ABI!
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
Perhaps this is related to strace
trying to figure out how to decode system calls: The Linux ptrace
API that strace
uses doesn't have a simple reliable mechanism to tell which system call ABI a process invoked. https://superuser.com/questions/834122/how-to-distinguish-syscall-from-int-80h-when-using-ptrace
A 64-bit process that uses 32-bit system calls used to just get decoded according to 64-bit call numbers. But now it seems modern strace
checks:
I used eax=1
/ syscall
to invoke write
, and eax=1
/ int 0x80
to invoke exit
, and strace
decoded them both correctly
execve("./nasm-test", ["./nasm-test"], 0x7ffdb8da5890 /* 52 vars */) = 0
write(0, NULL, 0) = 0
strace: [ Process PID=5219 runs in 32 bit mode. ]
exit(0) = ?
+++ exited with 0 +++
This is with strace 5.3
on Linux 5.3.1-arch1-1-ARCH.