I've run across a problem with user apps that use the _syscall[0-7] macros
in asm-mips/unistd.h. With the latest Linux-MIPS glibc release (the
2.0.6-5lm version), they're not getting errno set properly for error
conditions. In particular, this breaks recent versions of modutils.
The problem is this: In user space, errno is now a per-thread value. This
seems like a good thing to me, but it means that the assignment of errno is
no longer a simple assignment, but now involves a function call to retrieve
a pointer to errno. This trips up the _syscall macros in unistd.h because
they all do:
errno = __res;
where __res is declared to be the v0 register, which is set by the syscall
itself. Meanwhile, the function that retrieves the pointer to errno returns
it in... v0. So errno winds up getting set to the address of errno. This
doesn't affect _syscall usage in kernel code, because errno is a simple
assignment in that case, nor does it affect glibc itself, since glibc
doesn't seem to use the _syscall macros.
I worked around this problem by adding to each _syscall macro:
unsigned long __res_save; \
errno = __res; \
__res_save = __res; \
errno = __res_save; \
I'm not sure that's the best/cleanest solution, but it does have the benefit
that when errno is a simple assignment (as is the case for the kernel), the
compiler optimizes out the additional assignment.