On 03/02/16 05:25, Andreas Schwab wrote:
Greg Ungerer <gerg@xxxxxxxxxxx> writes:
Does it work to use this signature:
asmlinkage int do_sigreturn(struct switch_stack sw, struct pt_regs regs)
without changing the caller?
No, same problem.
So this is unrelated to aliasing. Can you create a test case?
Attached is a test case - derived from the original signal.c code.
I removed a lot to get it to a manageable size. It still exhibits
the problem. I compile this test case with:
m68k-uclinux-gcc -Wall -mcpu=5208 -fno-strict-aliasing -O2 -c -o signal.o signal.i
I get the same result if I use a m68k-linux-gcc as well (I am
using gcc-5.3 based toolchains).
Regards
Greg
typedef unsigned int __u32;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef unsigned int __kernel_size_t;
typedef int __kernel_clockid_t;
typedef __kernel_clockid_t clockid_t;
typedef __kernel_size_t size_t;
typedef struct {
unsigned long fds_bits[1024 / (8 * sizeof(long))];
} __kernel_fd_set;
typedef struct {
unsigned long sig[(64 / 32)];
} sigset_t;
typedef struct sigaltstack {
void *ss_sp;
int ss_flags;
size_t ss_size;
} stack_t;
struct sigcontext {
unsigned long sc_mask;
unsigned long sc_usp;
unsigned long sc_d0;
unsigned long sc_d1;
unsigned long sc_a0;
unsigned long sc_a1;
unsigned long sc_a5;
unsigned short sc_sr;
unsigned long sc_pc;
unsigned short sc_formatvec;
};
struct pt_regs {
long d1;
long d2;
long d3;
long d4;
long d5;
long a0;
long a1;
long a2;
long d0;
long orig_d0;
long stkadj;
unsigned format : 4;
unsigned vector : 12;
unsigned short sr;
unsigned long pc;
};
struct switch_stack {
unsigned long d6;
unsigned long d7;
unsigned long a3;
unsigned long a4;
unsigned long a5;
unsigned long a6;
unsigned long retpc;
};
struct timespec;
struct restart_block {
long (*fn)(struct restart_block *);
union {
struct {
u32 *uaddr;
u32 val;
u32 flags;
u32 bitset;
u64 time;
u32 *uaddr2;
} futex;
struct {
clockid_t clockid;
struct timespec *rmtp;
u64 expires;
} nanosleep;
struct {
struct pollfd *ufds;
int nfds;
int has_timeout;
unsigned long tv_sec;
unsigned long tv_nsec;
} poll;
};
};
struct thread_struct {
unsigned long ksp;
unsigned long usp;
unsigned short sr;
unsigned short fs;
unsigned long crp[2];
unsigned long esp0;
unsigned long faddr;
int signo, code;
unsigned long fp[8*3];
unsigned long fpcntl[3];
unsigned char fpstate[(0)];
};
struct mm_struct {
u32 vmacache_seqnum;
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
};
struct task_struct {
volatile long state;
void *stack;
struct mm_struct *mm, *active_mm;
struct restart_block restart_block;
int exit_state;
int exit_code, exit_signal;
};
typedef struct {
unsigned long seg;
} mm_segment_t;
struct thread_info {
struct task_struct *task;
unsigned long flags;
mm_segment_t addr_limit;
int preempt_count;
__u32 cpu;
unsigned long tp_value;
};
typedef int greg_t;
typedef greg_t gregset_t[18];
typedef struct fpregset {
int f_fpcntl[3];
int f_fpregs[8*3];
} fpregset_t;
struct mcontext {
int version;
gregset_t gregs;
fpregset_t fpregs;
};
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct mcontext uc_mcontext;
unsigned long uc_filler[80];
sigset_t uc_sigmask;
};
struct sigframe
{
char *pretcode;
int sig;
int code;
struct sigcontext *psc;
char retcode[8];
unsigned long extramask[(64 / 32)-1];
struct sigcontext sc;
};
extern void force_sig(int, struct task_struct *);
extern void set_current_blocked(sigset_t *);
extern long do_no_restart_syscall(struct restart_block *parm);
extern int __builtin_memcmp(const void *, const void *, __kernel_size_t);
extern int __get_user_bad(void);
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
__asm__(
"move.l %%sp, %0 \n\t"
"and.l %1, %0"
: "=&d"(ti)
: "di" (~(((1UL) << 13)-1))
);
return ti;
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) struct task_struct *get_current(void)
{
return(current_thread_info()->task);
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) unsigned long rdusp(void)
{
register unsigned long usp __asm__("a0");
__asm__ __volatile__(".word 0x4e68" : "=a" (usp));
return usp;
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) void wrusp(unsigned long usp)
{
register unsigned long a0 __asm__("a0") = usp;
__asm__ __volatile__(".word 0x4e60" : : "a" (a0) );
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) int _access_ok(unsigned long addr, unsigned long size)
{
return 1;
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) int frame_extra_sizes(int f)
{
return 0;
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) int restore_fpu_state(struct sigcontext *sc)
{
return 0;
}
static int mangle_kernel_stack(struct pt_regs *regs, int formatvec, void *fp)
{
int fsize = frame_extra_sizes(formatvec >> 12);
if (fsize < 0) {
return 1;
}
if (!fsize) {
regs->format = formatvec >> 12;
regs->vector = formatvec & 0xfff;
} else {
struct switch_stack *sw = (struct switch_stack *)regs - 1;
unsigned long buf[fsize / 2];
if ((__builtin_memcpy(buf + fsize / 4, fp, fsize), 0))
return 1;
regs->format = formatvec >> 12;
regs->vector = formatvec & 0xfff;
__asm__ __volatile__ (
" movel %0,%/sp\n\t"
" bra ret_from_signal\n"
:
: "a" (sw), "d" (fsize), "d" ((sizeof(struct pt_regs)+sizeof(struct switch_stack))/4-1),
"n" ((sizeof(struct pt_regs)+sizeof(struct switch_stack))), "a" (buf + fsize/4)
: "a0");
}
return 0;
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
{
int formatvec;
struct sigcontext context;
int err = 0;
get_current()->restart_block.fn = do_no_restart_syscall;
if ((__builtin_memcpy(&context, usc, sizeof(context)), 0))
goto badframe;
regs->d0 = context.sc_d0;
regs->d1 = context.sc_d1;
regs->a0 = context.sc_a0;
regs->a1 = context.sc_a1;
regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
regs->pc = context.sc_pc;
regs->orig_d0 = -1;
wrusp(context.sc_usp);
formatvec = context.sc_formatvec;
err = restore_fpu_state(&context);
if (err || mangle_kernel_stack(regs, formatvec, fp))
goto badframe;
return 0;
badframe:
return 1;
}
int do_sigreturn(unsigned long __unused)
{
struct switch_stack *sw = (struct switch_stack *) &__unused;
struct pt_regs *regs = (struct pt_regs *) (sw + 1);
unsigned long usp = rdusp();
struct sigframe *frame = (struct sigframe *)(usp - 4);
sigset_t set;
if (!_access_ok((unsigned long)(frame),(sizeof(*frame))))
goto badframe;
if (({ int __gu_err = 0; typeof(set.sig[0]) __gu_val = 0; switch (sizeof(*(&frame->sc.sc_mask))) { case 1: __asm__ ("move" "b" " %1,%0" : "=d" (__gu_val) : "m" (*((unsigned long *)(&frame->sc.sc_mask)))); break; case 2: __asm__ ("move" "w" " %1,%0" : "=d" (__gu_val) : "m" (*((unsigned long *)(&frame->sc.sc_mask)))); break; case 4: __asm__ ("move" "l" " %1,%0" : "=d" (__gu_val) : "m" (*((unsigned long *)(&frame->sc.sc_mask)))); break; case 8: __builtin_memcpy((void *) &__gu_val, &frame->sc.sc_mask, sizeof (*(&frame->sc.sc_mask))); break; default: __gu_val = 0; __gu_err = __get_user_bad(); break; } (set.sig[0]) = (typeof(*(&frame->sc.sc_mask))) __gu_val; __gu_err; }) ||
((64 / 32) > 1 &&
(__builtin_memcpy(&set.sig[1], &frame->extramask, sizeof(frame->extramask)), 0)
))
goto badframe;
set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, frame + 1))
goto badframe;
return regs->d0;
badframe:
force_sig(11, get_current());
return 0;
}