diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt index cdac67e93df14..84f42712f04c4 100644 --- a/libunwind/CMakeLists.txt +++ b/libunwind/CMakeLists.txt @@ -338,7 +338,7 @@ if (LIBUNWIND_ENABLE_ASSERTIONS) # On Release builds cmake automatically defines NDEBUG, so we # explicitly undefine it: - if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + if ((uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") AND (NOT RUST_SGX)) add_compile_flags(-UNDEBUG) endif() else() diff --git a/libunwind/README_RUST_SGX.md b/libunwind/README_RUST_SGX.md new file mode 100644 index 0000000000000..c5d6eb4772bc3 --- /dev/null +++ b/libunwind/README_RUST_SGX.md @@ -0,0 +1,22 @@ +# Libunwind customizations for linking with x86_64-fortanix-unknown-sgx Rust target. + +## Description +### Initial Fork +Initial Fork has been made from 5.0 release of llvm (commit: 6a075b6de4) +### Detailed Description +#### Header files that we do not include for this target +1. pthread.h +#### Library that we do not link to for this target. +1. pthread (Locks used by libunwind is provided by rust stdlib for this target) + +## Building unwind for rust-sgx target +### Generate Make files: +* `cd where you want to build libunwind` +* `mkdir build` +* `cd build` +* `cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" -DLLVM_ENABLE_WARNINGS=1 -DLIBUNWIND_ENABLE_PEDANTIC=0 -DLLVM_PATH= ` +* `"DEBUG"` could be used instead of `"RELEASE"` to enable debug logs of libunwind. + +### Build: +* `make unwind_static` +* `build/lib/` will have the built library. diff --git a/libunwind/docs/BuildingLibunwind.rst b/libunwind/docs/BuildingLibunwind.rst index ad9dee0519a82..a2d21dfcd021f 100644 --- a/libunwind/docs/BuildingLibunwind.rst +++ b/libunwind/docs/BuildingLibunwind.rst @@ -159,3 +159,8 @@ libunwind specific options .. option:: LIBUNWIND_SYSROOT Sysroot for cross compiling + +.. option:: LIBUNWIND_ENABLE_RUST_SGX:BOOL + + **Default**: ``OFF`` + diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 93395ffb3b1d1..c087fedaa139c 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -124,6 +124,7 @@ namespace libunwind { // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; +#if !defined(RUST_SGX) extern char __eh_frame_start; extern char __eh_frame_end; @@ -132,6 +133,15 @@ extern char __eh_frame_hdr_start; extern char __eh_frame_hdr_end; #endif +#elif defined(RUST_SGX) +extern "C" char IMAGE_BASE; +extern "C" uint64_t EH_FRM_HDR_OFFSET; +extern "C" uint64_t EH_FRM_HDR_LEN; +extern "C" uint64_t EH_FRM_OFFSET; +extern "C" uint64_t EH_FRM_LEN; +#endif + + #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) // When statically linked on bare-metal, the symbols for the EH table are looked @@ -557,6 +567,10 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, #endif // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#if defined(RUST_SGX) +extern "C" char IMAGE_BASE; +#endif + inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, UnwindInfoSections &info) { #ifdef __APPLE__ @@ -573,6 +587,8 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, } #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) // Bare metal is statically linked, so no need to ask the dynamic loader + +#if !defined(RUST_SGX) info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); info.dwarf_section = (uintptr_t)(&__eh_frame_start); _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", @@ -583,6 +599,17 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); #endif + +#elif defined(RUST_SGX) + info.dwarf_section = (uintptr_t)EH_FRM_OFFSET + (uintptr_t)(&IMAGE_BASE); + info.dwarf_section_length = (uintptr_t)EH_FRM_LEN; +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + info.dwarf_index_section = (uintptr_t)EH_FRM_HDR_OFFSET + (uintptr_t)(&IMAGE_BASE); + info.dwarf_index_section_length = (uintptr_t)EH_FRM_HDR_LEN; +#endif + +#endif + if (info.dwarf_section_length) return true; #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) diff --git a/libunwind/src/CMakeLists.txt b/libunwind/src/CMakeLists.txt index 309a85b22f593..36bb376cd5cbc 100644 --- a/libunwind/src/CMakeLists.txt +++ b/libunwind/src/CMakeLists.txt @@ -1,5 +1,9 @@ # Get sources +enable_language(C CXX ASM) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(LIBUNWIND_CXX_SOURCES libunwind.cpp Unwind-EHABI.cpp @@ -16,20 +20,12 @@ set(LIBUNWIND_C_SOURCES UnwindLevel1-gcc-ext.c Unwind-sjlj.c ) -set_source_files_properties(${LIBUNWIND_C_SOURCES} - PROPERTIES - COMPILE_FLAGS "-std=c99") set(LIBUNWIND_ASM_SOURCES UnwindRegistersRestore.S UnwindRegistersSave.S ) -# See add_asm_sources() in compiler-rt for explanation of this workaround. -if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17)) - set_source_files_properties(${LIBUNWIND_ASM_SOURCES} PROPERTIES LANGUAGE C) -endif() - set(LIBUNWIND_HEADERS AddressSpace.hpp assembly.h @@ -57,6 +53,44 @@ if (MSVC_IDE) source_group("Header Files" FILES ${LIBUNWIND_HEADERS}) endif() +if (RUST_SGX) + # Compile Flags + add_definitions(-DRUST_SGX) + add_definitions(-D__NO_STRING_INLINES) + add_definitions(-D__NO_MATH_INLINES) + add_definitions(-D_LIBUNWIND_IS_BAREMETAL) + # Can't use add_definitions because CMake will reorder these arguments + list(APPEND LIBUNWIND_COMPILE_FLAGS -U_FORTIFY_SOURCE) + list(APPEND LIBUNWIND_COMPILE_FLAGS -D_FORTIFY_SOURCE=0) + + list(APPEND LIBUNWIND_COMPILE_FLAGS -fno-stack-protector) + list(APPEND LIBUNWIND_COMPILE_FLAGS -ffreestanding) + list(APPEND LIBUNWIND_COMPILE_FLAGS -fexceptions) + # Avoid too new relocation types being emitted, which might prevent linking + # on older platforms. + # + # See https://github.com/rust-lang/rust/issues/34978 + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + list(APPEND LIBUNWIND_COMPILE_FLAGS -Wa,-mrelax-relocations=no) + else() + list(APPEND LIBUNWIND_COMPILE_FLAGS) + endif() + + # Sources + list(APPEND LIBUNWIND_HEADERS UnwindRustSgx.h) + list(APPEND LIBUNWIND_C_SOURCES UnwindRustSgx.c) +endif() + + +set_source_files_properties(${LIBUNWIND_C_SOURCES} + PROPERTIES + COMPILE_FLAGS "-std=c99") + +# See add_asm_sources() in compiler-rt for explanation of this workaround. +if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17)) + set_source_files_properties(${LIBUNWIND_ASM_SOURCES} PROPERTIES LANGUAGE C) +endif() + set(LIBUNWIND_SOURCES ${LIBUNWIND_CXX_SOURCES} ${LIBUNWIND_C_SOURCES} @@ -71,7 +105,7 @@ else() add_library_flags_if(LIBUNWIND_HAS_GCC_LIB gcc) endif() add_library_flags_if(LIBUNWIND_HAS_DL_LIB dl) -if (LIBUNWIND_ENABLE_THREADS) +if (LIBUNWIND_ENABLE_THREADS AND (NOT RUST_SGX)) add_library_flags_if(LIBUNWIND_HAS_PTHREAD_LIB pthread) add_compile_flags_if(LIBUNWIND_WEAK_PTHREAD_LIB -DLIBUNWIND_USE_WEAK_PTHREAD=1) endif() diff --git a/libunwind/src/RWMutex.hpp b/libunwind/src/RWMutex.hpp index fcd3f4967d17f..8589460c278b3 100644 --- a/libunwind/src/RWMutex.hpp +++ b/libunwind/src/RWMutex.hpp @@ -15,7 +15,7 @@ #if defined(_WIN32) #include -#elif !defined(_LIBUNWIND_HAS_NO_THREADS) +#elif !defined(_LIBUNWIND_HAS_NO_THREADS) && !defined(RUST_SGX) #include #if defined(__ELF__) && defined(_LIBUNWIND_LINK_PTHREAD_LIB) #pragma comment(lib, "pthread") diff --git a/libunwind/src/UnwindRustSgx.c b/libunwind/src/UnwindRustSgx.c new file mode 100644 index 0000000000000..9be7c1b54e6f8 --- /dev/null +++ b/libunwind/src/UnwindRustSgx.c @@ -0,0 +1,125 @@ +//===--------------------- UnwindRustSgx.c ----------------------------------===// +// +//// The LLVM Compiler Infrastructure +//// +//// This file is dual licensed under the MIT and the University of Illinois Open +//// Source Licenses. See LICENSE.TXT for details. +//// +//// +////===----------------------------------------------------------------------===// + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include "UnwindRustSgx.h" + +#define max_log 256 + +__attribute__((weak)) struct _IO_FILE *stderr = (struct _IO_FILE *)-1; + +static int vwrite_err(const char *format, va_list ap) +{ + int len = 0; +#ifndef NDEBUG + char s[max_log]; + s[0]='\0'; + len = vsnprintf(s, max_log, format, ap); + __rust_print_err((uint8_t *)s, len); +#endif + return len; +} + +static int write_err(const char *format, ...) +{ + int ret; + va_list args; + va_start(args, format); + ret = vwrite_err(format, args); + va_end(args); + + + return ret; +} + +__attribute__((weak)) int fprintf (FILE *__restrict __stream, + const char *__restrict __format, ...) +{ + + int ret; + if (__stream != stderr) { + write_err("Rust SGX Unwind supports only writing to stderr\n"); + return -1; + } else { + va_list args; + ret = 0; + va_start(args, __format); + ret += vwrite_err(__format, args); + va_end(args); + } + + return ret; +} + +__attribute__((weak)) int fflush (FILE *__stream) +{ + // We do not need to do anything here. + return 0; +} + +__attribute__((weak)) void __assert_fail(const char * assertion, + const char * file, + unsigned int line, + const char * function) +{ + write_err("%s:%d %s %s\n", file, line, function, assertion); + abort(); +} + +// We do not report stack over flow detected. +// Calling write_err uses more stack due to the way we have implemented it. +// With possible enabling of stack probes, we should not +// get into __stack_chk_fail() at all. +__attribute__((weak)) void __stack_chk_fail() { + abort(); +} + +/* + * Below are defined for all executibles compiled for + * x86_64-fortanix-unknown-sgx rust target. + * Ref: rust/src/libstd/sys/sgx/abi/entry.S + */ + +struct libwu_rs_alloc_meta { + size_t alloc_size; + // Should we put a signatre guard before ptr for oob access? + unsigned char ptr[0]; +}; + +#define META_FROM_PTR(__PTR) (struct libwu_rs_alloc_meta *) \ + ((unsigned char *)__PTR - offsetof(struct libwu_rs_alloc_meta, ptr)) + +void *libuw_malloc(size_t size) +{ + struct libwu_rs_alloc_meta *meta; + size_t alloc_size = size + sizeof(struct libwu_rs_alloc_meta); + meta = (void *)__rust_c_alloc(alloc_size, sizeof(size_t)); + if (!meta) { + return NULL; + } + meta->alloc_size = alloc_size; + return (void *)meta->ptr; +} + +void libuw_free(void *p) +{ + struct libwu_rs_alloc_meta *meta; + if (!p) { + return; + } + meta = META_FROM_PTR(p); + __rust_c_dealloc((unsigned char *)meta, meta->alloc_size, sizeof(size_t)); +} diff --git a/libunwind/src/UnwindRustSgx.h b/libunwind/src/UnwindRustSgx.h new file mode 100644 index 0000000000000..3c54b167696a9 --- /dev/null +++ b/libunwind/src/UnwindRustSgx.h @@ -0,0 +1,94 @@ +//===--------------------- UnwindRustSgx.h ----------------------------------===// +// +//// The LLVM Compiler Infrastructure +//// +//// This file is dual licensed under the MIT and the University of Illinois Open +//// Source Licenses. See LICENSE.TXT for details. +//// +//// +////===----------------------------------------------------------------------===// + +#if !defined(UNWIND_RUST_SGX_H) +#define UNWIND_RUST_SGX_H + +#ifdef RUST_SGX + +#undef _GNU_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include + +// We have to use RWLock from rust repo, it is defined in: +// src/libstd/sys/sgx/rwlock.rs. +// rwlock.rs has compile time check to ensure sizeof(RWLock) = 144. +typedef struct { + unsigned char opaque[144]; +} RWLock; + +// The below is obtained by printing initialized bytes +// for RWLock in rust repo: src/libstd/sys/sgx/rwlock.rs. +#define RWLOCK_INIT { { \ + /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ + } } + +// These are the functions exposed by SGX-Rust. +// The rust changes are available at: +#ifdef __cplusplus +extern "C" { +#endif + int __rust_rwlock_rdlock(RWLock *rwlock); + int __rust_rwlock_wrlock(RWLock *rwlock); + int __rust_rwlock_unlock(RWLock *rwlock); + unsigned char *__rust_c_alloc(size_t, size_t); + void __rust_c_dealloc(unsigned char *, size_t, size_t); + __attribute__((noreturn)) void __rust_abort(void); + unsigned char *__rust_encl_address(size_t); + +#ifndef NDEBUG + void __rust_print_err(uint8_t *m, int s); +#endif + +#ifdef __cplusplus +} +#endif + +#define abort __rust_abort + +#undef pthread_rwlock_t +#undef pthread_rwlock_rdlock +#undef pthread_rwlock_wrlock +#undef pthread_rwlock_unlock +#undef PTHREAD_RWLOCK_INITIALIZER + +#define pthread_rwlock_t RWLock +#define pthread_rwlock_rdlock __rust_rwlock_rdlock +#define pthread_rwlock_wrlock __rust_rwlock_wrlock +#define pthread_rwlock_unlock __rust_rwlock_unlock +#define PTHREAD_RWLOCK_INITIALIZER RWLOCK_INIT + +#define malloc libuw_malloc +#define free libuw_free + +#ifdef __cplusplus +extern "C" { +#endif + +void *libuw_malloc(size_t size); +void libuw_free(void *p); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/libunwind/src/config.h b/libunwind/src/config.h index 842fd829af197..a1573229054ec 100644 --- a/libunwind/src/config.h +++ b/libunwind/src/config.h @@ -17,7 +17,9 @@ #include #include #include - +#ifdef RUST_SGX +#include "UnwindRustSgx.h" +#endif // Define static_assert() unless already defined by compiler. #ifndef __has_feature #define __has_feature(__x) 0