ppc32/64: rewrite get/set/swapcontext in assembly
getcontext cannot be correctly implemented in C. If this calls another function, as it does to call syscall, it needs to first spill its return address to the stack. If, after getcontext returns, its caller then calls other functions, this saved return address can be clobbered. When the context saved by getcontext is later restored, the (now clobbered) return address will be reloaded from the stack, and the second return from getcontext will return to the wrong location. Because the powerpc swapcontext syscall allows either the old context or new context pointers to be null, it is usable for implementing all of get/set/swapcontext. We therefore rewrite swapcontext in assembly, and get/setcontext as simple assembly function wrappers around swapcontext. The one piece we keep in C is the code to check the return value of the system call and to set errno. This code was actually unnecessary before -- libc does this within syscall. However, now that the system call is made directly in assembly, bypassing libc, it is truly necessary. Because errno is thread-local and the details of how to set it can vary by libc, this code remains written in C.pull/11/head
parent
90ff6330e6
commit
2610c7faa7
10
Makefile
10
Makefile
|
@ -2,14 +2,8 @@ ARCH := $(shell uname -m)
|
|||
|
||||
CFLAGS = -ggdb3 -O2 -Wall -Iarch/${ARCH}
|
||||
|
||||
LIBUCONTEXT_C_SRC = \
|
||||
arch/${ARCH}/makecontext.c
|
||||
|
||||
LIBUCONTEXT_S_SRC = \
|
||||
arch/${ARCH}/getcontext.S \
|
||||
arch/${ARCH}/setcontext.S \
|
||||
arch/${ARCH}/swapcontext.S \
|
||||
arch/${ARCH}/startcontext.S
|
||||
LIBUCONTEXT_C_SRC = $(wildcard arch/${ARCH}/*.c)
|
||||
LIBUCONTEXT_S_SRC = $(wildcard arch/${ARCH}/*.S)
|
||||
|
||||
LIBUCONTEXT_OBJ = ${LIBUCONTEXT_C_SRC:.c=.o} ${LIBUCONTEXT_S_SRC:.S=.o}
|
||||
LIBUCONTEXT_SOVERSION = 0
|
||||
|
|
|
@ -19,7 +19,7 @@ Right now these archs are supported and should work on bare metal:
|
|||
* aarch64
|
||||
* s390x
|
||||
|
||||
These archs require kernel assistance and use a syscall (the only assembly is the trampoline):
|
||||
These archs require kernel assistance and use a syscall:
|
||||
|
||||
* ppc
|
||||
* ppc64 (ELFv2 ABI spec only, ELFv1 not supported)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
.global __getcontext
|
||||
.hidden __swapcontext
|
||||
__getcontext:
|
||||
li 4, 0
|
||||
b __swapcontext@local
|
||||
|
||||
.weak getcontext
|
||||
getcontext = __getcontext
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -10,36 +11,15 @@
|
|||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
int
|
||||
__getcontext(ucontext_t *ucp)
|
||||
__attribute__ ((visibility ("hidden")))
|
||||
int __retfromsyscall(long retval)
|
||||
{
|
||||
#ifdef SYS_swapcontext
|
||||
int r;
|
||||
|
||||
r = syscall(SYS_swapcontext, ucp, NULL, sizeof(ucontext_t));
|
||||
if (r < 0)
|
||||
{
|
||||
errno = -r;
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern __typeof(__getcontext) getcontext __attribute__((weak, __alias__("__getcontext")));
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
.global __setcontext
|
||||
.hidden __swapcontext
|
||||
__setcontext:
|
||||
mr 4, 3
|
||||
li 3, 0
|
||||
b __swapcontext@local
|
||||
|
||||
.weak setcontext
|
||||
setcontext = __setcontext
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
int
|
||||
__setcontext(const ucontext_t *ucp)
|
||||
{
|
||||
#ifdef SYS_swapcontext
|
||||
int r;
|
||||
|
||||
r = syscall(SYS_swapcontext, NULL, (void *) ucp, sizeof(ucontext_t));
|
||||
if (r < 0)
|
||||
{
|
||||
errno = -r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern __typeof(__setcontext) setcontext __attribute__((weak, __alias__("__setcontext")));
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
.global __swapcontext
|
||||
__swapcontext:
|
||||
li 0, 249 # SYS_swapcontext
|
||||
li 5, 1184 # sizeof(ucontext_t)
|
||||
sc
|
||||
|
||||
.hidden __retfromsyscall
|
||||
b __retfromsyscall@local
|
||||
|
||||
.weak swapcontext
|
||||
swapcontext = __swapcontext
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
int
|
||||
__swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
|
||||
{
|
||||
#ifdef SYS_swapcontext
|
||||
int r;
|
||||
|
||||
r = syscall(SYS_swapcontext, oucp, ucp, sizeof(ucontext_t));
|
||||
if (r < 0)
|
||||
{
|
||||
errno = -r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern __typeof(__swapcontext) swapcontext __attribute__((weak, __alias__("__swapcontext")));
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
.global __getcontext
|
||||
.hidden __swapcontext
|
||||
__getcontext:
|
||||
addis 2, 12, .TOC.-__getcontext@ha
|
||||
addi 2, 12, .TOC.-__getcontext@l
|
||||
|
||||
.localentry __getcontext,.-__getcontext
|
||||
|
||||
li 4, 0
|
||||
b __swapcontext
|
||||
|
||||
.weak getcontext
|
||||
getcontext = __getcontext
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -10,36 +11,15 @@
|
|||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
int
|
||||
__getcontext(ucontext_t *ucp)
|
||||
__attribute__ ((visibility ("hidden")))
|
||||
int __retfromsyscall(long retval)
|
||||
{
|
||||
#ifdef SYS_swapcontext
|
||||
int r;
|
||||
|
||||
r = syscall(SYS_swapcontext, ucp, NULL, sizeof(ucontext_t));
|
||||
if (r < 0)
|
||||
{
|
||||
errno = -r;
|
||||
if (retval < 0) {
|
||||
errno = -retval;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern __typeof(__getcontext) getcontext __attribute__((weak, __alias__("__getcontext")));
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
.global __setcontext
|
||||
.hidden __swapcontext
|
||||
__setcontext:
|
||||
addis 2, 12, .TOC.-__setcontext@ha
|
||||
addi 2, 12, .TOC.-__setcontext@l
|
||||
|
||||
.localentry __setcontext,.-__setcontext
|
||||
|
||||
mr 4, 3
|
||||
li 3, 0
|
||||
b __swapcontext
|
||||
|
||||
.weak setcontext
|
||||
setcontext = __setcontext
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
int
|
||||
__setcontext(const ucontext_t *ucp)
|
||||
{
|
||||
#ifdef SYS_swapcontext
|
||||
int r;
|
||||
|
||||
r = syscall(SYS_swapcontext, NULL, (void *) ucp, sizeof(ucontext_t));
|
||||
if (r < 0)
|
||||
{
|
||||
errno = -r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern __typeof(__setcontext) setcontext __attribute__((weak, __alias__("__setcontext")));
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
.global __swapcontext
|
||||
__swapcontext:
|
||||
addis 2, 12, .TOC.-__swapcontext@ha
|
||||
addi 2, 12, .TOC.-__swapcontext@l
|
||||
|
||||
.localentry __swapcontext,.-__swapcontext
|
||||
|
||||
li 0, 249 # SYS_swapcontext
|
||||
li 5, 1696 # sizeof(ucontext_t)
|
||||
sc
|
||||
|
||||
.hidden __retfromsyscall
|
||||
b __retfromsyscall
|
||||
|
||||
.weak swapcontext
|
||||
swapcontext = __swapcontext
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
int
|
||||
__swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
|
||||
{
|
||||
#ifdef SYS_swapcontext
|
||||
int r;
|
||||
|
||||
r = syscall(SYS_swapcontext, oucp, ucp, sizeof(ucontext_t));
|
||||
if (r < 0)
|
||||
{
|
||||
errno = -r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern __typeof(__swapcontext) swapcontext __attribute__((weak, __alias__("__swapcontext")));
|
Loading…
Reference in New Issue