[Top] [All Lists]

Re: Is r25 saved across syscalls?

Subject: Re: Is r25 saved across syscalls?
From: Rich Felker <>
Date: Tue, 11 Sep 2012 09:44:59 -0400
In-reply-to: <>
List-archive: <>
List-help: <>
List-id: linux-mips <>
List-owner: <>
List-post: <>
List-software: Ecartis version 1.0.0
List-subscribe: <>
List-unsubscribe: <>
References: <> <>
User-agent: Mutt/1.5.21 (2010-09-15)
On Tue, Sep 11, 2012 at 10:12:56AM +0200, Ralf Baechle wrote:
> On Sun, Sep 09, 2012 at 03:30:08PM -0400, Rich Felker wrote:
> > Hi all,
> > The kernel syscall entry/exit code seems to always save and restore
> > r25. Is this stable/documented behavior I can rely on? If there's a
> > reason it _needs_ to be preserved, knowing that would help convince me
> > it's safe to assume it will always be done. The intended usage is to
> > be able to make syscalls (where the syscall # is not a constant that
> > could be loaded with lwi) without a stack frame, as in "move $2,$25 ;
> > syscall".
> Since there is no place where the syscall interface is documented other
> than in the code itself, I've written a new wiki article
> as start.  It's still lacking on the more obscure points but it at least
> should have have answered your question, had it already existed when you
> asked.


Some comments... In the table,

    $a0 ... $a2/$a7 except $a3

is unclear. Do you mean to say $a0 ... $a2 on o32 and also $a4 ... $a7
on all other ABIs? If so I think it would make sense to put those
ranges as separate lines in the table, so it's clear that the second
group are not preserved on o32 (if they were, they would also have
solved my problem).

As for

    $a3  4th syscall argument   $a3 set to 0/1 for success/error

Does the kernel guarantee 0/1, or is it 0/nonzero? This could matter
to asm programmers using the syscall ABI who want to do bit twiddling.

    Syscall restarting is a special case where $v0, $v1 and $a3 will
    stay unmodified. Even the program counter will stay unmodified so
    the same syscall will be executed again. This is something that
    does not matter to application programmers but may become visible
    in debuggers. Syscall restarting is something that is used
    internally by the kernel, for example when during a large read(2)
    syscall the kernel receives a signal.

The way syscall restarting works does matter to userspace, although
only to very low-level code. In musl (,
the syscall routine for cancellation-point syscalls uses labels in the
asm before checking the cancellation flag and immediately after the
syscall instruction so that the signal handler that processes thread
cancellation can examine the saved program counter in the ucontext_t
it receives and determine whether the interrupted code is at a
cancellable syscall or not, with no race conditions. The glibc/NPTL
approach of wrapping a plain syscall with code to change to async
cancellation mode and back has extremely dangerous race conditions,
and my approach in musl of examining the program counter and comparing
it against asm labels is the only solution I've seen that's race-free.


<Prev in Thread] Current Thread [Next in Thread>