From 407c0c538a282a5bede21140ec836062381256bc Mon Sep 17 00:00:00 2001 From: TImada Date: Tue, 9 Jun 2020 23:39:30 +0900 Subject: [PATCH 1/8] Introduced libaeabi to provide builtin functions for aarch32 --- GNUmakefile | 13 +- lib32/GNUmakefile | 39 ++++ lib32/aeabi/.gitignore | 3 + lib32/aeabi/GNUmakefile | 31 +++ lib32/aeabi/README.md | 15 ++ lib32/aeabi/arm/aeabi_idivmod.S | 50 +++++ lib32/aeabi/arm/aeabi_ldivmod.S | 45 +++++ lib32/aeabi/arm/aeabi_uidivmod.S | 57 ++++++ lib32/aeabi/arm/aeabi_uldivmod.S | 45 +++++ lib32/aeabi/arm/divmodsi4.S | 70 +++++++ lib32/aeabi/assembly.h | 200 +++++++++++++++++++ lib32/aeabi/divdi3.c | 25 +++ lib32/aeabi/divmoddi4.c | 21 ++ lib32/aeabi/divsi3.c | 35 ++++ lib32/aeabi/fixdfdi.c | 44 +++++ lib32/aeabi/fixunsdfdi.c | 42 ++++ lib32/aeabi/floatdidf.c | 103 ++++++++++ lib32/aeabi/floatundidf.c | 106 ++++++++++ lib32/aeabi/fp_lib.h | 319 +++++++++++++++++++++++++++++++ lib32/aeabi/int_endianness.h | 114 +++++++++++ lib32/aeabi/int_lib.h | 141 ++++++++++++++ lib32/aeabi/int_math.h | 106 ++++++++++ lib32/aeabi/int_types.h | 174 +++++++++++++++++ lib32/aeabi/int_util.h | 31 +++ lib32/aeabi/tp_read.c | 14 ++ lib32/aeabi/udivmoddi4.c | 200 +++++++++++++++++++ lib32/aeabi/udivmodsi4.c | 21 ++ lib32/aeabi/udivsi3.c | 62 ++++++ 28 files changed, 2125 insertions(+), 1 deletion(-) create mode 100644 lib32/GNUmakefile create mode 100644 lib32/aeabi/.gitignore create mode 100644 lib32/aeabi/GNUmakefile create mode 100644 lib32/aeabi/README.md create mode 100644 lib32/aeabi/arm/aeabi_idivmod.S create mode 100644 lib32/aeabi/arm/aeabi_ldivmod.S create mode 100644 lib32/aeabi/arm/aeabi_uidivmod.S create mode 100644 lib32/aeabi/arm/aeabi_uldivmod.S create mode 100644 lib32/aeabi/arm/divmodsi4.S create mode 100644 lib32/aeabi/assembly.h create mode 100644 lib32/aeabi/divdi3.c create mode 100644 lib32/aeabi/divmoddi4.c create mode 100644 lib32/aeabi/divsi3.c create mode 100644 lib32/aeabi/fixdfdi.c create mode 100644 lib32/aeabi/fixunsdfdi.c create mode 100644 lib32/aeabi/floatdidf.c create mode 100644 lib32/aeabi/floatundidf.c create mode 100644 lib32/aeabi/fp_lib.h create mode 100644 lib32/aeabi/int_endianness.h create mode 100644 lib32/aeabi/int_lib.h create mode 100644 lib32/aeabi/int_math.h create mode 100644 lib32/aeabi/int_types.h create mode 100644 lib32/aeabi/int_util.h create mode 100644 lib32/aeabi/tp_read.c create mode 100644 lib32/aeabi/udivmoddi4.c create mode 100644 lib32/aeabi/udivmodsi4.c create mode 100644 lib32/aeabi/udivsi3.c diff --git a/GNUmakefile b/GNUmakefile index feca365e..fef806b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -21,7 +21,12 @@ $(TOPDIR)/Makeconf: $(error Makeconf not found, please run ./configure.sh) include Makefile.common -SUBDIRS := bindings tenders elftool tests +ifeq ($(CONFIG_BITS), __BITS_32__) +SUBDIRS := lib32 +else +SUBDIRS := +endif +SUBDIRS += bindings tenders elftool tests tests: bindings elftool @@ -130,6 +135,9 @@ ifdef CONFIG_HVT endif ifdef CONFIG_SPT cp tenders/spt/solo5-spt $(PREFIX)/bin +ifeq ($(CONFIG_ARCH), arm) + cp lib32/aeabi/libaeabi.a $(PREFIX)/lib/solo5-bindings-spt +endif endif ifdef CONFIG_VIRTIO cp scripts/virtio-mkimage/solo5-virtio-mkimage.sh \ @@ -157,6 +165,9 @@ uninstall-opam-%: force-uninstall $(PREFIX)/bin/solo5-hvt-configure # CONFIG_SPT $(RM) $(PREFIX)/bin/solo5-spt +ifeq ($(CONFIG_ARCH), arm) + $(RM) $(PREFIX)/lib/solo5-bindings-spt/libaeabi.a +endif # CONFIG_VIRTIO $(RM) $(PREFIX)/bin/solo5-virtio-mkimage $(RM) $(PREFIX)/bin/solo5-virtio-run diff --git a/lib32/GNUmakefile b/lib32/GNUmakefile new file mode 100644 index 00000000..c9ce2918 --- /dev/null +++ b/lib32/GNUmakefile @@ -0,0 +1,39 @@ +# Copyright (c) 2015-2019 Contributors as noted in the AUTHORS file +# +# This file is part of Solo5, a sandboxed execution environment. +# +# 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. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ifndef TOPDIR +$(error TOPDIR must be set, run $(MAKE) from the top of the source tree or set it manually) +endif +include $(TOPDIR)/Makeconf + +ifeq ($(CONFIG_ARCH),arm) +LIBDIRS := aeabi +endif + +TOPTARGETS := all clean + +.PHONY: $(TOPTARGETS) $(LIBDIRS) + +$(TOPTARGETS): $(LIBDIRS) + +$(LIBDIRS): + @echo "MAKE $@" + $(MAKE) -C $@ $(MAKECMDGOALS) $(SUBOVERRIDE) + +.SUFFIXES: +$(V).SILENT: diff --git a/lib32/aeabi/.gitignore b/lib32/aeabi/.gitignore new file mode 100644 index 00000000..a3337417 --- /dev/null +++ b/lib32/aeabi/.gitignore @@ -0,0 +1,3 @@ +*.o +*.a +arm/*.o diff --git a/lib32/aeabi/GNUmakefile b/lib32/aeabi/GNUmakefile new file mode 100644 index 00000000..0b93832d --- /dev/null +++ b/lib32/aeabi/GNUmakefile @@ -0,0 +1,31 @@ +NAME := aeabi + +CC := arm-linux-gnueabihf-gcc +AS := arm-linux-gnueabihf-gcc +AR := arm-linux-gnueabihf-ar + +CFLAGS := -std=c11 -Wall -Wextra -Werror -O2 -g -mthumb -march=armv7 +ASFLAGS := -Wall -Wextra -Werror -O2 -g -mthumb -march=armv7 + +OBJS := divdi3.o divsi3.o divmoddi4.o fixdfdi.o fixunsdfdi.o floatdidf.o floatundidf.o udivsi3.o udivmodsi4.o udivmoddi4.o tp_read.o +OBJS += arm/aeabi_idivmod.o arm/aeabi_ldivmod.o arm/aeabi_uidivmod.o arm/aeabi_uldivmod.o arm/divmodsi4.o +OUTPUT := libaeabi.a +INSTALL_DIR := /usr/lib + +all : staticlib + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: %.S + $(AS) $(ASFLAGS) -c $< -o $@ + +staticlib: $(OBJS) + $(AR) r $(OUTPUT) $(OBJS) + +install: + install -m 644 $(OUTPUT) $(INSTALL_DIR) + +clean: + @echo "CLEAN $(NAME)" + rm -f $(OBJS) $(OUTPUT) diff --git a/lib32/aeabi/README.md b/lib32/aeabi/README.md new file mode 100644 index 00000000..1ec7967a --- /dev/null +++ b/lib32/aeabi/README.md @@ -0,0 +1,15 @@ +# libaeabi +This library has 32-bit __aeabi functions to support aarch32, based on LLVM compiler-rt (Ver 10.0.0) builtins at https://github.com/llvm/llvm-project/tree/master/compiler-rt/lib/builtins. + +## What's included? +- `__aeabi_d2lz` +- `__aeabi_d2ulz` +- `__aeabi_idiv` +- `__aeabi_idivmod` +- `__aeabi_l2d` +- `__aeabi_ldivmod` +- `__aeabi_uidiv` +- `__aeabi_uidivmod` +- `__aeabi_ul2d` +- `__aeabi_uldivmod` +- `__aeabi_read_tp` diff --git a/lib32/aeabi/arm/aeabi_idivmod.S b/lib32/aeabi/arm/aeabi_idivmod.S new file mode 100644 index 00000000..bb80e4b9 --- /dev/null +++ b/lib32/aeabi/arm/aeabi_idivmod.S @@ -0,0 +1,50 @@ +//===-- aeabi_idivmod.S - EABI idivmod implementation ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { int quot, int rem} __aeabi_idivmod(int numerator, int denominator) { +// int rem, quot; +// quot = __divmodsi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + +#if defined(__MINGW32__) +#define __aeabi_idivmod __rt_sdiv +#endif + + .syntax unified + .text + DEFINE_CODE_STATE + .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) +#if defined(USE_THUMB_1) + push {r0, r1, lr} + bl SYMBOL_NAME(__divsi3) + pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom + muls r2, r0, r2 // r2 = quot * denom + subs r1, r1, r2 + JMP (r3) +#else // defined(USE_THUMB_1) + push { lr } + sub sp, sp, #4 + mov r2, sp +#if defined(__MINGW32__) + mov r3, r0 + mov r0, r1 + mov r1, r3 +#endif + bl SYMBOL_NAME(__divmodsi4) + ldr r1, [sp] + add sp, sp, #4 + pop { pc } +#endif // defined(USE_THUMB_1) +END_COMPILERRT_FUNCTION(__aeabi_idivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/lib32/aeabi/arm/aeabi_ldivmod.S b/lib32/aeabi/arm/aeabi_ldivmod.S new file mode 100644 index 00000000..d0d06be6 --- /dev/null +++ b/lib32/aeabi/arm/aeabi_ldivmod.S @@ -0,0 +1,45 @@ +//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { int64_t quot, int64_t rem} +// __aeabi_ldivmod(int64_t numerator, int64_t denominator) { +// int64_t rem, quot; +// quot = __divmoddi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + +#if defined(__MINGW32__) +#define __aeabi_ldivmod __rt_sdiv64 +#endif + + .syntax unified + .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod) + push {r6, lr} + sub sp, sp, #16 + add r6, sp, #8 + str r6, [sp] +#if defined(__MINGW32__) + movs r6, r0 + movs r0, r2 + movs r2, r6 + movs r6, r1 + movs r1, r3 + movs r3, r6 +#endif + bl SYMBOL_NAME(__divmoddi4) + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r6, pc} +END_COMPILERRT_FUNCTION(__aeabi_ldivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/lib32/aeabi/arm/aeabi_uidivmod.S b/lib32/aeabi/arm/aeabi_uidivmod.S new file mode 100644 index 00000000..df030769 --- /dev/null +++ b/lib32/aeabi/arm/aeabi_uidivmod.S @@ -0,0 +1,57 @@ +//===-- aeabi_uidivmod.S - EABI uidivmod implementation -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { unsigned quot, unsigned rem} +// __aeabi_uidivmod(unsigned numerator, unsigned denominator) { +// unsigned rem, quot; +// quot = __udivmodsi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + +#if defined(__MINGW32__) +#define __aeabi_uidivmod __rt_udiv +#endif + + .syntax unified + .text + DEFINE_CODE_STATE + .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) +#if defined(USE_THUMB_1) + cmp r0, r1 + bcc LOCAL_LABEL(case_denom_larger) + push {r0, r1, lr} + bl SYMBOL_NAME(__aeabi_uidiv) + pop {r1, r2, r3} + muls r2, r0, r2 // r2 = quot * denom + subs r1, r1, r2 + JMP (r3) +LOCAL_LABEL(case_denom_larger): + movs r1, r0 + movs r0, #0 + JMP (lr) +#else // defined(USE_THUMB_1) + push { lr } + sub sp, sp, #4 + mov r2, sp +#if defined(__MINGW32__) + mov r3, r0 + mov r0, r1 + mov r1, r3 +#endif + bl SYMBOL_NAME(__udivmodsi4) + ldr r1, [sp] + add sp, sp, #4 + pop { pc } +#endif +END_COMPILERRT_FUNCTION(__aeabi_uidivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/lib32/aeabi/arm/aeabi_uldivmod.S b/lib32/aeabi/arm/aeabi_uldivmod.S new file mode 100644 index 00000000..4fc97704 --- /dev/null +++ b/lib32/aeabi/arm/aeabi_uldivmod.S @@ -0,0 +1,45 @@ +//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { uint64_t quot, uint64_t rem} +// __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) { +// uint64_t rem, quot; +// quot = __udivmoddi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + +#if defined(__MINGW32__) +#define __aeabi_uldivmod __rt_udiv64 +#endif + + .syntax unified + .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod) + push {r6, lr} + sub sp, sp, #16 + add r6, sp, #8 + str r6, [sp] +#if defined(__MINGW32__) + movs r6, r0 + movs r0, r2 + movs r2, r6 + movs r6, r1 + movs r1, r3 + movs r3, r6 +#endif + bl SYMBOL_NAME(__udivmoddi4) + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r6, pc} +END_COMPILERRT_FUNCTION(__aeabi_uldivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/lib32/aeabi/arm/divmodsi4.S b/lib32/aeabi/arm/divmodsi4.S new file mode 100644 index 00000000..f94438df --- /dev/null +++ b/lib32/aeabi/arm/divmodsi4.S @@ -0,0 +1,70 @@ +//===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __divmodsi4 (32-bit signed integer divide and +// modulus) function for the ARM architecture. A naive digit-by-digit +// computation is employed for simplicity. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +#define ESTABLISH_FRAME \ + push {r4-r7, lr} ;\ + add r7, sp, #12 +#define CLEAR_FRAME_AND_RETURN \ + pop {r4-r7, pc} + + .syntax unified + .text + DEFINE_CODE_STATE + +@ int __divmodsi4(int divident, int divisor, int *remainder) +@ Calculate the quotient and remainder of the (signed) division. The return +@ value is the quotient, the remainder is placed in the variable. + + .p2align 3 +DEFINE_COMPILERRT_FUNCTION(__divmodsi4) +#if __ARM_ARCH_EXT_IDIV__ + tst r1, r1 + beq LOCAL_LABEL(divzero) + mov r3, r0 + sdiv r0, r3, r1 + mls r1, r0, r1, r3 + str r1, [r2] + bx lr +LOCAL_LABEL(divzero): + mov r0, #0 + bx lr +#else + ESTABLISH_FRAME +// Set aside the sign of the quotient and modulus, and the address for the +// modulus. + eor r4, r0, r1 + mov r5, r0 + mov r6, r2 +// Take the absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). + eor ip, r0, r0, asr #31 + eor lr, r1, r1, asr #31 + sub r0, ip, r0, asr #31 + sub r1, lr, r1, asr #31 +// Unsigned divmod: + bl SYMBOL_NAME(__udivmodsi4) +// Apply the sign of quotient and modulus + ldr r1, [r6] + eor r0, r0, r4, asr #31 + eor r1, r1, r5, asr #31 + sub r0, r0, r4, asr #31 + sub r1, r1, r5, asr #31 + str r1, [r6] + CLEAR_FRAME_AND_RETURN +#endif +END_COMPILERRT_FUNCTION(__divmodsi4) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/lib32/aeabi/assembly.h b/lib32/aeabi/assembly.h new file mode 100644 index 00000000..f437cb87 --- /dev/null +++ b/lib32/aeabi/assembly.h @@ -0,0 +1,200 @@ +//===-- assembly.h - compiler-rt assembler support macros -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines macros for use in compiler-rt assembler source. +// This file is not part of the interface of this library. +// +//===----------------------------------------------------------------------===// + +#ifndef COMPILERRT_ASSEMBLY_H +#define COMPILERRT_ASSEMBLY_H + +#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) +#define SEPARATOR @ +#else +#define SEPARATOR ; +#endif + +#if defined(__APPLE__) +#define HIDDEN(name) .private_extern name +#define LOCAL_LABEL(name) L_##name +// tell linker it can break up file at label boundaries +#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols +#define SYMBOL_IS_FUNC(name) +#define CONST_SECTION .const + +#define NO_EXEC_STACK_DIRECTIVE + +#elif defined(__ELF__) + +#define HIDDEN(name) .hidden name +#define LOCAL_LABEL(name) .L_##name +#define FILE_LEVEL_DIRECTIVE +#if defined(__arm__) +#define SYMBOL_IS_FUNC(name) .type name,%function +#else +#define SYMBOL_IS_FUNC(name) .type name,@function +#endif +#define CONST_SECTION .section .rodata + +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ + defined(__linux__) +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits +#else +#define NO_EXEC_STACK_DIRECTIVE +#endif + +#else // !__APPLE__ && !__ELF__ + +#define HIDDEN(name) +#define LOCAL_LABEL(name) .L ## name +#define FILE_LEVEL_DIRECTIVE +#define SYMBOL_IS_FUNC(name) \ + .def name SEPARATOR \ + .scl 2 SEPARATOR \ + .type 32 SEPARATOR \ + .endef +#define CONST_SECTION .section .rdata,"rd" + +#define NO_EXEC_STACK_DIRECTIVE + +#endif + +#if defined(__arm__) + +// Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros: +// - for '-mthumb -march=armv6' compiler defines '__thumb__' +// - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' +#if defined(__thumb2__) || defined(__thumb__) +#define DEFINE_CODE_STATE .thumb SEPARATOR +#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR +#if defined(__thumb2__) +#define USE_THUMB_2 +#define IT(cond) it cond +#define ITT(cond) itt cond +#define ITE(cond) ite cond +#else +#define USE_THUMB_1 +#define IT(cond) +#define ITT(cond) +#define ITE(cond) +#endif // defined(__thumb__2) +#else // !defined(__thumb2__) && !defined(__thumb__) +#define DEFINE_CODE_STATE .arm SEPARATOR +#define DECLARE_FUNC_ENCODING +#define IT(cond) +#define ITT(cond) +#define ITE(cond) +#endif + +#if defined(USE_THUMB_1) && defined(USE_THUMB_2) +#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together." +#endif + +#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 +#define ARM_HAS_BX +#endif +#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \ + (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__))) +#define __ARM_FEATURE_CLZ +#endif + +#ifdef ARM_HAS_BX +#define JMP(r) bx r +#define JMPc(r, c) bx##c r +#else +#define JMP(r) mov pc, r +#define JMPc(r, c) mov##c pc, r +#endif + +// pop {pc} can't switch Thumb mode on ARMv4T +#if __ARM_ARCH >= 5 +#define POP_PC() pop {pc} +#else +#define POP_PC() \ + pop {ip}; \ + JMP(ip) +#endif + +#if defined(USE_THUMB_2) +#define WIDE(op) op.w +#else +#define WIDE(op) op +#endif +#else // !defined(__arm) +#define DECLARE_FUNC_ENCODING +#define DEFINE_CODE_STATE +#endif + +#define GLUE2(a, b) a##b +#define GLUE(a, b) GLUE2(a, b) +#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) + +#ifdef VISIBILITY_HIDDEN +#define DECLARE_SYMBOL_VISIBILITY(name) \ + HIDDEN(SYMBOL_NAME(name)) SEPARATOR +#else +#define DECLARE_SYMBOL_VISIBILITY(name) +#endif + +#define DEFINE_COMPILERRT_FUNCTION(name) \ + DEFINE_CODE_STATE \ + FILE_LEVEL_DIRECTIVE SEPARATOR \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_SYMBOL_VISIBILITY(name) \ + DECLARE_FUNC_ENCODING \ + SYMBOL_NAME(name): + +#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ + DEFINE_CODE_STATE \ + FILE_LEVEL_DIRECTIVE SEPARATOR \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \ + .thumb_func SEPARATOR \ + SYMBOL_NAME(name): + +#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ + DEFINE_CODE_STATE \ + FILE_LEVEL_DIRECTIVE SEPARATOR \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + HIDDEN(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_FUNC_ENCODING \ + SYMBOL_NAME(name): + +#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ + DEFINE_CODE_STATE \ + .globl name SEPARATOR \ + SYMBOL_IS_FUNC(name) SEPARATOR \ + HIDDEN(name) SEPARATOR \ + DECLARE_FUNC_ENCODING \ + name: + +#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR \ + .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR + +#if defined(__ARM_EABI__) +#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \ + DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name) +#else +#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) +#endif + +#ifdef __ELF__ +#define END_COMPILERRT_FUNCTION(name) \ + .size SYMBOL_NAME(name), . - SYMBOL_NAME(name) +#else +#define END_COMPILERRT_FUNCTION(name) +#endif + +#endif // COMPILERRT_ASSEMBLY_H diff --git a/lib32/aeabi/divdi3.c b/lib32/aeabi/divdi3.c new file mode 100644 index 00000000..ee08d655 --- /dev/null +++ b/lib32/aeabi/divdi3.c @@ -0,0 +1,25 @@ +//===-- divdi3.c - Implement __divdi3 -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __divdi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a / b + +COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; // s_a = a < 0 ? -1 : 0 + di_int s_b = b >> bits_in_dword_m1; // s_b = b < 0 ? -1 : 0 + a = (a ^ s_a) - s_a; // negate if s_a == -1 + b = (b ^ s_b) - s_b; // negate if s_b == -1 + s_a ^= s_b; // sign of quotient + return (__udivmoddi4(a, b, (du_int *)0) ^ s_a) - s_a; // negate if s_a == -1 +} diff --git a/lib32/aeabi/divmoddi4.c b/lib32/aeabi/divmoddi4.c new file mode 100644 index 00000000..7f333510 --- /dev/null +++ b/lib32/aeabi/divmoddi4.c @@ -0,0 +1,21 @@ +//===-- divmoddi4.c - Implement __divmoddi4 -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __divmoddi4 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a / b, *rem = a % b + +COMPILER_RT_ABI di_int __divmoddi4(di_int a, di_int b, di_int *rem) { + di_int d = __divdi3(a, b); + *rem = a - (d * b); + return d; +} diff --git a/lib32/aeabi/divsi3.c b/lib32/aeabi/divsi3.c new file mode 100644 index 00000000..b97e1111 --- /dev/null +++ b/lib32/aeabi/divsi3.c @@ -0,0 +1,35 @@ +//===-- divsi3.c - Implement __divsi3 -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __divsi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a / b + +COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) { + const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1; + si_int s_a = a >> bits_in_word_m1; // s_a = a < 0 ? -1 : 0 + si_int s_b = b >> bits_in_word_m1; // s_b = b < 0 ? -1 : 0 + a = (a ^ s_a) - s_a; // negate if s_a == -1 + b = (b ^ s_b) - s_b; // negate if s_b == -1 + s_a ^= s_b; // sign of quotient + // + // On CPUs without unsigned hardware division support, + // this calls __udivsi3 (notice the cast to su_int). + // On CPUs with unsigned hardware division support, + // this uses the unsigned division instruction. + // + return ((su_int)a / (su_int)b ^ s_a) - s_a; // negate if s_a == -1 +} + +#if defined(__ARM_EABI__) +COMPILER_RT_ALIAS(__divsi3, __aeabi_idiv) +#endif diff --git a/lib32/aeabi/fixdfdi.c b/lib32/aeabi/fixdfdi.c new file mode 100644 index 00000000..2ed5261c --- /dev/null +++ b/lib32/aeabi/fixdfdi.c @@ -0,0 +1,44 @@ +//===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +#ifndef __SOFT_FP__ +// Support for systems that have hardware floating-point; can set the invalid +// flag as a side-effect of computation. + +COMPILER_RT_ABI du_int __fixunsdfdi(double a); + +COMPILER_RT_ABI di_int __fixdfdi(double a) { + if (a < 0.0) { + return -__fixunsdfdi(-a); + } + return __fixunsdfdi(a); +} + +#else +// Support for systems that don't have hardware floating-point; there are no +// flags to set, and we don't want to code-gen to an unknown soft-float +// implementation. + +typedef di_int fixint_t; +typedef du_int fixuint_t; +#include "fp_fixint_impl.inc" + +COMPILER_RT_ABI di_int __fixdfdi(fp_t a) { return __fixint(a); } + +#endif + +#if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI di_int __aeabi_d2lz(fp_t a) { return __fixdfdi(a); } +#else +COMPILER_RT_ALIAS(__fixdfdi, __aeabi_d2lz) +#endif +#endif diff --git a/lib32/aeabi/fixunsdfdi.c b/lib32/aeabi/fixunsdfdi.c new file mode 100644 index 00000000..d2ba7382 --- /dev/null +++ b/lib32/aeabi/fixunsdfdi.c @@ -0,0 +1,42 @@ +//===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +#ifndef __SOFT_FP__ +// Support for systems that have hardware floating-point; can set the invalid +// flag as a side-effect of computation. + +COMPILER_RT_ABI du_int __fixunsdfdi(double a) { + if (a <= 0.0) + return 0; + su_int high = a / 4294967296.f; // a / 0x1p32f; + su_int low = a - (double)high * 4294967296.f; // high * 0x1p32f; + return ((du_int)high << 32) | low; +} + +#else +// Support for systems that don't have hardware floating-point; there are no +// flags to set, and we don't want to code-gen to an unknown soft-float +// implementation. + +typedef du_int fixuint_t; +#include "fp_fixuint_impl.inc" + +COMPILER_RT_ABI du_int __fixunsdfdi(fp_t a) { return __fixuint(a); } + +#endif + +#if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) { return __fixunsdfdi(a); } +#else +COMPILER_RT_ALIAS(__fixunsdfdi, __aeabi_d2ulz) +#endif +#endif diff --git a/lib32/aeabi/floatdidf.c b/lib32/aeabi/floatdidf.c new file mode 100644 index 00000000..8f887314 --- /dev/null +++ b/lib32/aeabi/floatdidf.c @@ -0,0 +1,103 @@ +//===-- floatdidf.c - Implement __floatdidf -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __floatdidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// di_int is a 64 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// mmmm + +#ifndef __SOFT_FP__ +// Support for systems that have hardware floating-point; we'll set the inexact +// flag as a side-effect of this computation. + +COMPILER_RT_ABI double __floatdidf(di_int a) { + static const double twop52 = 4503599627370496.0; // 0x1.0p52 + static const double twop32 = 4294967296.0; // 0x1.0p32 + + union { + int64_t x; + double d; + } low = {.d = twop52}; + + const double high = (int32_t)(a >> 32) * twop32; + low.x |= a & INT64_C(0x00000000ffffffff); + + const double result = (high - twop52) + low.d; + return result; +} + +#else +// Support for systems that don't have hardware floating-point; there are no +// flags to set, and we don't want to code-gen to an unknown soft-float +// implementation. + +COMPILER_RT_ABI double __floatdidf(di_int a) { + if (a == 0) + return 0.0; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N - 1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); // number of significant digits + int e = sd - 1; // exponent + if (sd > DBL_MANT_DIG) { + // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + // 12345678901234567890123456 + // 1 = msb 1 bit + // P = bit DBL_MANT_DIG-1 bits to the right of 1 + // Q = bit DBL_MANT_DIG bits to the right of 1 + // R = "or" of all bits to the right of Q + switch (sd) { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = ((du_int)a >> (sd - (DBL_MANT_DIG + 2))) | + ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0); + }; + // finish: + a |= (a & 4) != 0; // Or P into R + ++a; // round - this step may add a significant bit + a >>= 2; // dump Q and R + // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits + if (a & ((du_int)1 << DBL_MANT_DIG)) { + a >>= 1; + ++e; + } + // a is now rounded to DBL_MANT_DIG bits + } else { + a <<= (DBL_MANT_DIG - sd); + // a is now rounded to DBL_MANT_DIG bits + } + double_bits fb; + fb.u.s.high = ((su_int)s & 0x80000000) | // sign + ((e + 1023) << 20) | // exponent + ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high + fb.u.s.low = (su_int)a; // mantissa-low + return fb.f; +} +#endif + +#if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI double __aeabi_l2d(di_int a) { return __floatdidf(a); } +#else +COMPILER_RT_ALIAS(__floatdidf, __aeabi_l2d) +#endif +#endif diff --git a/lib32/aeabi/floatundidf.c b/lib32/aeabi/floatundidf.c new file mode 100644 index 00000000..e7c6aae5 --- /dev/null +++ b/lib32/aeabi/floatundidf.c @@ -0,0 +1,106 @@ +//===-- floatundidf.c - Implement __floatundidf ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __floatundidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// du_int is a 64 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// mmmm + +#include "int_lib.h" + +#ifndef __SOFT_FP__ +// Support for systems that have hardware floating-point; we'll set the inexact +// flag as a side-effect of this computation. + +COMPILER_RT_ABI double __floatundidf(du_int a) { + static const double twop52 = 4503599627370496.0; // 0x1.0p52 + static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84 + static const double twop84_plus_twop52 = + 19342813118337666422669312.0; // 0x1.00000001p84 + + union { + uint64_t x; + double d; + } high = {.d = twop84}; + union { + uint64_t x; + double d; + } low = {.d = twop52}; + + high.x |= a >> 32; + low.x |= a & UINT64_C(0x00000000ffffffff); + + const double result = (high.d - twop84_plus_twop52) + low.d; + return result; +} + +#else +// Support for systems that don't have hardware floating-point; there are no +// flags to set, and we don't want to code-gen to an unknown soft-float +// implementation. + +COMPILER_RT_ABI double __floatundidf(du_int a) { + if (a == 0) + return 0.0; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int sd = N - __builtin_clzll(a); // number of significant digits + int e = sd - 1; // exponent + if (sd > DBL_MANT_DIG) { + // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + // 12345678901234567890123456 + // 1 = msb 1 bit + // P = bit DBL_MANT_DIG-1 bits to the right of 1 + // Q = bit DBL_MANT_DIG bits to the right of 1 + // R = "or" of all bits to the right of Q + switch (sd) { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (DBL_MANT_DIG + 2))) | + ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0); + }; + // finish: + a |= (a & 4) != 0; // Or P into R + ++a; // round - this step may add a significant bit + a >>= 2; // dump Q and R + // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits + if (a & ((du_int)1 << DBL_MANT_DIG)) { + a >>= 1; + ++e; + } + // a is now rounded to DBL_MANT_DIG bits + } else { + a <<= (DBL_MANT_DIG - sd); + // a is now rounded to DBL_MANT_DIG bits + } + double_bits fb; + fb.u.s.high = ((e + 1023) << 20) | // exponent + ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high + fb.u.s.low = (su_int)a; // mantissa-low + return fb.f; +} +#endif + +#if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI double __aeabi_ul2d(du_int a) { return __floatundidf(a); } +#else +COMPILER_RT_ALIAS(__floatundidf, __aeabi_ul2d) +#endif +#endif diff --git a/lib32/aeabi/fp_lib.h b/lib32/aeabi/fp_lib.h new file mode 100644 index 00000000..e2a90668 --- /dev/null +++ b/lib32/aeabi/fp_lib.h @@ -0,0 +1,319 @@ +//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a configuration header for soft-float routines in compiler-rt. +// This file does not provide any part of the compiler-rt interface, but defines +// many useful constants and utility routines that are used in the +// implementation of the soft-float routines in compiler-rt. +// +// Assumes that float, double and long double correspond to the IEEE-754 +// binary32, binary64 and binary 128 types, respectively, and that integer +// endianness matches floating point endianness on the target platform. +// +//===----------------------------------------------------------------------===// + +#ifndef FP_LIB_HEADER +#define FP_LIB_HEADER + +#include "int_lib.h" +#include "int_math.h" +#include +#include +#include + +// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in +// 32-bit mode. +#if defined(__FreeBSD__) && defined(__i386__) +#include +#if __FreeBSD_version < 903000 // v9.3 +#define uint64_t unsigned long long +#define int64_t long long +#undef UINT64_C +#define UINT64_C(c) (c##ULL) +#endif +#endif + +#if defined SINGLE_PRECISION + +typedef uint32_t rep_t; +typedef int32_t srep_t; +typedef float fp_t; +#define REP_C UINT32_C +#define significandBits 23 + +static __inline int rep_clz(rep_t a) { return __builtin_clz(a); } + +// 32x32 --> 64 bit multiply +static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + const uint64_t product = (uint64_t)a * b; + *hi = product >> 32; + *lo = product; +} +COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b); + +#elif defined DOUBLE_PRECISION + +typedef uint64_t rep_t; +typedef int64_t srep_t; +typedef double fp_t; +#define REP_C UINT64_C +#define significandBits 52 + +static __inline int rep_clz(rep_t a) { +#if defined __LP64__ + return __builtin_clzl(a); +#else + if (a & REP_C(0xffffffff00000000)) + return __builtin_clz(a >> 32); + else + return 32 + __builtin_clz(a & REP_C(0xffffffff)); +#endif +} + +#define loWord(a) (a & 0xffffffffU) +#define hiWord(a) (a >> 32) + +// 64x64 -> 128 wide multiply for platforms that don't have such an operation; +// many 64-bit platforms have this operation, but they tend to have hardware +// floating-point, so we don't bother with a special case for them here. +static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + // Each of the component 32x32 -> 64 products + const uint64_t plolo = loWord(a) * loWord(b); + const uint64_t plohi = loWord(a) * hiWord(b); + const uint64_t philo = hiWord(a) * loWord(b); + const uint64_t phihi = hiWord(a) * hiWord(b); + // Sum terms that contribute to lo in a way that allows us to get the carry + const uint64_t r0 = loWord(plolo); + const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo); + *lo = r0 + (r1 << 32); + // Sum terms contributing to hi with the carry from lo + *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi; +} +#undef loWord +#undef hiWord + +COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b); + +#elif defined QUAD_PRECISION +#if __LDBL_MANT_DIG__ == 113 && defined(__SIZEOF_INT128__) +#define CRT_LDBL_128BIT +typedef __uint128_t rep_t; +typedef __int128_t srep_t; +typedef long double fp_t; +#define REP_C (__uint128_t) +// Note: Since there is no explicit way to tell compiler the constant is a +// 128-bit integer, we let the constant be casted to 128-bit integer +#define significandBits 112 + +static __inline int rep_clz(rep_t a) { + const union { + __uint128_t ll; +#if _YUGA_BIG_ENDIAN + struct { + uint64_t high, low; + } s; +#else + struct { + uint64_t low, high; + } s; +#endif + } uu = {.ll = a}; + + uint64_t word; + uint64_t add; + + if (uu.s.high) { + word = uu.s.high; + add = 0; + } else { + word = uu.s.low; + add = 64; + } + return __builtin_clzll(word) + add; +} + +#define Word_LoMask UINT64_C(0x00000000ffffffff) +#define Word_HiMask UINT64_C(0xffffffff00000000) +#define Word_FullMask UINT64_C(0xffffffffffffffff) +#define Word_1(a) (uint64_t)((a >> 96) & Word_LoMask) +#define Word_2(a) (uint64_t)((a >> 64) & Word_LoMask) +#define Word_3(a) (uint64_t)((a >> 32) & Word_LoMask) +#define Word_4(a) (uint64_t)(a & Word_LoMask) + +// 128x128 -> 256 wide multiply for platforms that don't have such an operation; +// many 64-bit platforms have this operation, but they tend to have hardware +// floating-point, so we don't bother with a special case for them here. +static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + + const uint64_t product11 = Word_1(a) * Word_1(b); + const uint64_t product12 = Word_1(a) * Word_2(b); + const uint64_t product13 = Word_1(a) * Word_3(b); + const uint64_t product14 = Word_1(a) * Word_4(b); + const uint64_t product21 = Word_2(a) * Word_1(b); + const uint64_t product22 = Word_2(a) * Word_2(b); + const uint64_t product23 = Word_2(a) * Word_3(b); + const uint64_t product24 = Word_2(a) * Word_4(b); + const uint64_t product31 = Word_3(a) * Word_1(b); + const uint64_t product32 = Word_3(a) * Word_2(b); + const uint64_t product33 = Word_3(a) * Word_3(b); + const uint64_t product34 = Word_3(a) * Word_4(b); + const uint64_t product41 = Word_4(a) * Word_1(b); + const uint64_t product42 = Word_4(a) * Word_2(b); + const uint64_t product43 = Word_4(a) * Word_3(b); + const uint64_t product44 = Word_4(a) * Word_4(b); + + const __uint128_t sum0 = (__uint128_t)product44; + const __uint128_t sum1 = (__uint128_t)product34 + (__uint128_t)product43; + const __uint128_t sum2 = + (__uint128_t)product24 + (__uint128_t)product33 + (__uint128_t)product42; + const __uint128_t sum3 = (__uint128_t)product14 + (__uint128_t)product23 + + (__uint128_t)product32 + (__uint128_t)product41; + const __uint128_t sum4 = + (__uint128_t)product13 + (__uint128_t)product22 + (__uint128_t)product31; + const __uint128_t sum5 = (__uint128_t)product12 + (__uint128_t)product21; + const __uint128_t sum6 = (__uint128_t)product11; + + const __uint128_t r0 = (sum0 & Word_FullMask) + ((sum1 & Word_LoMask) << 32); + const __uint128_t r1 = (sum0 >> 64) + ((sum1 >> 32) & Word_FullMask) + + (sum2 & Word_FullMask) + ((sum3 << 32) & Word_HiMask); + + *lo = r0 + (r1 << 64); + *hi = (r1 >> 64) + (sum1 >> 96) + (sum2 >> 64) + (sum3 >> 32) + sum4 + + (sum5 << 32) + (sum6 << 64); +} +#undef Word_1 +#undef Word_2 +#undef Word_3 +#undef Word_4 +#undef Word_HiMask +#undef Word_LoMask +#undef Word_FullMask +#endif // __LDBL_MANT_DIG__ == 113 && __SIZEOF_INT128__ +#else +#error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined. +#endif + +#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || \ + defined(CRT_LDBL_128BIT) +#define typeWidth (sizeof(rep_t) * CHAR_BIT) +#define exponentBits (typeWidth - significandBits - 1) +#define maxExponent ((1 << exponentBits) - 1) +#define exponentBias (maxExponent >> 1) + +#define implicitBit (REP_C(1) << significandBits) +#define significandMask (implicitBit - 1U) +#define signBit (REP_C(1) << (significandBits + exponentBits)) +#define absMask (signBit - 1U) +#define exponentMask (absMask ^ significandMask) +#define oneRep ((rep_t)exponentBias << significandBits) +#define infRep exponentMask +#define quietBit (implicitBit >> 1) +#define qnanRep (exponentMask | quietBit) + +static __inline rep_t toRep(fp_t x) { + const union { + fp_t f; + rep_t i; + } rep = {.f = x}; + return rep.i; +} + +static __inline fp_t fromRep(rep_t x) { + const union { + fp_t f; + rep_t i; + } rep = {.i = x}; + return rep.f; +} + +static __inline int normalize(rep_t *significand) { + const int shift = rep_clz(*significand) - rep_clz(implicitBit); + *significand <<= shift; + return 1 - shift; +} + +static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) { + *hi = *hi << count | *lo >> (typeWidth - count); + *lo = *lo << count; +} + +static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, + unsigned int count) { + if (count < typeWidth) { + const bool sticky = (*lo << (typeWidth - count)) != 0; + *lo = *hi << (typeWidth - count) | *lo >> count | sticky; + *hi = *hi >> count; + } else if (count < 2 * typeWidth) { + const bool sticky = *hi << (2 * typeWidth - count) | *lo; + *lo = *hi >> (count - typeWidth) | sticky; + *hi = 0; + } else { + const bool sticky = *hi | *lo; + *lo = sticky; + *hi = 0; + } +} + +// Implements logb methods (logb, logbf, logbl) for IEEE-754. This avoids +// pulling in a libm dependency from compiler-rt, but is not meant to replace +// it (i.e. code calling logb() should get the one from libm, not this), hence +// the __compiler_rt prefix. +static __inline fp_t __compiler_rt_logbX(fp_t x) { + rep_t rep = toRep(x); + int exp = (rep & exponentMask) >> significandBits; + + // Abnormal cases: + // 1) +/- inf returns +inf; NaN returns NaN + // 2) 0.0 returns -inf + if (exp == maxExponent) { + if (((rep & signBit) == 0) || (x != x)) { + return x; // NaN or +inf: return x + } else { + return -x; // -inf: return -x + } + } else if (x == 0.0) { + // 0.0: return -inf + return fromRep(infRep | signBit); + } + + if (exp != 0) { + // Normal number + return exp - exponentBias; // Unbias exponent + } else { + // Subnormal number; normalize and repeat + rep &= absMask; + const int shift = 1 - normalize(&rep); + exp = (rep & exponentMask) >> significandBits; + return exp - exponentBias - shift; // Unbias exponent + } +} +#endif + +#if defined(SINGLE_PRECISION) +static __inline fp_t __compiler_rt_logbf(fp_t x) { + return __compiler_rt_logbX(x); +} +#elif defined(DOUBLE_PRECISION) +static __inline fp_t __compiler_rt_logb(fp_t x) { + return __compiler_rt_logbX(x); +} +#elif defined(QUAD_PRECISION) +#if defined(CRT_LDBL_128BIT) +static __inline fp_t __compiler_rt_logbl(fp_t x) { + return __compiler_rt_logbX(x); +} +#else +// The generic implementation only works for ieee754 floating point. For other +// floating point types, continue to rely on the libm implementation for now. +static __inline long double __compiler_rt_logbl(long double x) { + return crt_logbl(x); +} +#endif +#endif + +#endif // FP_LIB_HEADER diff --git a/lib32/aeabi/int_endianness.h b/lib32/aeabi/int_endianness.h new file mode 100644 index 00000000..def046c3 --- /dev/null +++ b/lib32/aeabi/int_endianness.h @@ -0,0 +1,114 @@ +//===-- int_endianness.h - configuration header for compiler-rt -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a configuration header for compiler-rt. +// This file is not part of the interface of this library. +// +//===----------------------------------------------------------------------===// + +#ifndef INT_ENDIANNESS_H +#define INT_ENDIANNESS_H + +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + defined(__ORDER_LITTLE_ENDIAN__) + +// Clang and GCC provide built-in endianness definitions. +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif // __BYTE_ORDER__ + +#else // Compilers other than Clang or GCC. + +#if defined(__SVR4) && defined(__sun) +#include + +#if defined(_BIG_ENDIAN) +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif defined(_LITTLE_ENDIAN) +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#else // !_LITTLE_ENDIAN +#error "unknown endianness" +#endif // !_LITTLE_ENDIAN + +#endif // Solaris and AuroraUX. + +// .. + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__minix) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif // _BYTE_ORDER + +#endif // *BSD + +#if defined(__OpenBSD__) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif // _BYTE_ORDER + +#endif // OpenBSD + +// .. + +// Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the +// compiler (at least with GCC) +#if defined(__APPLE__) || defined(__ellcc__) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#endif +#endif // __BIG_ENDIAN__ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif +#endif // __LITTLE_ENDIAN__ + +#endif // Mac OSX + +// .. + +#if defined(_WIN32) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif // Windows + +#endif // Clang or GCC. + +// . + +#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) +#error Unable to determine endian +#endif // Check we found an endianness correctly. + +#endif // INT_ENDIANNESS_H diff --git a/lib32/aeabi/int_lib.h b/lib32/aeabi/int_lib.h new file mode 100644 index 00000000..3092f68c --- /dev/null +++ b/lib32/aeabi/int_lib.h @@ -0,0 +1,141 @@ +//===-- int_lib.h - configuration header for compiler-rt -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a configuration header for compiler-rt. +// This file is not part of the interface of this library. +// +//===----------------------------------------------------------------------===// + +#ifndef INT_LIB_H +#define INT_LIB_H + +// Assumption: Signed integral is 2's complement. +// Assumption: Right shift of signed negative is arithmetic shift. +// Assumption: Endianness is little or big (not mixed). + +// ABI macro definitions + +#if __ARM_EABI__ +#ifdef COMPILER_RT_ARMHF_TARGET +#define COMPILER_RT_ABI +#else +#define COMPILER_RT_ABI __attribute__((__pcs__("aapcs"))) +#endif +#else +#define COMPILER_RT_ABI +#endif + +#define AEABI_RTABI __attribute__((__pcs__("aapcs"))) + +#if defined(_MSC_VER) && !defined(__clang__) +#define ALWAYS_INLINE __forceinline +#define NOINLINE __declspec(noinline) +#define NORETURN __declspec(noreturn) +#define UNUSED +#else +#define ALWAYS_INLINE __attribute__((always_inline)) +#define NOINLINE __attribute__((noinline)) +#define NORETURN __attribute__((noreturn)) +#define UNUSED __attribute__((unused)) +#endif + +#define STR(a) #a +#define XSTR(a) STR(a) +#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name + +#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__) +#define COMPILER_RT_ALIAS(name, aliasname) \ + COMPILER_RT_ABI __typeof(name) aliasname __attribute__((__alias__(#name))); +#elif defined(__APPLE__) +#define COMPILER_RT_ALIAS(name, aliasname) \ + __asm__(".globl " SYMBOL_NAME(aliasname)); \ + __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \ + COMPILER_RT_ABI __typeof(name) aliasname; +#elif defined(_WIN32) +#define COMPILER_RT_ALIAS(name, aliasname) +#else +#error Unsupported target +#endif + +#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE)) +// +// Kernel and boot environment can't use normal headers, +// so use the equivalent system headers. +// +#include +#include +#include +#else +// Include the standard compiler builtin headers we use functionality from. +#include +#include +#include +#include +#endif + +// Include the commonly used internal type definitions. +#include "int_types.h" + +// Include internal utility function declarations. +#include "int_util.h" + +COMPILER_RT_ABI si_int __paritysi2(si_int a); +COMPILER_RT_ABI si_int __paritydi2(di_int a); + +COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b); +COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b); +COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d); + +COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem); +COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem); +#ifdef CRT_HAS_128BIT +COMPILER_RT_ABI si_int __clzti2(ti_int a); +COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem); +#endif + +// Definitions for builtins unavailable on MSVC +#if defined(_MSC_VER) && !defined(__clang__) +#include + +uint32_t __inline __builtin_ctz(uint32_t value) { + unsigned long trailing_zero = 0; + if (_BitScanForward(&trailing_zero, value)) + return trailing_zero; + return 32; +} + +uint32_t __inline __builtin_clz(uint32_t value) { + unsigned long leading_zero = 0; + if (_BitScanReverse(&leading_zero, value)) + return 31 - leading_zero; + return 32; +} + +#if defined(_M_ARM) || defined(_M_X64) +uint32_t __inline __builtin_clzll(uint64_t value) { + unsigned long leading_zero = 0; + if (_BitScanReverse64(&leading_zero, value)) + return 63 - leading_zero; + return 64; +} +#else +uint32_t __inline __builtin_clzll(uint64_t value) { + if (value == 0) + return 64; + uint32_t msh = (uint32_t)(value >> 32); + uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF); + if (msh != 0) + return __builtin_clz(msh); + return 32 + __builtin_clz(lsh); +} +#endif + +#define __builtin_clzl __builtin_clzll +#endif // defined(_MSC_VER) && !defined(__clang__) + +#endif // INT_LIB_H diff --git a/lib32/aeabi/int_math.h b/lib32/aeabi/int_math.h new file mode 100644 index 00000000..58d8990f --- /dev/null +++ b/lib32/aeabi/int_math.h @@ -0,0 +1,106 @@ +//===-- int_math.h - internal math inlines --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is not part of the interface of this library. +// +// This file defines substitutes for the libm functions used in some of the +// compiler-rt implementations, defined in such a way that there is not a direct +// dependency on libm or math.h. Instead, we use the compiler builtin versions +// where available. This reduces our dependencies on the system SDK by foisting +// the responsibility onto the compiler. +// +//===----------------------------------------------------------------------===// + +#ifndef INT_MATH_H +#define INT_MATH_H + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#include +#include +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define CRT_INFINITY INFINITY +#else +#define CRT_INFINITY __builtin_huge_valf() +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define crt_isfinite(x) _finite((x)) +#define crt_isinf(x) !_finite((x)) +#define crt_isnan(x) _isnan((x)) +#else +// Define crt_isfinite in terms of the builtin if available, otherwise provide +// an alternate version in terms of our other functions. This supports some +// versions of GCC which didn't have __builtin_isfinite. +#if __has_builtin(__builtin_isfinite) +#define crt_isfinite(x) __builtin_isfinite((x)) +#elif defined(__GNUC__) +#define crt_isfinite(x) \ + __extension__(({ \ + __typeof((x)) x_ = (x); \ + !crt_isinf(x_) && !crt_isnan(x_); \ + })) +#else +#error "Do not know how to check for infinity" +#endif // __has_builtin(__builtin_isfinite) +#define crt_isinf(x) __builtin_isinf((x)) +#define crt_isnan(x) __builtin_isnan((x)) +#endif // _MSC_VER + +#if defined(_MSC_VER) && !defined(__clang__) +#define crt_copysign(x, y) copysign((x), (y)) +#define crt_copysignf(x, y) copysignf((x), (y)) +#define crt_copysignl(x, y) copysignl((x), (y)) +#else +#define crt_copysign(x, y) __builtin_copysign((x), (y)) +#define crt_copysignf(x, y) __builtin_copysignf((x), (y)) +#define crt_copysignl(x, y) __builtin_copysignl((x), (y)) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define crt_fabs(x) fabs((x)) +#define crt_fabsf(x) fabsf((x)) +#define crt_fabsl(x) fabs((x)) +#else +#define crt_fabs(x) __builtin_fabs((x)) +#define crt_fabsf(x) __builtin_fabsf((x)) +#define crt_fabsl(x) __builtin_fabsl((x)) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define crt_fmax(x, y) __max((x), (y)) +#define crt_fmaxf(x, y) __max((x), (y)) +#define crt_fmaxl(x, y) __max((x), (y)) +#else +#define crt_fmax(x, y) __builtin_fmax((x), (y)) +#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y)) +#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y)) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define crt_logbl(x) logbl((x)) +#else +#define crt_logbl(x) __builtin_logbl((x)) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define crt_scalbn(x, y) scalbn((x), (y)) +#define crt_scalbnf(x, y) scalbnf((x), (y)) +#define crt_scalbnl(x, y) scalbnl((x), (y)) +#else +#define crt_scalbn(x, y) __builtin_scalbn((x), (y)) +#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y)) +#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y)) +#endif + +#endif // INT_MATH_H diff --git a/lib32/aeabi/int_types.h b/lib32/aeabi/int_types.h new file mode 100644 index 00000000..f89220d5 --- /dev/null +++ b/lib32/aeabi/int_types.h @@ -0,0 +1,174 @@ +//===-- int_lib.h - configuration header for compiler-rt -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is not part of the interface of this library. +// +// This file defines various standard types, most importantly a number of unions +// used to access parts of larger types. +// +//===----------------------------------------------------------------------===// + +#ifndef INT_TYPES_H +#define INT_TYPES_H + +#include "int_endianness.h" + +// si_int is defined in Linux sysroot's asm-generic/siginfo.h +#ifdef si_int +#undef si_int +#endif +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +typedef union { + di_int all; + struct { +#if _YUGA_LITTLE_ENDIAN + su_int low; + si_int high; +#else + si_int high; + su_int low; +#endif // _YUGA_LITTLE_ENDIAN + } s; +} dwords; + +typedef union { + du_int all; + struct { +#if _YUGA_LITTLE_ENDIAN + su_int low; + su_int high; +#else + su_int high; + su_int low; +#endif // _YUGA_LITTLE_ENDIAN + } s; +} udwords; + +#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) || \ + defined(__riscv) || defined(_WIN64) +#define CRT_HAS_128BIT +#endif + +// MSVC doesn't have a working 128bit integer type. Users should really compile +// compiler-rt with clang, but if they happen to be doing a standalone build for +// asan or something else, disable the 128 bit parts so things sort of work. +#if defined(_MSC_VER) && !defined(__clang__) +#undef CRT_HAS_128BIT +#endif + +#ifdef CRT_HAS_128BIT +typedef int ti_int __attribute__((mode(TI))); +typedef unsigned tu_int __attribute__((mode(TI))); + +typedef union { + ti_int all; + struct { +#if _YUGA_LITTLE_ENDIAN + du_int low; + di_int high; +#else + di_int high; + du_int low; +#endif // _YUGA_LITTLE_ENDIAN + } s; +} twords; + +typedef union { + tu_int all; + struct { +#if _YUGA_LITTLE_ENDIAN + du_int low; + du_int high; +#else + du_int high; + du_int low; +#endif // _YUGA_LITTLE_ENDIAN + } s; +} utwords; + +static __inline ti_int make_ti(di_int h, di_int l) { + twords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +static __inline tu_int make_tu(du_int h, du_int l) { + utwords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +#endif // CRT_HAS_128BIT + +typedef union { + su_int u; + float f; +} float_bits; + +typedef union { + udwords u; + double f; +} double_bits; + +typedef struct { +#if _YUGA_LITTLE_ENDIAN + udwords low; + udwords high; +#else + udwords high; + udwords low; +#endif // _YUGA_LITTLE_ENDIAN +} uqwords; + +// Check if the target supports 80 bit extended precision long doubles. +// Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC +// still makes it 80 bits. Clang will match whatever compiler it is trying to +// be compatible with. +#if ((defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)) || \ + defined(__m68k__) || defined(__ia64__) +#define HAS_80_BIT_LONG_DOUBLE 1 +#else +#define HAS_80_BIT_LONG_DOUBLE 0 +#endif + +typedef union { + uqwords u; + long double f; +} long_double_bits; + +#if __STDC_VERSION__ >= 199901L +typedef float _Complex Fcomplex; +typedef double _Complex Dcomplex; +typedef long double _Complex Lcomplex; + +#define COMPLEX_REAL(x) __real__(x) +#define COMPLEX_IMAGINARY(x) __imag__(x) +#else +typedef struct { + float real, imaginary; +} Fcomplex; + +typedef struct { + double real, imaginary; +} Dcomplex; + +typedef struct { + long double real, imaginary; +} Lcomplex; + +#define COMPLEX_REAL(x) (x).real +#define COMPLEX_IMAGINARY(x) (x).imaginary +#endif +#endif // INT_TYPES_H diff --git a/lib32/aeabi/int_util.h b/lib32/aeabi/int_util.h new file mode 100644 index 00000000..5fbdfb57 --- /dev/null +++ b/lib32/aeabi/int_util.h @@ -0,0 +1,31 @@ +//===-- int_util.h - internal utility functions ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is not part of the interface of this library. +// +// This file defines non-inline utilities which are available for use in the +// library. The function definitions themselves are all contained in int_util.c +// which will always be compiled into any compiler-rt library. +// +//===----------------------------------------------------------------------===// + +#ifndef INT_UTIL_H +#define INT_UTIL_H + +/// \brief Trigger a program abort (or panic for kernel code). +#define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__) + +NORETURN void __compilerrt_abort_impl(const char *file, int line, + const char *function); + +#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__) +#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt) +#define COMPILE_TIME_ASSERT2(expr, cnt) \ + typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED + +#endif // INT_UTIL_H diff --git a/lib32/aeabi/tp_read.c b/lib32/aeabi/tp_read.c new file mode 100644 index 00000000..53cc40db --- /dev/null +++ b/lib32/aeabi/tp_read.c @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2020, Takayuki Imada + */ + +unsigned __aeabi_read_tp(void); + +unsigned __aeabi_read_tp(void) +{ + unsigned ret = 0x0U; + __asm__ __volatile__("mrc p15, 0, %0, c13, c0, 2" :"=r"(ret)::); + + return ret; +} diff --git a/lib32/aeabi/udivmoddi4.c b/lib32/aeabi/udivmoddi4.c new file mode 100644 index 00000000..5b297c32 --- /dev/null +++ b/lib32/aeabi/udivmoddi4.c @@ -0,0 +1,200 @@ +//===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __udivmoddi4 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Effects: if rem != 0, *rem = a % b +// Returns: a / b + +// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide + +#if defined(_MSC_VER) && !defined(__clang__) +// MSVC throws a warning about mod 0 here, disable it for builds that +// warn-as-error +#pragma warning(push) +#pragma warning(disable : 4724) +#endif + +COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) { + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + // special cases, X is unknown, K != 0 + if (n.s.high == 0) { + if (d.s.high == 0) { + // 0 X + // --- + // 0 X + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + // 0 X + // --- + // K X + if (rem) + *rem = n.s.low; + return 0; + } + // n.s.high != 0 + if (d.s.low == 0) { + if (d.s.high == 0) { + // K X + // --- + // 0 0 + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + // d.s.high != 0 + if (n.s.low == 0) { + // K 0 + // --- + // K 0 + if (rem) { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + // K K + // --- + // K 0 + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ { + if (rem) { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + // K K + // --- + // K 0 + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + // 0 <= sr <= n_uword_bits - 2 or sr large + if (sr > n_uword_bits - 2) { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + // 1 <= sr <= n_uword_bits - 1 + // q.all = n.all << (n_udword_bits - sr); + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + // r.all = n.all >> sr; + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } else /* d.s.low != 0 */ { + if (d.s.high == 0) { + // K X + // --- + // 0 K + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + // K X + // --- + // 0 K + sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + // 2 <= sr <= n_udword_bits - 1 + // q.all = n.all << (n_udword_bits - sr); + // r.all = n.all >> sr; + if (sr == n_uword_bits) { + q.s.low = 0; + q.s.high = n.s.low; + r.s.high = 0; + r.s.low = n.s.high; + } else if (sr < n_uword_bits) /* 2 <= sr <= n_uword_bits - 1 */ { + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } else /* n_uword_bits + 1 <= sr <= n_udword_bits - 1 */ { + q.s.low = n.s.low << (n_udword_bits - sr); + q.s.high = (n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits)); + r.s.high = 0; + r.s.low = n.s.high >> (sr - n_uword_bits); + } + } else { + // K X + // --- + // K K + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + // 0 <= sr <= n_uword_bits - 1 or sr large + if (sr > n_uword_bits - 1) { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + // 1 <= sr <= n_uword_bits + // q.all = n.all << (n_udword_bits - sr); + q.s.low = 0; + if (sr == n_uword_bits) { + q.s.high = n.s.low; + r.s.high = 0; + r.s.low = n.s.high; + } else { + q.s.high = n.s.low << (n_uword_bits - sr); + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + } + } + // Not a special case + // q and r are initialized with: + // q.all = n.all << (n_udword_bits - sr); + // r.all = n.all >> sr; + // 1 <= sr <= n_udword_bits - 1 + su_int carry = 0; + for (; sr > 0; --sr) { + // r:q = ((r:q) << 1) | carry + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + // carry = 0; + // if (r.all >= d.all) + // { + // r.all -= d.all; + // carry = 1; + // } + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif diff --git a/lib32/aeabi/udivmodsi4.c b/lib32/aeabi/udivmodsi4.c new file mode 100644 index 00000000..753ad6dd --- /dev/null +++ b/lib32/aeabi/udivmodsi4.c @@ -0,0 +1,21 @@ +//===-- udivmodsi4.c - Implement __udivmodsi4 -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __udivmodsi4 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a / b, *rem = a % b + +COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem) { + si_int d = __udivsi3(a, b); + *rem = a - (d * b); + return d; +} diff --git a/lib32/aeabi/udivsi3.c b/lib32/aeabi/udivsi3.c new file mode 100644 index 00000000..18cc96c1 --- /dev/null +++ b/lib32/aeabi/udivsi3.c @@ -0,0 +1,62 @@ +//===-- udivsi3.c - Implement __udivsi3 -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __udivsi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a / b + +// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide + +// This function should not call __divsi3! +COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d) { + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + su_int q; + su_int r; + unsigned sr; + // special cases + if (d == 0) + return 0; // ?! + if (n == 0) + return 0; + sr = __builtin_clz(d) - __builtin_clz(n); + // 0 <= sr <= n_uword_bits - 1 or sr large + if (sr > n_uword_bits - 1) // d > r + return 0; + if (sr == n_uword_bits - 1) // d == 1 + return n; + ++sr; + // 1 <= sr <= n_uword_bits - 1 + // Not a special case + q = n << (n_uword_bits - sr); + r = n >> sr; + su_int carry = 0; + for (; sr > 0; --sr) { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (n_uword_bits - 1)); + q = (q << 1) | carry; + // carry = 0; + // if (r.all >= d.all) + // { + // r.all -= d.all; + // carry = 1; + // } + const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1); + carry = s & 1; + r -= d & s; + } + q = (q << 1) | carry; + return q; +} + +#if defined(__ARM_EABI__) +COMPILER_RT_ALIAS(__udivsi3, __aeabi_uidiv) +#endif From 367270f1ac4b77b4ae56d6fd9583c6a3370a29f1 Mon Sep 17 00:00:00 2001 From: TImada Date: Tue, 9 Jun 2020 23:54:17 +0900 Subject: [PATCH 2/8] spt binding: Added aarch32 support --- bindings/GNUmakefile | 11 +- bindings/bindings.h | 13 +++ bindings/cpu_arm.h | 77 +++++++++++++ bindings/crt.c | 6 + bindings/crt_init.h | 2 + bindings/mem32.c | 83 ++++++++++++++ bindings/{mem.c => mem64.c} | 0 bindings/spt/bindings.h | 10 +- bindings/spt/net.c | 7 ++ bindings/spt/platform.c | 14 ++- bindings/spt/sys_linux_aarch64.c | 4 +- bindings/spt/sys_linux_arm.c | 185 +++++++++++++++++++++++++++++++ bindings/spt/sys_linux_ppc64le.c | 2 +- bindings/spt/sys_linux_x86_64.c | 4 +- 14 files changed, 407 insertions(+), 11 deletions(-) create mode 100644 bindings/cpu_arm.h create mode 100644 bindings/mem32.c rename bindings/{mem.c => mem64.c} (100%) create mode 100644 bindings/spt/sys_linux_arm.c diff --git a/bindings/GNUmakefile b/bindings/GNUmakefile index 147c245c..977abe78 100644 --- a/bindings/GNUmakefile +++ b/bindings/GNUmakefile @@ -41,9 +41,14 @@ hvt_SRCS := hvt/start.c $(common_SRCS) $(common_hvt_SRCS) \ hvt/platform_lifecycle.c hvt/yield.c hvt/tscclock.c hvt/console.c \ hvt/net.c hvt/block.c -spt_SRCS := spt/start.c \ - abort.c crt.c printf.c lib.c mem.c exit.c log.c cmdline.c tls.c mft.c \ - spt/bindings.c spt/block.c spt/net.c spt/platform.c \ +ifeq ($(CONFIG_BITS), __BITS_32__) +spt_SRCS := mem32.c +else ifeq ($(CONFIG_BITS), __BITS_64__) +spt_SRCS := mem64.c +endif +spt_SRCS += spt/start.c \ + abort.c crt.c printf.c lib.c exit.c log.c cmdline.c tls.c \ + mft.c spt/bindings.c spt/block.c spt/net.c spt/platform.c \ spt/sys_linux_$(CONFIG_ARCH).c virtio_SRCS := virtio/boot.S virtio/start.c $(common_SRCS) \ diff --git a/bindings/bindings.h b/bindings/bindings.h index 0e4d0208..28c239fa 100644 --- a/bindings/bindings.h +++ b/bindings/bindings.h @@ -41,6 +41,8 @@ #include "cpu_x86_64.h" #elif defined(__aarch64__) #include "cpu_aarch64.h" +#elif defined(__arm__) +#include "cpu_arm.h" #elif defined(__powerpc64__) #include "cpu_ppc64.h" #else @@ -91,7 +93,13 @@ extern int cpu_intr_depth; /* intr.c: interrupt handling */ void intr_register_irq(unsigned irq, int (*handler)(void *), void *arg); +#if defined(__BITS_32__) +void intr_irq_handler(uint32_t irq); +#elif defined(__BITS_64__) void intr_irq_handler(uint64_t irq); +#else +#error Unsupported architecture bits +#endif /* mem.c: low-level page alloc routines */ void mem_init(void); @@ -118,7 +126,12 @@ const char *platform_cmdline(void); uint64_t platform_mem_size(void); void platform_exit(int status, void *cookie) __attribute__((noreturn)); int platform_puts(const char *buf, int n); + +#if defined(__BITS_32__) +int platform_set_tls_base(uint32_t base); +#else int platform_set_tls_base(uint64_t base); +#endif /* platform_intr.c: platform-specific interrupt handling */ void platform_intr_init(void); diff --git a/bindings/cpu_arm.h b/bindings/cpu_arm.h new file mode 100644 index 00000000..7774c116 --- /dev/null +++ b/bindings/cpu_arm.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015-2019 Contributors as noted in the AUTHORS file + * + * This file is part of Solo5, a sandboxed execution environment. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __CPU_ARM_H__ +#define __CPU_ARM_H__ + +/* memory defines */ +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 +#define PAGE_MASK ~(0xfff) + +#ifndef _BITUL + +#ifdef ASM_FILE +#define _AC(X,Y) X +#define _AT(T,X) X +#else +#define __AC(X,Y) (X##Y) +#define _AC(X,Y) __AC(X,Y) +#define _AT(T,X) ((T)(X)) +#endif + +#define _BITUL(x) (_AC(1,UL) << (x)) +#define _BITULL(x) (_AC(1,ULL) << (x)) + +#endif + +#define ESR_EC_IABT_LOW _AC(0x20, UL) +#define ESR_EC_IABT_CUR _AC(0x21, UL) +#define ESR_EC_DABT_LOW _AC(0x24, UL) +#define ESR_EC_DABT_CUR _AC(0x25, UL) + +#define ESR_EC_SHIFT _AC(26, UL) +#define ESR_EC_MASK (_AC(0x3F, UL) << ESR_EC_SHIFT) +#define ESR_EC(esr) (((esr) & ESR_EC_MASK) >> ESR_EC_SHIFT) + +#ifndef ASM_FILE + +/* + * The remainder of this file is used only from C. + */ +static inline uint64_t cpu_cntvct(void) +{ + uint32_t hi, lo; + + __asm__ __volatile__("mrrc p15, 1, %0, %1, c14" : "=r" (lo), "=r" (hi)); + return ((uint64_t) hi << 32) | lo; +} + +static inline uint64_t mul64_32(uint64_t a, uint32_t b, uint8_t s) +{ + return (a * b) >> s; +} +#endif /* !ASM_FILE */ + +static inline void cpu_set_tls_base(uint32_t base) +{ + __asm__ __volatile__("mcr p15, 0, %0, c13, c0, 2" :: "r"(base)); +} + +#endif /* __CPU_ARM_H__ */ diff --git a/bindings/crt.c b/bindings/crt.c index 45819286..01f6371c 100644 --- a/bindings/crt.c +++ b/bindings/crt.c @@ -25,7 +25,13 @@ * crt_init_early(), keep an easily recognisable "terminator" value here to * flag if that did not happen as expected. */ +#if (__BITS_32__) +uintptr_t SSP_GUARD = 0xdeadbeef; +#elif (__BITS_64__) uintptr_t SSP_GUARD = 0x00deadbeef0d0a00; +#else +#error Unsupported architecture bits +#endif /* * Called by compiler-generated code when corruption of the canary value is diff --git a/bindings/crt_init.h b/bindings/crt_init.h index e242f96c..b7f5da6a 100644 --- a/bindings/crt_init.h +++ b/bindings/crt_init.h @@ -24,6 +24,8 @@ extern uintptr_t SSP_GUARD; #define READ_CPU_TICKS cpu_rdtsc #elif defined(__aarch64__) #define READ_CPU_TICKS cpu_cntvct +#elif defined(__arm__) +#define READ_CPU_TICKS cpu_cntvct #elif defined(__powerpc64__) #define READ_CPU_TICKS cpu_cntvct #else diff --git a/bindings/mem32.c b/bindings/mem32.c new file mode 100644 index 00000000..cc6c3a76 --- /dev/null +++ b/bindings/mem32.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015-2019 Contributors as noted in the AUTHORS file + * + * This file is part of Solo5, a sandboxed execution environment. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "bindings.h" + +static uint32_t heap_start; + +/* + * Locks the memory layout (by disabling mem_ialloc_pages()). Must be called + * before passing control to the application via solo5_app_main(). + * + * Returns the first usable memory address for application heap in (*start) + * and the size of the heap in (*size). + */ +static int mem_locked = 0; +void mem_lock_heap(uintptr_t *start, size_t *size) +{ + assert(!mem_locked); + + mem_locked = 1; + *start = heap_start; + *size = platform_mem_size() - heap_start; +} + +void mem_init(void) +{ + extern char _stext[], _etext[], _erodata[], _end[]; + uint32_t mem_size; + + mem_size = platform_mem_size(); + heap_start = ((uint32_t)&_end + PAGE_SIZE - 1) & PAGE_MASK; + + /* + * Cowardly refuse to run with less than 512KB of free memory. + */ + if (heap_start + 0x80000 > mem_size) + PANIC("Not enough memory", NULL); + + log(INFO, "Solo5: Memory map: %lu MB addressable:\n", + (unsigned long)mem_size >> 20); + log(INFO, "Solo5: reserved @ (0x0 - 0x%lx)\n", + (unsigned long)_stext-1); + log(INFO, "Solo5: text @ (0x%lx - 0x%lx)\n", + (unsigned long)_stext, (unsigned long)_etext-1); + log(INFO, "Solo5: rodata @ (0x%lx - 0x%lx)\n", + (unsigned long)_etext, (unsigned long)_erodata-1); + log(INFO, "Solo5: data @ (0x%lx - 0x%lx)\n", + (unsigned long)_erodata, (unsigned long)_end-1); + log(INFO, "Solo5: heap >= 0x%lx < stack < 0x%lx\n", + (unsigned long)heap_start, (unsigned long)mem_size); +} + +/* + * Allocate pages on the heap. Should only be called on + * initialization (before solo5_app_main). + */ +void *mem_ialloc_pages(size_t num) +{ + assert(!mem_locked); + + uint32_t prev = heap_start; + heap_start += num << PAGE_SHIFT; + assert(heap_start < (uint32_t)&prev); + + return (void *)prev; +} diff --git a/bindings/mem.c b/bindings/mem64.c similarity index 100% rename from bindings/mem.c rename to bindings/mem64.c diff --git a/bindings/spt/bindings.h b/bindings/spt/bindings.h index c65d0062..37f6f378 100644 --- a/bindings/spt/bindings.h +++ b/bindings/spt/bindings.h @@ -35,13 +35,19 @@ long sys_read(long fd, void *buf, long size); long sys_write(long fd, const void *buf, long size); -long sys_pread64(long fd, void *buf, long size, long pos); -long sys_pwrite64(long fd, const void *buf, long size, long pos); +long sys_pread64(long fd, void *buf, long size, solo5_off_t pos); +long sys_pwrite64(long fd, const void *buf, long size, solo5_off_t pos); void sys_exit_group(long status) __attribute__((noreturn)); struct sys_timespec { +#if defined(__BITS_32__) + uint32_t tv_sec; +#elif defined(__BITS_64__) uint64_t tv_sec; +#else +#error Unsupported architecture bits +#endif long tv_nsec; }; diff --git a/bindings/spt/net.c b/bindings/spt/net.c index 707810fa..56ecc444 100644 --- a/bindings/spt/net.c +++ b/bindings/spt/net.c @@ -102,8 +102,15 @@ void solo5_yield(solo5_time_t deadline, solo5_handle_set_t *ready_set) struct sys_itimerspec it = { .it_interval = { 0 }, .it_value = { +#if defined(__BITS_32__) + .tv_sec = (uint32_t)(deadline / 1000000000ULL), + .tv_nsec = (long)(deadline % 1000000000ULL) +#elif defined(__BITS_64__) .tv_sec = deadline / 1000000000ULL, .tv_nsec = deadline % 1000000000ULL +#else +#error Unsupported architecture bits +#endif } }; /* diff --git a/bindings/spt/platform.c b/bindings/spt/platform.c index 0f1f2e2f..0421ee70 100644 --- a/bindings/spt/platform.c +++ b/bindings/spt/platform.c @@ -21,7 +21,13 @@ #include "bindings.h" static const char *cmdline; +#if defined(__BITS_32__) +static uint32_t mem_size; +#elif defined(__BITS_64__) static uint64_t mem_size; +#else +#error Unsupported architecture bits +#endif void platform_init(const void *arg) { @@ -52,12 +58,18 @@ int platform_puts(const char *buf, int n) return n; } +#if defined(__BITS_32__) +int platform_set_tls_base(uint32_t base) +#elif defined(__BITS_64__) int platform_set_tls_base(uint64_t base) +#else +#error Unsupported architecture bits +#endif { #if defined(__x86_64__) /* In x86 we need to ask the host kernel to change %fs for us. */ return sys_arch_prctl(SYS_ARCH_SET_FS, base); -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(__arm__) cpu_set_tls_base(base); return 0; #elif defined(__powerpc64__) diff --git a/bindings/spt/sys_linux_aarch64.c b/bindings/spt/sys_linux_aarch64.c index 984ee923..858c1123 100644 --- a/bindings/spt/sys_linux_aarch64.c +++ b/bindings/spt/sys_linux_aarch64.c @@ -73,7 +73,7 @@ long sys_write(long fd, const void *buf, long size) return x0; } -long sys_pread64(long fd, void *buf, long size, long pos) +long sys_pread64(long fd, void *buf, long size, solo5_off_t pos) { register long x8 __asm__("x8") = SYS_pread64; register long x0 __asm__("x0") = fd; @@ -91,7 +91,7 @@ long sys_pread64(long fd, void *buf, long size, long pos) return x0; } -long sys_pwrite64(long fd, const void *buf, long size, long pos) +long sys_pwrite64(long fd, const void *buf, long size, solo5_off_t pos) { register long x8 __asm__("x8") = SYS_pwrite64; register long x0 __asm__("x0") = fd; diff --git a/bindings/spt/sys_linux_arm.c b/bindings/spt/sys_linux_arm.c new file mode 100644 index 00000000..e07197e5 --- /dev/null +++ b/bindings/spt/sys_linux_arm.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015-2019 Contributors as noted in the AUTHORS file + * + * This file is part of Solo5, a sandboxed execution environment. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "bindings.h" + +/* + * The sys_ functions in this file are intentionally weakly typed as they only + * pass through values to/from the system call without interpretation. All + * integer values are passed as (long) and all pointer values are passed as + * (void *). + * + * TODO: This will need to be re-considered for 32-bit archs, and we should + * also consider explicitly inlining these functions. + */ + +#define SYS_read 3 +#define SYS_write 4 +#define SYS_pread64 180 +#define SYS_pwrite64 181 +#define SYS_clock_gettime 263 +#define SYS_exit_group 248 +#define SYS_epoll_pwait 346 +#define SYS_timerfd_settime 353 + +long sys_read(long fd, void *buf, long size) +{ + register long r7 __asm__("r7") = SYS_read; + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = (long)buf; + register long r2 __asm__("r2") = size; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1), "r" (r2) + : "memory", "cc" + ); + + return r0; +} + +long sys_write(long fd, const void *buf, long size) +{ + register long r7 __asm__("r7") = SYS_write; + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = (long)buf; + register long r2 __asm__("r2") = size; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1), "r" (r2) + : "memory", "cc" + ); + + return r0; +} + +long sys_pread64(long fd, void *buf, long size, solo5_off_t pos) +{ + register long r7 __asm__("r7") = SYS_pread64; + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = (long)buf; + register long r2 __asm__("r2") = size; + register long r3 __asm__("r3") = 0; + register long r4 __asm__("r4") = (long)(pos & 0xffffffff); + register long r5 __asm__("r5") = (long)(pos >> 32); + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5) + : "memory", "cc" + ); + + return r0; +} + +long sys_pwrite64(long fd, const void *buf, long size, solo5_off_t pos) +{ + register long r7 __asm__("r7") = SYS_pwrite64; + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = (long)buf; + register long r2 __asm__("r2") = size; + register long r3 __asm__("r3") = 0; + register long r4 __asm__("r4") = (long)(pos & 0xffffffff); + register long r5 __asm__("r5") = (long)(pos >> 32); + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5) + : "memory", "cc" + ); + + return r0; +} + +void sys_exit_group(long status) +{ + register long r7 __asm__("r7") = SYS_exit_group; + register long r0 __asm__("r0") = status; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0) + : "memory", "cc" + ); + + for(;;); +} + +long sys_clock_gettime(const long which, void *ts) +{ + register long r7 __asm__("r7") = SYS_clock_gettime; + register long r0 __asm__("r0") = which; + register long r1 __asm__("r1") = (long)ts; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1) + : "memory", "cc" + ); + + return r0; +} + +long sys_epoll_pwait(long epfd, void *events, long maxevents, long timeout, + void *sigmask, long sigsetsize) +{ + register long r7 __asm__("r7") = SYS_epoll_pwait; + register long r0 __asm__("r0") = epfd; + register long r1 __asm__("r1") = (long)events; + register long r2 __asm__("r2") = maxevents; + register long r3 __asm__("r3") = timeout; + register long r4 __asm__("r4") = (long)sigmask; + register long r5 __asm__("r5") = sigsetsize; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), + "r" (r5) + : "memory", "cc" + ); + + return r0; +} + +long sys_timerfd_settime(long fd, long flags, const void *utmr, void *otmr) +{ + register long r7 __asm__("r7") = SYS_timerfd_settime; + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = flags; + register long r2 __asm__("r2") = (long)utmr; + register long r3 __asm__("r3") = (long)otmr; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) + : "r" (r7), "r" (r0), "r" (r1), "r" (r2), "r" (r3) + : "memory", "cc" + ); + + return r0; +} diff --git a/bindings/spt/sys_linux_ppc64le.c b/bindings/spt/sys_linux_ppc64le.c index 358fd3f2..d9bc7381 100644 --- a/bindings/spt/sys_linux_ppc64le.c +++ b/bindings/spt/sys_linux_ppc64le.c @@ -78,7 +78,7 @@ long sys_write(long fd, const void *buf, long size) return r3; } -long sys_pread64(long fd, void *buf, long size, long pos) +long sys_pread64(long fd, void *buf, long size, solo5_off_t pos) { register long r0 __asm__("r0") = SYS_pread64; register long r3 __asm__("r3") = fd; diff --git a/bindings/spt/sys_linux_x86_64.c b/bindings/spt/sys_linux_x86_64.c index 53287775..5e67a474 100644 --- a/bindings/spt/sys_linux_x86_64.c +++ b/bindings/spt/sys_linux_x86_64.c @@ -68,7 +68,7 @@ long sys_write(long fd, const void *buf, long size) return ret; } -long sys_pread64(long fd, void *buf, long size, long pos) +long sys_pread64(long fd, void *buf, long size, solo5_off_t pos) { long ret; register long r10 __asm__("r10") = pos; @@ -83,7 +83,7 @@ long sys_pread64(long fd, void *buf, long size, long pos) return ret; } -long sys_pwrite64(long fd, const void *buf, long size, long pos) +long sys_pwrite64(long fd, const void *buf, long size, solo5_off_t pos) { long ret; register long r10 __asm__("r10") = pos; From 919d27f6e7cd7c5f3990b769a4b6ee2e98d6e325 Mon Sep 17 00:00:00 2001 From: TImada Date: Tue, 9 Jun 2020 23:55:57 +0900 Subject: [PATCH 3/8] spt tender: Added aarch32 support --- Makefile.common | 5 +- elftool/elftool.c | 8 +- tenders/GNUmakefile | 14 +- tenders/common/elf.h | 10 +- tenders/common/elf32.c | 500 ++++++++++++++++++++++++++++++ tenders/common/{elf.c => elf64.c} | 4 +- tenders/common/types.h | 35 +++ tenders/spt/spt.h | 17 +- tenders/spt/spt_core.c | 42 ++- tenders/spt/spt_launch_arm.S | 34 ++ tenders/spt/spt_main.c | 3 +- 11 files changed, 640 insertions(+), 32 deletions(-) create mode 100644 tenders/common/elf32.c rename tenders/common/{elf.c => elf64.c} (99%) create mode 100644 tenders/common/types.h create mode 100644 tenders/spt/spt_launch_arm.S diff --git a/Makefile.common b/Makefile.common index 5ccc2ea2..f779dd6e 100644 --- a/Makefile.common +++ b/Makefile.common @@ -72,7 +72,7 @@ HOSTAR := ar define HOSTCOMPILE.c @echo "HOSTCC $<" - $(HOSTCC) $(DEPFLAGS) $(HOSTCFLAGS) $(HOSTCPPFLAGS) -c $< -o $@ + $(HOSTCC) $(DEPFLAGS) $(HOSTCFLAGS) $(HOSTCPPFLAGS) -D$(CONFIG_BITS) -c $< -o $@ mv -f $*.Td $*.d && touch $@ endef @@ -82,8 +82,9 @@ define HOSTCOMPILE.S mv -f $*.Td $*.d && touch $@ endef +# @echo "HOSTLINK $@" define HOSTLINK - @echo "HOSTLINK $@" + @echo "$(HOSTCC) $(HOSTLDFLAGS) $^ $(HOSTLDLIBS) -o $@" $(HOSTCC) $(HOSTLDFLAGS) $^ $(HOSTLDLIBS) -o $@ endef diff --git a/elftool/elftool.c b/elftool/elftool.c index 260e1a1e..2b5c96d2 100644 --- a/elftool/elftool.c +++ b/elftool/elftool.c @@ -47,7 +47,13 @@ * code directly to simplify the build. */ #include "../tenders/common/mft.c" -#include "../tenders/common/elf.c" +#if defined(__BITS_32__) +#include "../tenders/common/elf32.c" +#elif defined(__BITS_64__) +#include "../tenders/common/elf64.c" +#else +#error "Unsupported architecture bits" +#endif static const char *jtypestr(enum jtypes t) { diff --git a/tenders/GNUmakefile b/tenders/GNUmakefile index ff8ac6dd..746e41a6 100644 --- a/tenders/GNUmakefile +++ b/tenders/GNUmakefile @@ -31,7 +31,12 @@ $(V).SILENT: ifneq ($(filter 1,$(CONFIG_HVT) $(CONFIG_SPT)),) common_LIB := common/libcommon.a -common_SRCS := common/elf.c common/mft.c common/block_attach.c \ +ifeq ($(CONFIG_BITS), __BITS_32__) +common_SRCS := common/elf32.c +else ifeq ($(CONFIG_BITS), __BITS_64__) +common_SRCS := common/elf64.c +endif +common_SRCS += common/mft.c common/block_attach.c \ common/tap_attach.c common_OBJS := $(patsubst %.c,%.o,$(common_SRCS)) @@ -92,7 +97,12 @@ endif # CONFIG_HVT ifdef CONFIG_SPT +ifeq ($(CONFIG_BITS), __BITS_32__) +# TODO: 1GB size good enough for 32-bit arch? +HOSTLDFLAGS += -Wl,-z -Wl,noexecstack -Wl,-Ttext-segment=0x40000000 +else ifeq ($(CONFIG_BITS), __BITS_64__) HOSTLDFLAGS += -Wl,-z -Wl,noexecstack +endif ifdef CONFIG_SPT_NO_PIE @@ -100,7 +110,7 @@ HOSTLDFLAGS += -Wl,-Ttext-segment=0x40000000 endif -HOSTCFLAGS += $(MAKECONF_SPT_CFLAGS) +HOSTCFLAGS += $(MAKECONF_SPT_CFLAGS) -D$(CONFIG_BITS) -g HOSTLDLIBS += $(MAKECONF_SPT_LDLIBS) spt_SRCS := spt/spt_main.c spt/spt_core.c spt/spt_launch_$(CONFIG_ARCH).S \ diff --git a/tenders/common/elf.h b/tenders/common/elf.h index f4f7962b..9d7ffc7b 100644 --- a/tenders/common/elf.h +++ b/tenders/common/elf.h @@ -25,6 +25,8 @@ #ifndef COMMON_ELF_H #define COMMON_ELF_H +#include "types.h" + /* * guest_mprotect_fn() is called by the ELF loader to request that the page * protection flags (prot) as used by the system mprotect(), i.e. PROT_X from @@ -33,8 +35,8 @@ * * Returns 0 on success, -1 and errno set on failure. */ -typedef int (*guest_mprotect_fn_t)(void *t_arg, uint64_t addr_start, - uint64_t addr_end, int prot); +typedef int (*guest_mprotect_fn_t)(void *t_arg, addr_t addr_start, + addr_t addr_end, int prot); /* * Load an ELF binary from (bin_fd) into (mem_size) bytes of memory at (*mem). @@ -50,8 +52,8 @@ typedef int (*guest_mprotect_fn_t)(void *t_arg, uint64_t addr_start, * terminates the program. */ void elf_load(int bin_fd, const char *bin_name, uint8_t *mem, size_t mem_size, - uint64_t p_min_loadaddr, guest_mprotect_fn_t t_guest_mprotect, - void *t_guest_mprotect_arg, uint64_t *p_entry, uint64_t *p_end); + addr_t p_min_loadaddr, guest_mprotect_fn_t t_guest_mprotect, + void *t_guest_mprotect_arg, addr_t *p_entry, addr_t *p_end); /* * Load the Solo5-owned NOTE of (note_type) from the ELF binary (file). diff --git a/tenders/common/elf32.c b/tenders/common/elf32.c new file mode 100644 index 00000000..0ca180a8 --- /dev/null +++ b/tenders/common/elf32.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2015-2020 Contributors as noted in the AUTHORS file + * + * This file is part of Solo5, a sandboxed execution environment. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * elf.c: ELF loader. + * + * This module should be kept backend-independent and architectural + * dependencies should be self-contained. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cc.h" +#include "elf.h" + +/* + * Define EM_TARGET, EM_PAGE_SIZE and EI_DATA_TARGET for the architecture we + * are compiling on. + */ +#if defined(__arm__) +#define EM_TARGET EM_ARM +#define EM_PAGE_SIZE 0x1000 +#else +#error Unsupported target architecture +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define EI_DATA_TARGET ELFDATA2LSB +#else +#define EI_DATA_TARGET ELFDATA2MSB +#endif + +/* + * Solo5-owned ELF notes are identified by an n_name of "Solo5". + */ +#define SOLO5_NOTE_NAME "Solo5" + +/* + * Defines an Elf32_Nhdr with n_name filled in and padded to a 4-byte boundary, + * i.e. the common part of a Solo5-owned Nhdr. + */ +struct solo5_nhdr { + Elf32_Nhdr h; + char n_name[(sizeof(SOLO5_NOTE_NAME) + 3) & -4]; + /* + * Note content ("descriptor" in ELF terms) follows in the file here, + * possibly with some internal alignment before the first struct member + * (see below). + */ +}; + +_Static_assert((sizeof(struct solo5_nhdr)) == + (sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + 8), + "struct solo5_nhdr alignment issue"); + +static ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset) +{ + ssize_t total = 0; + char *p = buf; + + if (count > SSIZE_MAX) { + errno = E2BIG; + return -1; + } + + while (count > 0) { + ssize_t nr; + + nr = pread(fd, p, count, offset); + if (nr == 0) + return total; + else if (nr == -1 && errno == EINTR) + continue; + else if (nr == -1) + return -1; + + count -= nr; + total += nr; + p += nr; + offset += nr; + } + + return total; +} + +static bool ehdr_is_valid(const Elf32_Ehdr *hdr) +{ + /* + * 1. Validate that this is an ELF32 header we support. + * + * Note: e_ident[EI_OSABI] and e_ident[EI_ABIVERSION] are deliberately NOT + * checked as compilers do not provide a way to override this without + * building the entire toolchain from scratch. + */ + if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 + && hdr->e_ident[EI_MAG1] == ELFMAG1 + && hdr->e_ident[EI_MAG2] == ELFMAG2 + && hdr->e_ident[EI_MAG3] == ELFMAG3 + && hdr->e_ident[EI_CLASS] == ELFCLASS32 + && hdr->e_ident[EI_DATA] == EI_DATA_TARGET + && hdr->e_version == EV_CURRENT)) + return false; + /* + * 2. Validate ELF32 header internal sizes match what we expect, and that + * at least one program header entry is present. + */ + if (hdr->e_ehsize != sizeof (Elf32_Ehdr)) + return false; + if (hdr->e_phnum < 1) + return false; + if (hdr->e_phentsize != sizeof (Elf32_Phdr)) + return false; + /* + * 3. Validate that this is an executable for our target architecture. + */ + if (hdr->e_type != ET_EXEC) + return false; + if (hdr->e_machine != EM_TARGET) + return false; + + return true; +} + +/* + * Align (addr) down to (align) boundary. Returns 1 if (align) is not a + * non-zero power of 2. + */ +static int align_down(Elf32_Addr addr, Elf32_Xword align, + Elf32_Addr *out_result) +{ + if (align > 0 && (align & (align - 1)) == 0) { + *out_result = addr & -align; + return 0; + } + else + return 1; +} + +/* + * Align (addr) up to (align) boundary. Returns 1 if an overflow would occur or + * (align) is not a non-zero power of 2, otherwise result in (*out_result) and + * 0. + */ +static int align_up(Elf32_Addr addr, Elf32_Xword align, Elf32_Addr *out_result) +{ + Elf32_Addr result; + + if (align > 0 && (align & (align - 1)) == 0) { + if (add_overflow(addr, (align - 1), result)) + return 1; + result = result & -align; + *out_result = result; + return 0; + } + else + return 1; +} + +void elf_load(int bin_fd, const char *bin_name, uint8_t *mem, size_t mem_size, + addr_t p_min_loadaddr, guest_mprotect_fn_t t_guest_mprotect, + void *t_guest_mprotect_arg, addr_t *p_entry, addr_t *p_end) +{ + ssize_t nbytes; + Elf32_Phdr *phdr = NULL; + Elf32_Ehdr *ehdr = NULL; + Elf32_Addr e_entry; /* Program entry point */ + Elf32_Addr e_end; /* Highest memory address occupied */ + + ehdr = malloc(sizeof(Elf32_Ehdr)); + if (ehdr == NULL) + goto out_error; + nbytes = pread_in_full(bin_fd, ehdr, sizeof(Elf32_Ehdr), 0); + if (nbytes < 0) + goto out_error; + if (nbytes != sizeof(Elf32_Ehdr)) + goto out_invalid; + if (!ehdr_is_valid(ehdr)) + goto out_invalid; + /* + * e_entry must be non-zero and within range of our memory allocation. + */ + if (ehdr->e_entry < p_min_loadaddr || ehdr->e_entry >= mem_size) + goto out_invalid; + e_entry = ehdr->e_entry; + + size_t ph_size = ehdr->e_phnum * ehdr->e_phentsize; + phdr = malloc(ph_size); + if (!phdr) + goto out_error; + nbytes = pread_in_full(bin_fd, phdr, ph_size, ehdr->e_phoff); + if (nbytes < 0) + goto out_error; + if (nbytes != ph_size) + goto out_invalid; + + /* + * Load all program segments with the PT_LOAD directive. + */ + e_end = 0; + Elf32_Addr plast_vaddr = 0; + for (Elf32_Half ph_i = 0; ph_i < ehdr->e_phnum; ph_i++) { + Elf32_Addr p_vaddr = phdr[ph_i].p_vaddr; + Elf32_Xword p_filesz = phdr[ph_i].p_filesz; + Elf32_Xword p_memsz = phdr[ph_i].p_memsz; + Elf32_Xword p_align = phdr[ph_i].p_align; + Elf32_Addr temp, p_vaddr_start, p_vaddr_end; + + if (phdr[ph_i].p_type != PT_LOAD) + continue; + + if (p_vaddr < p_min_loadaddr) + goto out_invalid; + /* + * The ELF specification mandates that program headers are sorted on + * p_vaddr in ascending order. Enforce this, at the same time avoiding + * any surprises later. + */ + if (p_vaddr < plast_vaddr) + goto out_invalid; + else + plast_vaddr = p_vaddr; + /* + * Compute p_vaddr_start = p_vaddr, aligned down to requested alignment + * and verify result is within range. + */ + if (align_down(p_vaddr, p_align, &p_vaddr_start)) + goto out_invalid; + if (p_vaddr_start < p_min_loadaddr) + goto out_invalid; + /* + * Disallow overlapping segments. This may be overkill, but in practice + * the Solo5 toolchains do not produce such executables. + */ + if (p_vaddr_start < e_end) + goto out_invalid; + /* + * Verify p_vaddr + p_filesz is within range. + */ + if (p_vaddr >= mem_size) + goto out_invalid; + if (add_overflow(p_vaddr, p_filesz, temp)) + goto out_invalid; + if (temp > mem_size) + goto out_invalid; + /* + * Compute p_vaddr_end = p_vaddr + p_memsz, aligned up to requested + * alignment and verify result is within range. + */ + if (p_memsz < p_filesz) + goto out_invalid; + if (add_overflow(p_vaddr, p_memsz, p_vaddr_end)) + goto out_invalid; + if (align_up(p_vaddr_end, p_align, &p_vaddr_end)) + goto out_invalid; + if (p_vaddr_end > mem_size) + goto out_invalid; + /* + * Keep track of the highest byte of memory occupied by the program. + */ + if (p_vaddr_end > e_end) { + e_end = p_vaddr_end; + /* + * Double check result for host (caller) address space overflow. + */ + assert((mem + e_end) >= (mem + p_min_loadaddr)); + } + + /* + * Load the segment (p_vaddr .. p_vaddr + p_filesz) into host memory at + * host_vaddr and ensure any BSS (p_memsz - p_filesz) is initialised to + * zero. + */ + uint8_t *host_vaddr = mem + p_vaddr; + /* + * Double check result for host (caller) address space overflow. + */ + assert(host_vaddr >= (mem + p_min_loadaddr)); + nbytes = pread_in_full(bin_fd, host_vaddr, p_filesz, + phdr[ph_i].p_offset); + if (nbytes < 0) + goto out_error; + if (nbytes != p_filesz) + goto out_invalid; + memset(host_vaddr + p_filesz, 0, p_memsz - p_filesz); + + /* + * Memory protection flags should be applied to the aligned address + * range (p_vaddr_start .. p_vaddr_end). Before we apply them, also + * verify that the address range is aligned to the architectural page + * size. + */ + if (p_vaddr_start & (EM_PAGE_SIZE - 1)) + goto out_invalid; + if (p_vaddr_end & (EM_PAGE_SIZE - 1)) + goto out_invalid; + int prot = PROT_NONE; + if (phdr[ph_i].p_flags & PF_R) + prot |= PROT_READ; + if (phdr[ph_i].p_flags & PF_W) + prot |= PROT_WRITE; + if (phdr[ph_i].p_flags & PF_X) + prot |= PROT_EXEC; + if (prot & PROT_WRITE && prot & PROT_EXEC) { + warnx("%s: Error: phdr[%u] requests WRITE and EXEC permissions", + bin_name, ph_i); + goto out_invalid; + } + assert(t_guest_mprotect != NULL); + if (t_guest_mprotect(t_guest_mprotect_arg, p_vaddr_start, p_vaddr_end, + prot) == -1) + goto out_error; + } + + free(ehdr); + free(phdr); + *p_entry = e_entry; + *p_end = e_end; + return; + +out_error: + warn("%s", bin_name); + free(ehdr); + free(phdr); + exit(1); + +out_invalid: + warnx("%s: Invalid or unsupported executable", bin_name); + free(ehdr); + free(phdr); + exit(1); +} + +int elf_load_note(int bin_fd, const char *bin_name, uint32_t note_type, + size_t note_align, size_t max_note_size, void **out_note_data, + size_t *out_note_size) +{ + ssize_t nbytes; + Elf32_Phdr *phdr = NULL; + Elf32_Ehdr *ehdr = NULL; + uint8_t *note_data = NULL; + size_t note_offset, note_size, note_pad; + + ehdr = malloc(sizeof(Elf32_Ehdr)); + if (ehdr == NULL) + goto out_error; + nbytes = pread_in_full(bin_fd, ehdr, sizeof(Elf32_Ehdr), 0); + if (nbytes < 0) + goto out_error; + if (nbytes != sizeof(Elf32_Ehdr)) + goto out_invalid; + if (!ehdr_is_valid(ehdr)) + goto out_invalid; + + size_t ph_size = ehdr->e_phnum * ehdr->e_phentsize; + phdr = malloc(ph_size); + if (!phdr) + goto out_error; + nbytes = pread_in_full(bin_fd, phdr, ph_size, ehdr->e_phoff); + if (nbytes < 0) + goto out_error; + if (nbytes != ph_size) + goto out_invalid; + + /* + * Find the phdr containing the Solo5 NOTE of type note_type, and sanity + * check its headers. + */ + bool note_found = false; + Elf32_Half ph_i; + struct solo5_nhdr nhdr; + for (ph_i = 0; ph_i < ehdr->e_phnum; ph_i++) { + if (phdr[ph_i].p_type != PT_NOTE) + continue; + if (phdr[ph_i].p_filesz < sizeof (Elf32_Nhdr)) + /* + * p_filesz is less than minimum possible size of a NOTE header, + * reject the executable. + */ + goto out_invalid; + if (phdr[ph_i].p_filesz < sizeof nhdr) + /* + * p_filesz is less than minimum possible size of a Solo5 NOTE + * header, ignore the note. + */ + continue; + nbytes = pread_in_full(bin_fd, &nhdr, sizeof nhdr, + phdr[ph_i].p_offset); + if (nbytes < 0) + goto out_error; + if (nbytes != sizeof nhdr) + goto out_invalid; + if (nhdr.h.n_namesz != sizeof(SOLO5_NOTE_NAME)) + /* + * Not a Solo5-owned NOTE or invalid n_namesz, skip. + */ + continue; + if (strncmp(nhdr.n_name, SOLO5_NOTE_NAME, sizeof(SOLO5_NOTE_NAME)) != 0) + /* + * Not a Solo5-owned NOTE, skip. + */ + continue; + if (nhdr.h.n_type != note_type) + /* + * Not the Solo5 NOTE of note_type we are looking for, skip. + */ + continue; + /* + * Check note descriptor (content) size is within limits, and + * cross-check with p_filesz. + */ + if (nhdr.h.n_descsz < 1 || nhdr.h.n_descsz > max_note_size) + goto out_invalid; + if (phdr[ph_i].p_filesz < sizeof nhdr + nhdr.h.n_descsz) + goto out_invalid; + + note_found = true; + break; + } + if (!note_found) { + free(ehdr); + free(phdr); + return -1; + } + + /* + * At this point we have verified that the NOTE at phdr[ph_i] is the Solo5 + * NOTE with the requested note_type and its file sizes are sane. + * + * Adjust for alignment requested in (note_align) and read the note + * descriptor (content) following the header into dynamically allocated + * memory. + */ + assert(note_align > 0 && (note_align & (note_align - 1)) == 0); + note_offset = (sizeof nhdr + (note_align - 1)) & -note_align; + assert(note_offset >= sizeof nhdr); + note_pad = note_offset - sizeof nhdr; + note_size = nhdr.h.n_descsz - note_pad; + assert(note_size != 0 && note_size <= nhdr.h.n_descsz); + note_data = malloc(note_size); + if (note_data == NULL) + goto out_error; + nbytes = pread_in_full(bin_fd, note_data, note_size, + phdr[ph_i].p_offset + note_offset); + if (nbytes < 0) + goto out_error; + if (nbytes != note_size) + goto out_invalid; + + *out_note_data = note_data; + *out_note_size = note_size; + free(ehdr); + free(phdr); + return 0; + +out_error: + warn("%s", bin_name); + free(ehdr); + free(phdr); + free(note_data); + exit(1); + +out_invalid: + warnx("%s: Invalid or unsupported executable", bin_name); + free(ehdr); + free(phdr); + free(note_data); + exit(1); +} diff --git a/tenders/common/elf.c b/tenders/common/elf64.c similarity index 99% rename from tenders/common/elf.c rename to tenders/common/elf64.c index 0a93e192..e3d3cd83 100644 --- a/tenders/common/elf.c +++ b/tenders/common/elf64.c @@ -195,8 +195,8 @@ static int align_up(Elf64_Addr addr, Elf64_Xword align, Elf64_Addr *out_result) } void elf_load(int bin_fd, const char *bin_name, uint8_t *mem, size_t mem_size, - uint64_t p_min_loadaddr, guest_mprotect_fn_t t_guest_mprotect, - void *t_guest_mprotect_arg, uint64_t *p_entry, uint64_t *p_end) + addr_t p_min_loadaddr, guest_mprotect_fn_t t_guest_mprotect, + void *t_guest_mprotect_arg, addr_t *p_entry, addr_t *p_end) { ssize_t nbytes; Elf64_Phdr *phdr = NULL; diff --git a/tenders/common/types.h b/tenders/common/types.h new file mode 100644 index 00000000..c5f98700 --- /dev/null +++ b/tenders/common/types.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015-2020 Contributors as noted in the AUTHORS file + * + * This file is part of Solo5, a sandboxed execution environment. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * types.h: Addressing type (32 or 64-bit) abstruction. + */ + +#ifndef COMMON_TYPES_H +#define COMMON_TYPES_H + + +#if defined(__BITS_32__) +typedef uint32_t addr_t; +#else +typedef uint64_t addr_t; +#endif + +#endif /* COMMON_TYPES_H */ diff --git a/tenders/spt/spt.h b/tenders/spt/spt.h index 6d2b2b22..cd626b00 100644 --- a/tenders/spt/spt.h +++ b/tenders/spt/spt.h @@ -26,12 +26,21 @@ #ifndef SPT_H #define SPT_H +#if defined(__BITS_32__) +#define ALIGN_SIZE 4 +#elif defined(__BITS_64__) +#define ALIGN_SIZE 8 +#else +#error Unsupported architecture +#endif + #include #include #include "../common/cc.h" #include "../common/elf.h" #include "../common/mft.h" +#include "../common/types.h" #include "spt_abi.h" struct spt { @@ -45,13 +54,13 @@ struct spt { struct spt *spt_init(size_t mem_size); -int spt_guest_mprotect(void *t_arg, uint64_t addr_start, uint64_t addr_end, +int spt_guest_mprotect(void *t_arg, addr_t addr_start, addr_t addr_end, int prot); -void spt_boot_info_init(struct spt *spt, uint64_t p_end, int cmdline_argc, +void spt_boot_info_init(struct spt *spt, addr_t p_end, int cmdline_argc, char **cmdline_argv, struct mft *mft, size_t mft_size); -void spt_run(struct spt *spt, uint64_t p_entry); +void spt_run(struct spt *spt, addr_t p_entry); /* * Operations provided by a module. (setup) is required, all other functions @@ -80,7 +89,7 @@ struct spt_module { */ #define DECLARE_MODULE(module_name, ...) \ static struct spt_module __module_ ##module_name \ - __attribute((section("modules"), aligned(8))) \ + __attribute((section("modules"), aligned(ALIGN_SIZE))) \ __attribute((used)) = { \ .name = #module_name, \ .ops = { __VA_ARGS__ } \ diff --git a/tenders/spt/spt_core.c b/tenders/spt/spt_core.c index 60bda05c..53164d9d 100644 --- a/tenders/spt/spt_core.c +++ b/tenders/spt/spt_core.c @@ -43,6 +43,7 @@ #include #endif +#include "../common/types.h" #include "spt.h" /* @@ -70,9 +71,9 @@ struct spt *spt_init(size_t mem_size) * On systems where we are built as a PIE executable: * * The kernel will apply ASLR and map the tender at a high virtual address - * (see ELF_ET_DYN_BASE in the kernel source for the arch-specific value, - * as we only support 64-bit architectures for now where this should always - * be >= 4 GB). + * for 64-bit architectures (see ELF_ET_DYN_BASE in the kernel source + * for the arch-specific value). It will apply only ASLR for 32-bit + * architectures. * * Therefore, rather than mislead the user with an incorrect error message, * assert that a) the tender has been loaded with a base address of at @@ -80,17 +81,24 @@ struct spt *spt_init(size_t mem_size) * address space. We can re-visit this if it turns out that users run on * systems where this does not hold (e.g. kernel ASLR is disabled). */ - assert((uint64_t)&__executable_start >= (1ULL << 32)); - assert((uint64_t)(mem_size - 1) < (uint64_t)&__executable_start); +#if defined(__BITS_32__) +#define ELF_ET_DYN_BASE 0x400000UL /* Derived from the kernel 5.6 */ + assert((addr_t)&__executable_start >= ELF_ET_DYN_BASE); +#elif defined(__BITS_64__) + assert((addr_t)&__executable_start >= (1ULL << 32)); #else +#error Unsupported architecture bits +#endif + assert((addr_t)(mem_size - 1) < (addr_t)&__executable_start); +#else /* !defined(__PIE__) */ /* * On systems where we are NOT built as a PIE executable, first assert that * -Ttext-segment has been correctly passed at the link step (see * configure.sh), and then check that guest memory size is within limits. */ - assert((uint64_t)&__executable_start >= (1ULL << 30)); - if ((uint64_t)(mem_size - 1) >= (uint64_t)&__executable_start) { - uint64_t max_mem_size_mb = (uint64_t)&__executable_start >> 20; + assert((addr_t)&__executable_start >= (1ULL << 30)); + if ((addr_t)(mem_size - 1) >= (addr_t)&__executable_start) { + addr_t max_mem_size_mb = (addr_t)&__executable_start >> 20; warnx("Maximum guest memory size (%lu MB) exceeded.", max_mem_size_mb); errx(1, "Either decrease --mem-size, or recompile solo5-spt" @@ -146,7 +154,7 @@ struct spt *spt_init(size_t mem_size) return spt; } -int spt_guest_mprotect(void *t_arg, uint64_t addr_start, uint64_t addr_end, +int spt_guest_mprotect(void *t_arg, addr_t addr_start, addr_t addr_end, int prot) { struct spt *spt = t_arg; @@ -187,10 +195,10 @@ static void setup_cmdline(uint8_t *cmdline, int argc, char **argv) } } -void spt_boot_info_init(struct spt *spt, uint64_t p_end, int cmdline_argc, +void spt_boot_info_init(struct spt *spt, addr_t p_end, int cmdline_argc, char **cmdline_argv, struct mft *mft, size_t mft_size) { - uint64_t lowmem_pos = SPT_BOOT_INFO_BASE; + addr_t lowmem_pos = SPT_BOOT_INFO_BASE; struct spt_boot_info *bi = (struct spt_boot_info *)(spt->mem + lowmem_pos); @@ -212,9 +220,9 @@ void spt_boot_info_init(struct spt *spt, uint64_t p_end, int cmdline_argc, /* * Defined in spt_lauch_.S. */ -extern void spt_launch(uint64_t stack_start, void (*fn)(void *), void *arg); +extern void spt_launch(addr_t stack_start, void (*fn)(void *), void *arg); -void spt_run(struct spt *spt, uint64_t p_entry) +void spt_run(struct spt *spt, addr_t p_entry) { typedef void (*start_fn_t)(void *arg); start_fn_t start_fn = (start_fn_t)(spt->mem + p_entry); @@ -222,14 +230,16 @@ void spt_run(struct spt *spt, uint64_t p_entry) * Set initial stack alignment based on arch-specific ABI requirements. */ #if defined(__x86_64__) - uint64_t sp = spt->mem_size - 0x8; + addr_t sp = spt->mem_size - 0x8; #elif defined(__aarch64__) - uint64_t sp = spt->mem_size - 0x10; + addr_t sp = spt->mem_size - 0x10; +#elif defined(__arm__) + addr_t sp = spt->mem_size - 0x8; #elif defined(__powerpc64__) /* * Stack alignment on PPC64 is 0x10, minimum stack frame size is 112 bytes. */ - uint64_t sp = spt->mem_size - 112; + addr_t sp = spt->mem_size - 112; #else #error Unsupported architecture #endif diff --git a/tenders/spt/spt_launch_arm.S b/tenders/spt/spt_launch_arm.S new file mode 100644 index 00000000..e2cca2e0 --- /dev/null +++ b/tenders/spt/spt_launch_arm.S @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015-2019 Contributors as noted in the AUTHORS file + * + * This file is part of Solo5, a sandboxed execution environment. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define ENTRY(x) .text; .globl x; .type x,%function; x: +#define END(x) .size x, . - x + +/* TODO/XXX: This calling convention is probably not 100% correct */ + +ENTRY(spt_launch) + mov sp, r0 + mov r0, r2 + mov r14, #0 + + blx r1 + + bx lr +END(spt_launch) diff --git a/tenders/spt/spt_main.c b/tenders/spt/spt_main.c index 60e90025..fdb836f3 100644 --- a/tenders/spt/spt_main.c +++ b/tenders/spt/spt_main.c @@ -35,6 +35,7 @@ #include #include +#include "../common/types.h" #include "spt.h" #include "solo5_version.h" @@ -131,7 +132,7 @@ static void version(const char *prog) int main(int argc, char **argv) { size_t mem_size = 0x20000000; - uint64_t p_entry, p_end; + addr_t p_entry, p_end; const char *prog; const char *elf_filename; int elf_fd = -1; From 65df7bc7e6e4918c88ee95236e516801ee62794c Mon Sep 17 00:00:00 2001 From: TImada Date: Wed, 10 Jun 2020 00:01:12 +0900 Subject: [PATCH 4/8] Test code fixes to support aarch32 --- tests/Makefile.tests | 4 ++++ tests/test_fpu/test_fpu.c | 27 +++++++++++++++++++++++++++ tests/test_notls/test_notls.c | 5 +++++ tests/test_seccomp/test_seccomp.c | 9 +++++++++ tests/test_tls/test_tls.c | 23 +++++++++++++++++++++++ 5 files changed, 68 insertions(+) diff --git a/tests/Makefile.tests b/tests/Makefile.tests index 2cd0dcd0..f44cb36d 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -54,7 +54,11 @@ manifest.c: manifest.json ../../include/solo5/mft_abi.h $(ELFTOOL) %.spt: %.o manifest.o $(LDS.spt) $(BINDINGS.spt) @echo "LD $@" +ifeq ($(CONFIG_ARCH), arm) + $(LD) $(LDFLAGS) -T $(LDS.spt) $(BINDINGS.spt) $< manifest.o $(TOPDIR)/lib32/aeabi/libaeabi.a -o $@ +else $(LD) $(LDFLAGS) -T $(LDS.spt) $(BINDINGS.spt) $< manifest.o -o $@ +endif %.virtio: %.o manifest.o $(LDS.virtio) $(BINDINGS.virtio) @echo "LD $@" diff --git a/tests/test_fpu/test_fpu.c b/tests/test_fpu/test_fpu.c index 93b47682..ddd5d9e5 100644 --- a/tests/test_fpu/test_fpu.c +++ b/tests/test_fpu/test_fpu.c @@ -56,6 +56,29 @@ int solo5_app_main(const struct solo5_start_info *si __attribute__((unused))) : "m" (c) : "q0", "q1", "v0" ); +#elif defined(__arm__) + /* We focus on only the first half of the array c[] */ + float *addr = &c[0]; + __asm__( + "ldr r0, %0\n" + "vld1.32 {d0}, [r0]\n" + "vld1.32 {d1}, [r0]\n" + "vmul.f32 d0, d1, d0\n" + "vst1.32 {d0}, [r0]\n" + : "=m" (addr) + : "m" (addr) + : "r0", "d0", "d1" + ); + /* TODO: This is a workaround for arm-linux-gnueabihf-gcc */ + int i; + for (i = 0; i < 6; i++) { + __asm__( + "nop\n" + : + : + : + ); + } #elif defined(__powerpc64__) #define DOMUL(VAR) \ __asm__( \ @@ -79,7 +102,11 @@ int solo5_app_main(const struct solo5_start_info *si __attribute__((unused))) b = 5.0; a *= b; +#if defined(__arm__) + if (a == 7.5 && c[0] == 4.0 && c[1] == 25.0 && c[2] == 3.0 && c[3] == 8.0) +#else if (a == 7.5 && c[0] == 4.0 && c[1] == 25.0 && c[2] == 9.0 && c[3] == 64.0) +#endif puts("SUCCESS\n"); else return SOLO5_EXIT_FAILURE; diff --git a/tests/test_notls/test_notls.c b/tests/test_notls/test_notls.c index 1105f176..56920fe8 100644 --- a/tests/test_notls/test_notls.c +++ b/tests/test_notls/test_notls.c @@ -37,6 +37,11 @@ int solo5_app_main(const struct solo5_start_info *si __attribute__((unused))) "add x0, x0, #0x10; " "ldr w1, [x0]" : : : "x0", "w1"); +#elif defined(__arm__) + __asm__ __volatile("mrc p15, 0, r0, c13, c0, 2; " + "add r0, r0, #0x10; " + "ldr r1, [r0]" + : : : "r0", "r1"); #elif defined(__powerpc64__) __asm__ __volatile("ld 3,-28672(13)" : : : "r3", "r13"); #else diff --git a/tests/test_seccomp/test_seccomp.c b/tests/test_seccomp/test_seccomp.c index 8b64c477..070cdcdc 100644 --- a/tests/test_seccomp/test_seccomp.c +++ b/tests/test_seccomp/test_seccomp.c @@ -49,6 +49,15 @@ int solo5_app_main(const struct solo5_start_info *si __attribute__((unused))) "svc 0" : "=r" (x0) : "r" (x8), "r" (x1) : "cc", "memory" ); +#elif defined(__arm__) + register long r7 __asm__("r7") = 41; + register long r0 __asm__("r0"); + register long r1 __asm__("r1") = 1; + + __asm__ __volatile__ ( + "svc 0" + : "=r" (r0) : "r" (r7), "r" (r1) : "cc", "memory" + ); #elif defined(__powerpc__) register long r0 __asm__("r0") = 41; register long r3 __asm__("r3") = 0; diff --git a/tests/test_tls/test_tls.c b/tests/test_tls/test_tls.c index da1774db..3372825c 100644 --- a/tests/test_tls/test_tls.c +++ b/tests/test_tls/test_tls.c @@ -62,6 +62,13 @@ struct tcb { void *pad; volatile uint64_t _data; }; +#elif defined(__arm__) +/* Variant I */ +struct tcb { + void *tp; + void *pad; + volatile uint32_t _data; +}; #else #error Unsupported architecture #endif @@ -74,6 +81,19 @@ static void puts(const char *s) solo5_console_write(s, strlen(s)); } +#if defined(__BITS_32__) +__thread volatile uint32_t _data; + +uint32_t __attribute__ ((noinline)) get_data() +{ + return _data; +} + +void __attribute__ ((noinline)) set_data(uint32_t data) +{ + _data = data; +} +#elif defined(__BITS_64__) __thread volatile uint64_t _data; uint64_t __attribute__ ((noinline)) get_data() @@ -85,6 +105,9 @@ void __attribute__ ((noinline)) set_data(uint64_t data) { _data = data; } +#else +#error Unsupported architecture bits +#endif int solo5_app_main(const struct solo5_start_info *si __attribute__((unused))) { From 86605f632ca5185db4fc5d3ed2f685648b3f45a3 Mon Sep 17 00:00:00 2001 From: TImada Date: Wed, 10 Jun 2020 00:04:26 +0900 Subject: [PATCH 5/8] configure.sh fixes to support aarch32 --- configure.sh | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/configure.sh b/configure.sh index 08284097..fa5a5251 100755 --- a/configure.sh +++ b/configure.sh @@ -117,7 +117,7 @@ config_host_linux() mkdir -p ${HOST_INCDIR} cp -R ${CC_INCDIR}/. ${HOST_INCDIR} - MAKECONF_CFLAGS="-nostdinc" + MAKECONF_CFLAGS="-nostdinc -D${CONFIG_BITS}" # Recent distributions now default to PIE enabled. Disable it explicitly # if that's the case here. # XXX: This breaks MirageOS in (at least) the build of mirage-solo5 due @@ -136,6 +136,23 @@ config_host_linux() MAKECONF_CFLAGS="${MAKECONF_CFLAGS} -mstack-protector-guard=global" fi + # 32-bit ARM specific configuration: + # + # 1. We are mainly focusing on ARMv7-a architecture and assuming that + # target processors have the NEON SIMD feature. + # 2. We asssme a target system has libaebai.a as a library to solve + # the following problems. + # - ARMv7-a based processors does not support instructions related to + # several arithmetic operations. + # - GCC tries to use the TPIDRURO register rather than TPIDRURW for TLS + # (Thread Local Storage). We need to put the "-mtp=soft" flag to make + # GCC to use an external __aeabi_read_tp funtion provided in + # libaeabi.a. + if [ "${CONFIG_ARCH}" = "arm" ]; + then + MAKECONF_CFLAGS="${MAKECONF_CFLAGS} -mfpu=neon -mtp=soft" + fi + # If the host toolchain is NOT configured to build PIE exectuables by # default, assume it has no support for that and apply a workaround by # locating the spt tender starting at a virtual address of 1 GB. @@ -175,6 +192,7 @@ config_host_linux() [ "${CONFIG_ARCH}" = "x86_64" ] && CONFIG_VIRTIO=1 [ "${CONFIG_ARCH}" = "x86_64" ] && CONFIG_MUEN=1 [ "${CONFIG_ARCH}" = "ppc64le" ] && CONFIG_HVT= + [ "${CONFIG_ARCH}" = "arm" ] && CONFIG_HVT= CONFIG_GENODE= } @@ -274,23 +292,33 @@ CC_MACHINE=$(${CC} -dumpmachine) # Determine HOST and ARCH based on what the toolchain reports. case ${CC_MACHINE} in x86_64-*linux*) - CONFIG_ARCH=x86_64 CONFIG_HOST=Linux + CONFIG_ARCH=x86_64 CONFIG_BITS=__BITS_64__ + CONFIG_HOST=Linux CONFIG_GUEST_PAGE_SIZE=0x1000 ;; aarch64-*linux*) - CONFIG_ARCH=aarch64 CONFIG_HOST=Linux + CONFIG_ARCH=aarch64 CONFIG_BITS=__BITS_64__ + CONFIG_HOST=Linux + CONFIG_GUEST_PAGE_SIZE=0x1000 + ;; + arm-*linux*) + CONFIG_ARCH=arm CONFIG_BITS=__BITS_32__ + CONFIG_HOST=Linux CONFIG_GUEST_PAGE_SIZE=0x1000 ;; powerpc64le-*linux*|ppc64le-*linux*) - CONFIG_ARCH=ppc64le CONFIG_HOST=Linux + CONFIG_ARCH=ppc64le CONFIG_BITS=__BITS_64__ + CONFIG_HOST=Linux CONFIG_GUEST_PAGE_SIZE=0x10000 ;; x86_64-*freebsd*) - CONFIG_ARCH=x86_64 CONFIG_HOST=FreeBSD + CONFIG_ARCH=x86_64 CONFIG_BITS=__BITS_64__ + CONFIG_HOST=FreeBSD CONFIG_GUEST_PAGE_SIZE=0x1000 ;; amd64-*openbsd*) - CONFIG_ARCH=x86_64 CONFIG_HOST=OpenBSD + CONFIG_ARCH=x86_64 CONFIG_BITS=__BITS_64__ + CONFIG_HOST=OpenBSD CONFIG_GUEST_PAGE_SIZE=0x1000 ;; *) @@ -357,6 +385,7 @@ CONFIG_GENODE=${CONFIG_GENODE} MAKECONF_CFLAGS=${MAKECONF_CFLAGS} MAKECONF_LDFLAGS=${MAKECONF_LDFLAGS} CONFIG_ARCH=${CONFIG_ARCH} +CONFIG_BITS=${CONFIG_BITS} CONFIG_HOST=${CONFIG_HOST} CONFIG_GUEST_PAGE_SIZE=${CONFIG_GUEST_PAGE_SIZE} MAKECONF_CC=${CC} From 887c2b4c769e96e11084ba12571cfaed5a00e42e Mon Sep 17 00:00:00 2001 From: TImada Date: Wed, 10 Jun 2020 02:17:49 +0900 Subject: [PATCH 6/8] Build document fixes to describe the aarch32 support by the spt target --- docs/building.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/building.md b/docs/building.md index ca9ebb14..44ca42fe 100644 --- a/docs/building.md +++ b/docs/building.md @@ -16,7 +16,7 @@ unikernel -- about building Solo5, and running Solo5-based unikernels. ## Building Solo5 -Solo5 itself has the following build dependencies: +Solo5 itself has the following build dependencies on 64-bit architectures: * a 64-bit Linux, FreeBSD or OpenBSD system (see also [Supported targets](#supported-targets) for further requirements), @@ -26,6 +26,16 @@ Solo5 itself has the following build dependencies: by default), * on Linux only, pkg-config and libseccomp >= 2.3.3 are required. +Solo5 with the _spt_ target can be built experimentally on a 32-bit ARM +architecture with the following build dependencies: + +* a 32-bit Linux system with ARMv7-A architecture supporitng NEON v1 or newer, +* a C11 compiler; only arm-linux-gnueabihf-gcc supported, +* GNU make, +* full host system headers (on Linux, kernel headers are not always installed + by default), +* pkg-config and libseccomp >= 2.3.3 are required. + Note that Solo5 does not support cross-compilation. With the exception of the _muen_ and _genode_ targets (which are not self-hosting), you should build Solo5 and unikernels on a build system matching the host system and processor @@ -80,9 +90,9 @@ Experimental: * _hvt_: OpenBSD vmm, using `solo5-hvt` as a _tender_, on the x86\_64 architecture. OpenBSD 6.4 or later is required, 6.7 or later is recommended for full W^X support. -* _spt_: Linux systems on the x86\_64, ppc64le and aarch64 architectures, using - `solo5-spt` as a _tender_. A Linux distribution with libseccomp >= 2.3.3 is - required. +* _spt_: Linux systems on the x86\_64, ppc64le, aarch64 and aarch32 + architectures, using `solo5-spt` as a _tender_. A Linux distribution with + libseccomp >= 2.3.3 is required. * _muen_: The [Muen Separation Kernel](https://muen.sk/), on the x86\_64 architecture. Muen commit `f10bd6b` or later is required. From 0fe3a2fa965c8ec7190ed2a60af6a01a63ba7bbd Mon Sep 17 00:00:00 2001 From: TImada Date: Wed, 10 Jun 2020 02:20:15 +0900 Subject: [PATCH 7/8] Added arm32(aarch32) to the opam file for solo5-bindings-spt --- opam/solo5-bindings-spt.opam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opam/solo5-bindings-spt.opam b/opam/solo5-bindings-spt.opam index bdc1166f..f8e39707 100644 --- a/opam/solo5-bindings-spt.opam +++ b/opam/solo5-bindings-spt.opam @@ -32,7 +32,7 @@ conflicts: [ "solo5-bindings-genode" ] available: [ - (arch = "x86_64" | arch = "arm64") & os = "linux" + (arch = "x86_64" | arch = "arm32" | arch = "arm64") & os = "linux" ] synopsis: "Solo5 sandboxed execution environment (spt target)" description: """ @@ -44,4 +44,4 @@ This package provides the Solo5 components needed to build MirageOS unikernels on the "spt" target and the "solo5-spt" tender binary used to run such unikernels. -The "spt" target is supported on 64-bit Linux systems only.""" +The "spt" target is supported on 64-bit Linux systems or 32-bit Linux ARM systems only.""" From a23d41e17174c45d28f267ddcff3575754aad3b5 Mon Sep 17 00:00:00 2001 From: TImada Date: Wed, 10 Jun 2020 22:35:29 +0900 Subject: [PATCH 8/8] Added license description about libaeabi --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 043c3eb0..8d7da15e 100644 --- a/README.md +++ b/README.md @@ -52,12 +52,18 @@ unikernel in particular: - [Debugging Solo5-based unikernels](docs/debugging.md) - [Technical overview, goals and limitations, and architecture of Solo5](docs/architecture.md) -# Contributing and community +# License, contributing and community -Solo5 is developed on GitHub and licensed under a liberal ISC license. We -accept contributions via GitHub pull requests. When submitting a contribution, -please add your details to the `AUTHORS` file, and if your contribution adds -new source files copy the copyright header from an existing source file. +Solo5 is developed on GitHub and its original contributions are licensed under +a liberal ISC license. + +This package incorporates components derived or copied from LLVM compiler-rt. +For full details of the licenses of the components, refer to each source file. + +We accept contributions via GitHub pull requests. When submitting a +contribution, please add your details to the `AUTHORS` file, and if your +contribution adds new source files copy the copyright header from an existing +source file. The coding style for the project is "as for the Linux kernel, but with 4 spaces instead of tabs". When in doubt, please follow style in existing source