diff options
Diffstat (limited to 'lib/mlibc/options/internal/gcc')
-rw-r--r-- | lib/mlibc/options/internal/gcc/guard-abi.cpp | 68 | ||||
-rw-r--r-- | lib/mlibc/options/internal/gcc/initfini.cpp | 23 | ||||
-rw-r--r-- | lib/mlibc/options/internal/gcc/stack_protector.cpp | 31 |
3 files changed, 122 insertions, 0 deletions
diff --git a/lib/mlibc/options/internal/gcc/guard-abi.cpp b/lib/mlibc/options/internal/gcc/guard-abi.cpp new file mode 100644 index 0000000..945582a --- /dev/null +++ b/lib/mlibc/options/internal/gcc/guard-abi.cpp @@ -0,0 +1,68 @@ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include <mlibc/debug.hpp> +#include <mlibc/internal-sysdeps.hpp> + +namespace { + +// Itanium ABI static initialization guard. +struct Guard { + // bit of the mutex member variable. + // indicates that the mutex is locked. + static constexpr int32_t locked = 1; + + void lock() { + uint32_t v = 0; + if(__atomic_compare_exchange_n(&mutex, &v, Guard::locked, false, + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + return; + + mlibc::sys_libc_log("__cxa_guard_acquire contention"); + __builtin_trap(); + } + + void unlock() { + __atomic_store_n(&mutex, 0, __ATOMIC_RELEASE); + } + + // the first byte's meaning is fixed by the ABI. + // it indicates whether initialization has already been completed. + uint8_t complete; + + // we use some of the remaining bytes to implement a mutex. + uint32_t mutex; +}; + +static_assert(sizeof(Guard) == sizeof(int64_t)); + +} // namespace { } + +extern "C" [[ gnu::visibility("hidden") ]] void __cxa_pure_virtual() { + mlibc::panicLogger() << "mlibc: Pure virtual function called from IP " + << (void *)__builtin_return_address(0) << frg::endlog; +} + +extern "C" [[ gnu::visibility("hidden") ]] int __cxa_guard_acquire(int64_t *ptr) { + auto guard = reinterpret_cast<Guard *>(ptr); + guard->lock(); + // relaxed ordering is sufficient because + // Guard::complete is only modified while the mutex is held. + if(__atomic_load_n(&guard->complete, __ATOMIC_RELAXED)) { + guard->unlock(); + return 0; + }else{ + return 1; + } +} + +extern "C" [[ gnu::visibility("hidden") ]] void __cxa_guard_release(int64_t *ptr) { + auto guard = reinterpret_cast<Guard *>(ptr); + // do a store-release so that compiler generated code can skip calling + // __cxa_guard_acquire by doing a load-acquire on Guard::complete. + __atomic_store_n(&guard->complete, 1, __ATOMIC_RELEASE); + guard->unlock(); +} + diff --git a/lib/mlibc/options/internal/gcc/initfini.cpp b/lib/mlibc/options/internal/gcc/initfini.cpp new file mode 100644 index 0000000..b329f38 --- /dev/null +++ b/lib/mlibc/options/internal/gcc/initfini.cpp @@ -0,0 +1,23 @@ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include <mlibc/internal-sysdeps.hpp> +#include <mlibc/debug.hpp> + +typedef void (*InitPtr)(); + +extern InitPtr __CTOR_LIST__ [[ gnu::visibility("hidden") ]]; +extern InitPtr __CTOR_END__ [[ gnu::visibility("hidden") ]]; + +extern "C" [[ gnu::visibility("hidden") ]] void __mlibc_do_ctors() { + auto it = &__CTOR_LIST__; + while(it != &__CTOR_END__) + (*it++)(); +} + +extern "C" [[ gnu::visibility("hidden") ]] void __mlibc_do_dtors() { + mlibc::sys_libc_log("__mlibc_do_dtors() called"); +} + diff --git a/lib/mlibc/options/internal/gcc/stack_protector.cpp b/lib/mlibc/options/internal/gcc/stack_protector.cpp new file mode 100644 index 0000000..e5e50f0 --- /dev/null +++ b/lib/mlibc/options/internal/gcc/stack_protector.cpp @@ -0,0 +1,31 @@ +#include <stdint.h> +#include <string.h> +#include <mlibc/debug.hpp> +#include <mlibc/stack_protector.hpp> + +uintptr_t __stack_chk_guard = 0; + +namespace mlibc { + +void initStackGuard(void *entropy) { + if(entropy != nullptr) { + memcpy(&__stack_chk_guard, entropy, sizeof(__stack_chk_guard)); + } else { + // If no entropy is available, set it to the terminator canary + __stack_chk_guard = 0; + __stack_chk_guard |= ('\n' << 16); + __stack_chk_guard |= (255 << 24); + } +} + +} // namespace mlibc + +extern "C" [[noreturn]] void __stack_chk_fail() { + mlibc::panicLogger() << "Stack smashing detected!" << frg::endlog; + __builtin_unreachable(); +} + +extern "C" [[noreturn, gnu::visibility("hidden")]] void __stack_chk_fail_local() { + __stack_chk_fail(); +}; + |