r3 is caller-saved. When a function call appears in the args list
(e.g. INTERNAL_SYSCALL_CALL(tgkill, __getpid(), tid, sig)),
SUBSTITUTE_ARGS evaluates __getpid() before r3 is reloaded, leaving
r3=20 (__NR_getpid) instead of __NR_tgkill=270. The trapa then
dispatches the wrong syscall and the signal is silently dropped.
Fix: declare r3 uninitialised, expand SUBSTITUTE_ARGS (all function
calls happen here), then assign the syscall number to r3 with no
intervening calls before the trapa. Applies to both INTERNAL_SYSCALL
and INTERNAL_SYSCALL_NCS.
signal/tst-raise is a regression test for this bug: raise() calls
tgkill(__getpid(), tid, sig), which triggers the clobber.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
#define INTERNAL_SYSCALL(name, nr, args...) \
({ \
unsigned long int resultvar; \
- register long int r3 asm ("%r3") = SYS_ify (name); \
+ register long int r3 asm ("%r3"); \
SUBSTITUTE_ARGS_##nr(args); \
+ r3 = SYS_ify (name); \
\
asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD \
: "=z" (resultvar) \
#define INTERNAL_SYSCALL_NCS(name, nr, args...) \
({ \
unsigned long int resultvar; \
- register long int r3 asm ("%r3") = (name); \
+ register long int r3 asm ("%r3"); \
SUBSTITUTE_ARGS_##nr(args); \
+ r3 = (name); \
\
asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD \
: "=z" (resultvar) \