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
Bobby Bingham 2019-02-23 17:12:37 -06:00
parent 90ff6330e6
commit 2610c7faa7
14 changed files with 156 additions and 239 deletions

View File

@ -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

View File

@ -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)

20
arch/ppc/getcontext.S Normal file
View File

@ -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

View File

@ -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")));

21
arch/ppc/setcontext.S Normal file
View File

@ -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

View File

@ -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")));

23
arch/ppc/swapcontext.S Normal file
View File

@ -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

View File

@ -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")));

25
arch/ppc64/getcontext.S Normal file
View File

@ -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

View File

@ -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")));

26
arch/ppc64/setcontext.S Normal file
View File

@ -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

View File

@ -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")));

28
arch/ppc64/swapcontext.S Normal file
View File

@ -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

View File

@ -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")));