Skip to content

Commit

Permalink
Bring back the old implementation of setjmp() for aarch64.
Browse files Browse the repository at this point in the history
It looks like we can't really do without these functions. There are too
many ports that for some reason want to make use of them. As Clang
doesn't implement these functions only for AArch64, let that one use the
original version written in assembly.
  • Loading branch information
EdSchouten committed Dec 13, 2017
1 parent df5d09f commit ef8a62e
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 19 deletions.
16 changes: 14 additions & 2 deletions src/common/assembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,28 @@
#ifndef COMMON_ASSEMBLY_H
#define COMMON_ASSEMBLY_H

#if defined(__arm__)
#if defined(__aarch64__)

#define ENTRY(name) \
.text; \
.align 2; \
.global name; \
name:
#define ALTENTRY ENTRY

#define END(name) .size name, .- name

#elif defined(__arm__)

#define ENTRY(name) \
.text; \
.align 2; \
.global name; \
name:

#define END(name) .size name, .- name

#endif

#define ALTENTRY ENTRY

#endif
29 changes: 24 additions & 5 deletions src/include/setjmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,29 @@
#ifndef _SETJMP_H_
#define _SETJMP_H_

#include <_/cdefs.h>
#include <_/types.h>

struct __jmp_buf {
#ifdef __aarch64__

// The compiler doesn't support __builtin_longjmp() and __builtin_setjmp().
// Implement longjmp() and setjmp() as C library functions. These are
// less efficient.

typedef __uint64_t jmp_buf[21];

__BEGIN_DECLS
int setjmp(jmp_buf) __extname("__setjmp");
__END_DECLS

#else

// The compiler supports __builtin_longjmp() and __builtin_setjmp().
// Implement longjmp() and setjmp() on top of these intrinsics.

typedef struct __jmp_buf {
int __val;
void *__ptr[5];
};
typedef struct __jmp_buf jmp_buf[1];
typedef jmp_buf sigjmp_buf;
} jmp_buf[1];

#define setjmp(env) \
({ \
Expand All @@ -42,6 +57,10 @@ typedef jmp_buf sigjmp_buf;
__builtin_setjmp(__env->__ptr); \
__env->__val; \
})

#endif

typedef jmp_buf sigjmp_buf;
#define sigsetjmp(env, savemask) setjmp(env)

__BEGIN_DECLS
Expand Down
3 changes: 1 addition & 2 deletions src/libc/setjmp/longjmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

#include <setjmp.h>

// Clang doesn't provide setjmp()/longjmp() support on some architectures.
#if !defined(__aarch64__) && !defined(__riscv)
#ifndef __aarch64__

void longjmp(jmp_buf env, int val) {
env->__val = val == 0 ? 1 : val;
Expand Down
41 changes: 41 additions & 0 deletions src/libc/setjmp/longjmp_fallback.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
//
// SPDX-License-Identifier: BSD-2-Clause

#include <common/assembly.h>

#ifdef __aarch64__

ENTRY(longjmp)
ALTENTRY(siglongjmp)
// Restore callee-saved registers.
ldp x19, x20, [x0, #0]
ldp x21, x22, [x0, #16]
ldp x23, x24, [x0, #32]
ldp x25, x26, [x0, #48]
ldp x27, x28, [x0, #64]

// Restore frame pointer and link register.
ldp x29, x30, [x0, #80]

// Restore stack pointer.
ldr x2, [x0, #96]
mov sp, x2

// Restore VFP registers.
ldp d8, d9, [x0, #104]
ldp d10, d11, [x0, #120]
ldp d12, d13, [x0, #136]
ldp d14, d15, [x0, #152]

// Return the second parameter of longjmp(), ensuring that we never
// return zero.
mov x0, x1
cbnz x0, 1f
mov x0, #1
1:
br x30
END(longjmp)
END(siglongjmp)

#endif
35 changes: 35 additions & 0 deletions src/libc/setjmp/setjmp_fallback.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
//
// SPDX-License-Identifier: BSD-2-Clause

#include <common/assembly.h>

#ifdef __aarch64__

ENTRY(__setjmp)
// Save callee-saved registers.
stp x19, x20, [x0, #0]
stp x21, x22, [x0, #16]
stp x23, x24, [x0, #32]
stp x25, x26, [x0, #48]
stp x27, x28, [x0, #64]

// Save frame pointer and link register.
stp x29, x30, [x0, #80]

// Save stack pointer.
mov x1, sp
str x1, [x0, #96]

// Save VFP registers.
stp d8, d9, [x0, #104]
stp d10, d11, [x0, #120]
stp d12, d13, [x0, #136]
stp d14, d15, [x0, #152]

// Return zero for a direct invocation.
mov x0, #0
ret
END(setjmp)

#endif
5 changes: 0 additions & 5 deletions src/libc/setjmp/setjmp_longjmp_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
#include <setjmp.h>
#include <testing.h>

// Clang doesn't provide setjmp()/longjmp() support on some architectures.
#if !defined(__aarch64__) && !defined(__riscv)

TEST(setjmp_longjmp, example) {
jmp_buf jmp;
while (setjmp(jmp) != 123)
longjmp(jmp, 123);
}

#endif
5 changes: 0 additions & 5 deletions src/libc/setjmp/sigsetjmp_siglongjmp_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
#include <setjmp.h>
#include <testing.h>

// Clang doesn't provide setjmp()/longjmp() support on some architectures.
#if !defined(__aarch64__) && !defined(__riscv)

TEST(sigsetjmp_siglongjmp, example) {
sigjmp_buf jmp;
while (sigsetjmp(jmp, 0) != 123)
siglongjmp(jmp, 123);
}

#endif

0 comments on commit ef8a62e

Please sign in to comment.