From 2610c7faa7b9c4114d53bb659264a6be238cd2a3 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Sat, 23 Feb 2019 17:12:37 -0600
Subject: [PATCH] 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.
---
Makefile | 10 +----
README.md | 2 +-
arch/ppc/getcontext.S | 20 +++++++++
arch/ppc/{getcontext.c => retfromsyscall.c} | 30 +++----------
arch/ppc/setcontext.S | 21 +++++++++
arch/ppc/setcontext.c | 45 -------------------
arch/ppc/swapcontext.S | 23 ++++++++++
arch/ppc/swapcontext.c | 45 -------------------
arch/ppc64/getcontext.S | 25 +++++++++++
arch/ppc64/{getcontext.c => retfromsyscall.c} | 30 +++----------
arch/ppc64/setcontext.S | 26 +++++++++++
arch/ppc64/setcontext.c | 45 -------------------
arch/ppc64/swapcontext.S | 28 ++++++++++++
arch/ppc64/swapcontext.c | 45 -------------------
14 files changed, 156 insertions(+), 239 deletions(-)
create mode 100644 arch/ppc/getcontext.S
rename arch/ppc/{getcontext.c => retfromsyscall.c} (53%)
create mode 100644 arch/ppc/setcontext.S
delete mode 100644 arch/ppc/setcontext.c
create mode 100644 arch/ppc/swapcontext.S
delete mode 100644 arch/ppc/swapcontext.c
create mode 100644 arch/ppc64/getcontext.S
rename arch/ppc64/{getcontext.c => retfromsyscall.c} (53%)
create mode 100644 arch/ppc64/setcontext.S
delete mode 100644 arch/ppc64/setcontext.c
create mode 100644 arch/ppc64/swapcontext.S
delete mode 100644 arch/ppc64/swapcontext.c
diff --git a/Makefile b/Makefile
index 51365a3..d6ff1b0 100644
--- a/Makefile
+++ b/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
diff --git a/README.md b/README.md
index 6bd4493..27d3d0b 100644
--- a/README.md
+++ b/README.md
@@ -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)
diff --git a/arch/ppc/getcontext.S b/arch/ppc/getcontext.S
new file mode 100644
index 0000000..beffaf5
--- /dev/null
+++ b/arch/ppc/getcontext.S
@@ -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
diff --git a/arch/ppc/getcontext.c b/arch/ppc/retfromsyscall.c
similarity index 53%
rename from arch/ppc/getcontext.c
rename to arch/ppc/retfromsyscall.c
index 5da9dfb..3ad43c0 100644
--- a/arch/ppc/getcontext.c
+++ b/arch/ppc/retfromsyscall.c
@@ -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")));
diff --git a/arch/ppc/setcontext.S b/arch/ppc/setcontext.S
new file mode 100644
index 0000000..89e6de0
--- /dev/null
+++ b/arch/ppc/setcontext.S
@@ -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
diff --git a/arch/ppc/setcontext.c b/arch/ppc/setcontext.c
deleted file mode 100644
index 59c65b4..0000000
--- a/arch/ppc/setcontext.c
+++ /dev/null
@@ -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")));
diff --git a/arch/ppc/swapcontext.S b/arch/ppc/swapcontext.S
new file mode 100644
index 0000000..24b6655
--- /dev/null
+++ b/arch/ppc/swapcontext.S
@@ -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
diff --git a/arch/ppc/swapcontext.c b/arch/ppc/swapcontext.c
deleted file mode 100644
index af14bc2..0000000
--- a/arch/ppc/swapcontext.c
+++ /dev/null
@@ -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")));
diff --git a/arch/ppc64/getcontext.S b/arch/ppc64/getcontext.S
new file mode 100644
index 0000000..935edd2
--- /dev/null
+++ b/arch/ppc64/getcontext.S
@@ -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
diff --git a/arch/ppc64/getcontext.c b/arch/ppc64/retfromsyscall.c
similarity index 53%
rename from arch/ppc64/getcontext.c
rename to arch/ppc64/retfromsyscall.c
index 5da9dfb..3ad43c0 100644
--- a/arch/ppc64/getcontext.c
+++ b/arch/ppc64/retfromsyscall.c
@@ -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")));
diff --git a/arch/ppc64/setcontext.S b/arch/ppc64/setcontext.S
new file mode 100644
index 0000000..5a0cde3
--- /dev/null
+++ b/arch/ppc64/setcontext.S
@@ -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
diff --git a/arch/ppc64/setcontext.c b/arch/ppc64/setcontext.c
deleted file mode 100644
index 59c65b4..0000000
--- a/arch/ppc64/setcontext.c
+++ /dev/null
@@ -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")));
diff --git a/arch/ppc64/swapcontext.S b/arch/ppc64/swapcontext.S
new file mode 100644
index 0000000..982537a
--- /dev/null
+++ b/arch/ppc64/swapcontext.S
@@ -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
diff --git a/arch/ppc64/swapcontext.c b/arch/ppc64/swapcontext.c
deleted file mode 100644
index af14bc2..0000000
--- a/arch/ppc64/swapcontext.c
+++ /dev/null
@@ -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")));