user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_ARCH_DEFS_HPP
|
||||
#define MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline constexpr size_t page_size = 0x1000;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_ARCH_DEFS_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline Tcb *get_current_tcb() {
|
||||
// On AArch64, TPIDR_EL0 points to 0x10 bytes before the first TLS block.
|
||||
uintptr_t ptr;
|
||||
asm volatile ("mrs %0, tpidr_el0" : "=r"(ptr));
|
||||
return reinterpret_cast<Tcb *>(ptr + 0x10 - sizeof(Tcb));
|
||||
}
|
||||
|
||||
inline uintptr_t get_sp() {
|
||||
uintptr_t sp;
|
||||
asm volatile ("mov %0, sp" : "=r"(sp));
|
||||
return sp;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,69 @@
|
||||
# The functions below are taken from musl.
|
||||
.global fegetround
|
||||
.type fegetround,%function
|
||||
fegetround:
|
||||
mrs x0, fpcr
|
||||
and w0, w0, #0xc00000
|
||||
ret
|
||||
|
||||
.global __fesetround
|
||||
.hidden __fesetround
|
||||
.type __fesetround,%function
|
||||
__fesetround:
|
||||
mrs x1, fpcr
|
||||
bic w1, w1, #0xc00000
|
||||
orr w1, w1, w0
|
||||
msr fpcr, x1
|
||||
mov w0, #0
|
||||
ret
|
||||
|
||||
.global fetestexcept
|
||||
.type fetestexcept,%function
|
||||
fetestexcept:
|
||||
and w0, w0, #0x1f
|
||||
mrs x1, fpsr
|
||||
and w0, w0, w1
|
||||
ret
|
||||
|
||||
.global feclearexcept
|
||||
.type feclearexcept,%function
|
||||
feclearexcept:
|
||||
and w0, w0, #0x1f
|
||||
mrs x1, fpsr
|
||||
bic w1, w1, w0
|
||||
msr fpsr, x1
|
||||
mov w0, #0
|
||||
ret
|
||||
|
||||
.global feraiseexcept
|
||||
.type feraiseexcept,%function
|
||||
feraiseexcept:
|
||||
and w0, w0, #0x1f
|
||||
mrs x1, fpsr
|
||||
orr w1, w1, w0
|
||||
msr fpsr, x1
|
||||
mov w0, #0
|
||||
ret
|
||||
|
||||
.global fegetenv
|
||||
.type fegetenv,%function
|
||||
fegetenv:
|
||||
mrs x1, fpcr
|
||||
mrs x2, fpsr
|
||||
stp w1, w2, [x0]
|
||||
mov w0, #0
|
||||
ret
|
||||
|
||||
// TODO preserve some bits
|
||||
.global fesetenv
|
||||
.type fesetenv,%function
|
||||
fesetenv:
|
||||
mov x1, #0
|
||||
mov x2, #0
|
||||
cmn x0, #1
|
||||
b.eq 1f
|
||||
ldp w1, w2, [x0]
|
||||
1: msr fpcr, x1
|
||||
msr fpsr, x2
|
||||
mov w0, #0
|
||||
ret
|
||||
@@ -0,0 +1,67 @@
|
||||
// vim: ft=arm64asm
|
||||
|
||||
.extern __sigsetjmp
|
||||
|
||||
.type __setjmp, "function"
|
||||
__setjmp:
|
||||
stp x19, x20, [x0, #0]
|
||||
stp x21, x22, [x0, #16]
|
||||
stp x23, x24, [x0, #32]
|
||||
stp x25, x26, [x0, #48]
|
||||
stp x27, x28, [x0, #64]
|
||||
stp x29, x30, [x0, #80]
|
||||
mov x4, sp
|
||||
str x4, [x0, #96]
|
||||
|
||||
stp d8, d9, [x0, #112]
|
||||
stp d10, d11, [x0, #128]
|
||||
stp d12, d13, [x0, #144]
|
||||
stp d14, d15, [x0, #160]
|
||||
|
||||
cbnz x2, 1f
|
||||
|
||||
mov x0, xzr
|
||||
ret
|
||||
1:
|
||||
b __sigsetjmp
|
||||
|
||||
.global setjmp
|
||||
.type setjmp, "function"
|
||||
.global _setjmp
|
||||
.type _setjmp, "function"
|
||||
setjmp:
|
||||
_setjmp:
|
||||
mov x2, xzr
|
||||
b __setjmp
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, "function"
|
||||
sigsetjmp:
|
||||
mov x2, #1
|
||||
b __setjmp
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, "function"
|
||||
.global _longjmp
|
||||
.type _longjmp, "function"
|
||||
longjmp:
|
||||
_longjmp:
|
||||
ldp x19, x20, [x0, #0]
|
||||
ldp x21, x22, [x0, #16]
|
||||
ldp x23, x24, [x0, #32]
|
||||
ldp x25, x26, [x0, #48]
|
||||
ldp x27, x28, [x0, #64]
|
||||
ldp x29, x30, [x0, #80]
|
||||
ldr x4, [x0, #96]
|
||||
mov sp, x4
|
||||
|
||||
ldp d8, d9, [x0, #112]
|
||||
ldp d10, d11, [x0, #128]
|
||||
ldp d12, d13, [x0, #144]
|
||||
ldp d14, d15, [x0, #160]
|
||||
|
||||
cmp w1, 0
|
||||
csinc w0, w1, wzr, ne
|
||||
br x30
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
|
||||
// The cxxabi needs operator delete for *deleting* destructors, i.e., destructors that
|
||||
// are called by delete expressions. We never use such expressions in mlibc.
|
||||
// Note that G++ complains if we make the operator hidden,
|
||||
// thus we use it's mangled name as a workaround.
|
||||
#if defined(__clang__)
|
||||
extern "C" [[gnu::visibility("hidden")]] void _ZdlPv() { // operator delete (void *, size_t)
|
||||
__ensure(!"operator delete called! delete expressions cannot be used in mlibc.");
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]] void _ZdlPvj() { // operator delete (void *, unsigned int)
|
||||
__ensure(!"operator delete called! delete expressions cannot be used in mlibc.");
|
||||
}
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]] void _ZdlPvm() { // operator delete (void *, size_t)
|
||||
__ensure(!"operator delete called! delete expressions cannot be used in mlibc.");
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
#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;
|
||||
// padding to ensure correct alignment on certain platforms.
|
||||
uint8_t padding[3];
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <frg/eternal.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
#include <internal-config.h>
|
||||
|
||||
#if !MLIBC_DEBUG_ALLOCATOR
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Globals
|
||||
// --------------------------------------------------------
|
||||
|
||||
MemoryAllocator &getAllocator() {
|
||||
// use frg::eternal to prevent a call to __cxa_atexit().
|
||||
// this is necessary because __cxa_atexit() call this function.
|
||||
static frg::eternal<VirtualAllocator> virtualAllocator;
|
||||
static frg::eternal<MemoryPool> heap{virtualAllocator.get()};
|
||||
static frg::eternal<MemoryAllocator> singleton{&heap.get()};
|
||||
return singleton.get();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// VirtualAllocator
|
||||
// --------------------------------------------------------
|
||||
|
||||
uintptr_t VirtualAllocator::map(size_t length) {
|
||||
void *ptr;
|
||||
__ensure(!mlibc::sys_anon_allocate(length, &ptr));
|
||||
return (uintptr_t)ptr;
|
||||
}
|
||||
|
||||
void VirtualAllocator::unmap(uintptr_t address, size_t length) {
|
||||
__ensure(!mlibc::sys_anon_free((void *)address, length));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace {
|
||||
struct AllocatorMeta {
|
||||
size_t allocatedSize;
|
||||
size_t pagesSize;
|
||||
frg::array<uint64_t, 4> magic;
|
||||
};
|
||||
|
||||
constexpr frg::array<uint64_t, 4> allocatorMagic {
|
||||
0x6d4bbb9f3446e83f, 0x25e213a7a7f9f954,
|
||||
0x1a3c667586538bef, 0x994f34ff71c090bc
|
||||
};
|
||||
} // namespace anonymous
|
||||
|
||||
// Turn vm_unmap calls in free into vm_map(..., PROT_NONE, ...) calls to prevent
|
||||
// those addresses from being reused. This is useful for detecting situations like this:
|
||||
// 1. Allocate object X at address Y
|
||||
// 2. Do some computation using object X
|
||||
// 3. Free object X at address Y
|
||||
// 4. Allocate object Z at address W, and it so happens that W == Y
|
||||
// 5. Try to use object X, but the memory which was backing it now contains object Z
|
||||
constexpr bool neverReleaseVa = false;
|
||||
constexpr bool logAllocations = false;
|
||||
|
||||
// Area before the returned allocated block (which exists due to us offseting
|
||||
// the block to be as close to the edge of a page).
|
||||
constexpr uint8_t offsetAreaValue = 'A';
|
||||
// Area which we return a pointer to in allocate and reallocate.
|
||||
constexpr uint8_t allocatedAreaValue = 'B';
|
||||
// Area after the allocated block, which exists due to the alignment constraints.
|
||||
constexpr uint8_t alignmentAreaValue = 'C';
|
||||
// Remaining area within the metadata page after the metadata.
|
||||
constexpr uint8_t metaAreaValue = 'D';
|
||||
|
||||
// Alignment of the returned memory.
|
||||
// TODO(qookie): Eventually accept alignment as an argument of allocate.
|
||||
constexpr size_t pointerAlignment = 16;
|
||||
|
||||
// TODO(qookie): Support this. Perhaps by overallocating by 2x and then picking
|
||||
// an offset that guarantees the desired alignment.
|
||||
static_assert(pointerAlignment <= 4096, "Pointer aligment of more than 4096 bytes is unsupported");
|
||||
static_assert(!(pointerAlignment & (pointerAlignment - 1)),
|
||||
"Pointer aligment must be a power of 2");
|
||||
|
||||
constexpr size_t pageSize = 0x1000;
|
||||
|
||||
void *MemoryAllocator::allocate(size_t size) {
|
||||
size_t pg_size = (size + size_t{pageSize - 1}) & ~size_t{pageSize - 1};
|
||||
size_t offset = (pg_size - size) & ~size_t{pointerAlignment - 1};
|
||||
|
||||
void *ptr;
|
||||
|
||||
// Two extra pages for metadata in front and guard page at the end
|
||||
// Reserve the whole region as PROT_NONE...
|
||||
if (int e = mlibc::sys_vm_map(nullptr, pg_size + pageSize * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0, &ptr))
|
||||
mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::allocate (errno " << e << ")" << frg::endlog;
|
||||
|
||||
// ...Then replace pages to make them accessible, excluding the guard page
|
||||
if (int e = mlibc::sys_vm_map(ptr, pg_size + pageSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0, &ptr))
|
||||
mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::allocate (errno " << e << ")" << frg::endlog;
|
||||
|
||||
void *meta = ptr;
|
||||
void *out_page = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(ptr) + pageSize);
|
||||
void *out = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(out_page) + offset);
|
||||
void *out_align_area = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(out) + size);
|
||||
|
||||
AllocatorMeta metaData{size, pg_size, allocatorMagic};
|
||||
|
||||
memset(meta, metaAreaValue, pageSize);
|
||||
memcpy(meta, &metaData, sizeof(AllocatorMeta));
|
||||
|
||||
memset(out_page, offsetAreaValue, offset);
|
||||
memset(out, allocatedAreaValue, size);
|
||||
memset(out_align_area, alignmentAreaValue, pg_size - offset - size);
|
||||
|
||||
if constexpr (logAllocations)
|
||||
mlibc::infoLogger() << "MemoryAllocator::allocate(" << size << ") = " << out << frg::endlog;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void MemoryAllocator::free(void *ptr) {
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
if constexpr (logAllocations)
|
||||
mlibc::infoLogger() << "MemoryAllocator::free(" << ptr << ")" << frg::endlog;
|
||||
|
||||
uintptr_t page_addr = reinterpret_cast<uintptr_t>(ptr) & ~size_t{pageSize - 1};
|
||||
AllocatorMeta *meta = reinterpret_cast<AllocatorMeta *>(page_addr - pageSize);
|
||||
|
||||
if (meta->magic != allocatorMagic)
|
||||
mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::free" << frg::endlog;
|
||||
|
||||
deallocate(ptr, meta->allocatedSize);
|
||||
}
|
||||
|
||||
void MemoryAllocator::deallocate(void *ptr, size_t size) {
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
if constexpr (logAllocations)
|
||||
mlibc::infoLogger() << "MemoryAllocator::deallocate(" << ptr << ", " << size << ")" << frg::endlog;
|
||||
|
||||
uintptr_t page_addr = reinterpret_cast<uintptr_t>(ptr) & ~size_t{pageSize - 1};
|
||||
AllocatorMeta *meta = reinterpret_cast<AllocatorMeta *>(page_addr - pageSize);
|
||||
|
||||
if (meta->magic != allocatorMagic)
|
||||
mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::deallocate" << frg::endlog;
|
||||
|
||||
if (size != meta->allocatedSize)
|
||||
mlibc::panicLogger() << "Invalid allocated size in metadata in MemoryAllocator::deallocate (given " << size << ", stored " << meta->allocatedSize << ")" << frg::endlog;
|
||||
|
||||
if constexpr (neverReleaseVa) {
|
||||
void *unused;
|
||||
if (int e = mlibc::sys_vm_map(meta, meta->pagesSize + pageSize * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0, &unused))
|
||||
mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::deallocate (errno " << e << ")" << frg::endlog;
|
||||
} else {
|
||||
if (int e = mlibc::sys_vm_unmap(meta, meta->pagesSize + pageSize * 2))
|
||||
mlibc::panicLogger() << "sys_vm_unmap failed in MemoryAllocator::deallocate (errno " << e << ")" << frg::endlog;
|
||||
}
|
||||
}
|
||||
|
||||
void *MemoryAllocator::reallocate(void *ptr, size_t size) {
|
||||
if (!size) {
|
||||
free(ptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *newArea = allocate(size);
|
||||
|
||||
if (ptr) {
|
||||
uintptr_t page_addr = reinterpret_cast<uintptr_t>(ptr) & ~size_t{pageSize - 1};
|
||||
AllocatorMeta *meta = reinterpret_cast<AllocatorMeta *>(page_addr - pageSize);
|
||||
|
||||
if (meta->magic != allocatorMagic)
|
||||
mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::reallocate" << frg::endlog;
|
||||
|
||||
memcpy(newArea, ptr, frg::min(meta->allocatedSize, size));
|
||||
|
||||
deallocate(ptr, meta->allocatedSize);
|
||||
}
|
||||
|
||||
if constexpr (logAllocations)
|
||||
mlibc::infoLogger() << "MemoryAllocator::reallocate(" << ptr << ", " << size << ") = " << newArea << frg::endlog;
|
||||
|
||||
return newArea;
|
||||
}
|
||||
|
||||
size_t MemoryAllocator::get_size(void *ptr) {
|
||||
if constexpr (logAllocations)
|
||||
mlibc::infoLogger() << "MemoryAllocator::get_size(" << ptr << ")" << frg::endlog;
|
||||
|
||||
uintptr_t page_addr = reinterpret_cast<uintptr_t>(ptr) & ~size_t{pageSize - 1};
|
||||
AllocatorMeta *meta = reinterpret_cast<AllocatorMeta *>(page_addr - pageSize);
|
||||
|
||||
if (meta->magic != allocatorMagic)
|
||||
mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::get_size" << frg::endlog;
|
||||
|
||||
return meta->allocatedSize;
|
||||
}
|
||||
|
||||
MemoryAllocator &getAllocator() {
|
||||
// use frg::eternal to prevent a call to __cxa_atexit().
|
||||
// this is necessary because __cxa_atexit() call this function.
|
||||
static frg::eternal<MemoryAllocator> singleton{};
|
||||
return singleton.get();
|
||||
}
|
||||
|
||||
#endif /* !MLIBC_DEBUG_ALLOCATOR */
|
||||
@@ -0,0 +1,268 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <frg/string.hpp>
|
||||
#include <mlibc/charcode.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct utf8_charcode {
|
||||
static constexpr bool preserves_7bit_units = true;
|
||||
static constexpr bool has_shift_states = false;
|
||||
|
||||
struct decode_state {
|
||||
decode_state()
|
||||
: _progress{0}, _cpoint{0} { }
|
||||
|
||||
auto progress() { return _progress; }
|
||||
auto cpoint() { return _cpoint; }
|
||||
|
||||
charcode_error operator() (code_seq<const char> &seq) {
|
||||
auto uc = static_cast<unsigned char>(*seq.it);
|
||||
if(!_progress) {
|
||||
if(!(uc & 0b1000'0000)) {
|
||||
// ASCII-compatible.
|
||||
_cpoint = uc;
|
||||
}else if((uc & 0b1110'0000) == 0b1100'0000) {
|
||||
_cpoint = uc & 0b1'1111;
|
||||
_progress = 1;
|
||||
}else if((uc & 0b1111'0000) == 0b1110'0000) {
|
||||
_cpoint = uc & 0b1111;
|
||||
_progress = 2;
|
||||
}else if((uc & 0b1111'1000) == 0b1111'0000) {
|
||||
_cpoint = uc & 0b111;
|
||||
_progress = 3;
|
||||
}else{
|
||||
// If the highest two bits are 0b10, this is the second (or later) unit.
|
||||
// Units with highest five bits = 0b11111 do not occur in valid UTF-8.
|
||||
__ensure((uc & 0b1100'0000) == 0b1000'0000
|
||||
|| (uc & 0b1111'1000) == 0b1111'1000);
|
||||
return charcode_error::illegal_input;
|
||||
}
|
||||
}else{
|
||||
// TODO: Return an error.
|
||||
__ensure((uc & 0b1100'0000) == 0b1000'0000);
|
||||
_cpoint = (_cpoint << 6) | (uc & 0x3F);
|
||||
--_progress;
|
||||
}
|
||||
++seq.it;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
private:
|
||||
int _progress;
|
||||
codepoint _cpoint;
|
||||
};
|
||||
|
||||
#define NSEQ_STORE(VAL) do { \
|
||||
if (!static_cast<bool>(nseq)) { \
|
||||
return charcode_error::output_overflow; \
|
||||
} \
|
||||
*nseq.it = (VAL); \
|
||||
++nseq.it; \
|
||||
} while (0)
|
||||
|
||||
struct encode_state {
|
||||
// Encodes a single character from wseq + the current state and stores it in nseq.
|
||||
// TODO: Convert decode_state to the same strategy.
|
||||
charcode_error operator() (code_seq<char> &nseq, code_seq<const codepoint> &wseq) {
|
||||
auto wc = *wseq.it;
|
||||
if (wc <= 0x7F) {
|
||||
NSEQ_STORE(wc);
|
||||
} else if (wc <= 0x7FF) {
|
||||
NSEQ_STORE(0xC0 | (wc >> 6));
|
||||
NSEQ_STORE(0x80 | (wc & 0x3f));
|
||||
} else if (wc <= 0xFFFF) {
|
||||
NSEQ_STORE(0xE0 | (wc >> 12));
|
||||
NSEQ_STORE(0x80 | ((wc >> 6) & 0x3f));
|
||||
NSEQ_STORE(0x80 | (wc & 0x3f));
|
||||
} else if (wc <= 0x10FFFF) {
|
||||
NSEQ_STORE(0xF0 | (wc >> 18));
|
||||
NSEQ_STORE(0x80 | ((wc >> 12) & 0x3f));
|
||||
NSEQ_STORE(0x80 | ((wc >> 6) & 0x3f));
|
||||
NSEQ_STORE(0x80 | (wc & 0x3f));
|
||||
} else {
|
||||
return charcode_error::illegal_input;
|
||||
}
|
||||
++wseq.it;
|
||||
return charcode_error::null;
|
||||
}
|
||||
};
|
||||
|
||||
#undef NSEQ_STORE
|
||||
};
|
||||
|
||||
polymorphic_charcode::~polymorphic_charcode() = default;
|
||||
|
||||
// For *decoding, this class assumes that:
|
||||
// - G::decode_state has members progress() and cpoint().
|
||||
// - G::decode_state::progress() >= 0 at all times.
|
||||
// TODO: This will be needed on platforms like Windows, where wchar_t is UTF-16.
|
||||
// TODO: There, we can use negative __mlibc_mbstate::progress to represent encoding to UTF-16.
|
||||
// - If G::decode_state::progress() == 0, the code point (given by cpoint())
|
||||
// was decoded successfully.
|
||||
template<typename G>
|
||||
struct polymorphic_charcode_adapter : polymorphic_charcode {
|
||||
polymorphic_charcode_adapter()
|
||||
: polymorphic_charcode{G::preserves_7bit_units, G::has_shift_states} { }
|
||||
|
||||
charcode_error decode(code_seq<const char> &nseq, code_seq<codepoint> &wseq,
|
||||
__mlibc_mbstate &st) override {
|
||||
__ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint().
|
||||
|
||||
code_seq<const char> decode_nseq = nseq;
|
||||
typename G::decode_state ds;
|
||||
|
||||
while(decode_nseq && wseq) {
|
||||
// Consume the next code unit.
|
||||
if(auto e = ds(decode_nseq); e != charcode_error::null)
|
||||
return e;
|
||||
|
||||
// Produce a new code point.
|
||||
if(!ds.progress()) {
|
||||
// "Commit" consumed code units (as there was no decode error).
|
||||
nseq.it = decode_nseq.it;
|
||||
if(!ds.cpoint()) // Stop on null characters.
|
||||
return charcode_error::null;
|
||||
*wseq.it = ds.cpoint();
|
||||
++wseq.it;
|
||||
}
|
||||
}
|
||||
|
||||
if(ds.progress())
|
||||
return charcode_error::input_underflow;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
charcode_error decode_wtranscode(code_seq<const char> &nseq, code_seq<wchar_t> &wseq,
|
||||
__mlibc_mbstate &st) override {
|
||||
__ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint().
|
||||
|
||||
code_seq<const char> decode_nseq = nseq;
|
||||
typename G::decode_state ds;
|
||||
|
||||
while(decode_nseq && wseq) {
|
||||
// Consume the next code unit.
|
||||
if(auto e = ds(decode_nseq); e != charcode_error::null)
|
||||
return e;
|
||||
|
||||
// Produce a new code point.
|
||||
if(!ds.progress()) {
|
||||
nseq.it = decode_nseq.it;
|
||||
// "Commit" consumed code units (as there was no decode error).
|
||||
if(!ds.cpoint()) // Stop on null characters.
|
||||
return charcode_error::null;
|
||||
*wseq.it = ds.cpoint();
|
||||
++wseq.it;
|
||||
}
|
||||
}
|
||||
|
||||
if(ds.progress())
|
||||
return charcode_error::input_underflow;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
charcode_error decode_wtranscode_length(code_seq<const char> &nseq, size_t *n,
|
||||
__mlibc_mbstate &st) override {
|
||||
__ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint().
|
||||
|
||||
code_seq<const char> decode_nseq = nseq;
|
||||
typename G::decode_state ds;
|
||||
|
||||
*n = 0;
|
||||
while(decode_nseq) {
|
||||
// Consume the next code unit.
|
||||
if(auto e = ds(decode_nseq); e != charcode_error::null)
|
||||
return e;
|
||||
|
||||
if(!ds.progress()) {
|
||||
nseq.it = decode_nseq.it;
|
||||
// "Commit" consumed code units (as there was no decode error).
|
||||
if(!ds.cpoint()) // Stop on null code points.
|
||||
return charcode_error::null;
|
||||
++(*n);
|
||||
}
|
||||
}
|
||||
|
||||
if(ds.progress())
|
||||
return charcode_error::input_underflow;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
charcode_error encode_wtranscode(code_seq<char> &nseq, code_seq<const wchar_t> &wseq,
|
||||
__mlibc_mbstate &st) override {
|
||||
__ensure(!st.__progress); // TODO: Update st with es.progress() and es.cpoint().
|
||||
|
||||
code_seq<char> encode_nseq = nseq;
|
||||
typename G::encode_state es;
|
||||
|
||||
while(encode_nseq && wseq) {
|
||||
codepoint cp = *wseq.it;
|
||||
if(!cp)
|
||||
return charcode_error::null;
|
||||
|
||||
code_seq<const codepoint> cps{&cp, &cp + 1};
|
||||
if(auto e = es(encode_nseq, cps); e == charcode_error::dirty) {
|
||||
continue;
|
||||
}else if(e != charcode_error::null) {
|
||||
return e;
|
||||
}
|
||||
__ensure(cps.it == cps.end);
|
||||
++wseq.it;
|
||||
|
||||
// "Commit" produced code units (as there was no encode error).
|
||||
nseq.it = encode_nseq.it;
|
||||
}
|
||||
|
||||
if(encode_nseq.it != nseq.it)
|
||||
return charcode_error::output_overflow;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
charcode_error encode_wtranscode_length(code_seq<const wchar_t> &wseq, size_t *n,
|
||||
__mlibc_mbstate &st) override {
|
||||
__ensure(!st.__progress); // TODO: Update st with es.progress() and es.cpoint().
|
||||
|
||||
typename G::encode_state es;
|
||||
|
||||
*n = 0;
|
||||
while(wseq) {
|
||||
char temp[4];
|
||||
code_seq<char> encode_nseq{temp, temp + 4};
|
||||
codepoint cp = *wseq.it;
|
||||
if(!cp)
|
||||
return charcode_error::null;
|
||||
// Consume the next code unit.
|
||||
code_seq<const codepoint> cps{&cp, &cp + 1};
|
||||
if(auto e = es(encode_nseq, cps); e == charcode_error::dirty) {
|
||||
continue;
|
||||
}else if(e != charcode_error::null) {
|
||||
return e;
|
||||
}
|
||||
|
||||
++(*n);
|
||||
++wseq.it;
|
||||
}
|
||||
|
||||
return charcode_error::null;
|
||||
}
|
||||
};
|
||||
|
||||
polymorphic_charcode *current_charcode() {
|
||||
static polymorphic_charcode_adapter<utf8_charcode> global_charcode;
|
||||
return &global_charcode;
|
||||
}
|
||||
|
||||
charcode_error wide_charcode::promote(wchar_t nc, codepoint &wc) {
|
||||
// TODO: Allow non-identity encodings of wchar_t.
|
||||
wc = nc;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
wide_charcode *platform_wide_charcode() {
|
||||
static wide_charcode global_wide_charcode;
|
||||
return &global_wide_charcode;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/charset.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
bool charset::is_ascii_superset() {
|
||||
// TODO: For locales that change the meaning of ASCII chars, this needs to be changed.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool charset::is_alpha(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_alpha() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_digit(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return c >= '0' && c <= '9';
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_digit() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_xdigit(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_xdigit() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_alnum(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_alnum() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_punct(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return c == '!' || c == '"' || c == '#' || c == '$' || c == '%' || c == '&'
|
||||
|| c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ','
|
||||
|| c == '-' || c == '.' || c == '/'
|
||||
|| c == ':' || c == ';' || c == '<' || c == '=' || c == '>' || c == '?'
|
||||
|| c == '@'
|
||||
|| c == '[' || c == '\\' || c == ']' || c == '^' || c == '_' || c == '`'
|
||||
|| c == '{' || c == '|' || c == '}' || c == '~';
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_punct() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_graph(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return c >= 0x21 && c <= 0x7E;
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_graph() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_blank(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return c == ' ' || c == '\t';
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_blank() is not implemented"
|
||||
" for the full Unicode charset " << c << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_space(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_space() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_print(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return c >= 0x20 && c <= 0x7E;
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_lower(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return (c >= 'a' && c <= 'z');
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool charset::is_upper(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
return (c >= 'A' && c <= 'Z');
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return false;
|
||||
}
|
||||
|
||||
codepoint charset::to_lower(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
if(c >= 'A' && c <= 'Z')
|
||||
return c - 'A' + 'a';
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::to_lower() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return c;
|
||||
}
|
||||
|
||||
codepoint charset::to_upper(codepoint c) {
|
||||
if(c <= 0x7F && is_ascii_superset())
|
||||
if(c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 'A';
|
||||
if(c > 0x7F)
|
||||
mlibc::infoLogger() << "mlibc: charset::to_upper() is not implemented"
|
||||
" for the full Unicode charset" << frg::endlog;
|
||||
return c;
|
||||
}
|
||||
|
||||
charset *current_charset() {
|
||||
static charset global_charset;
|
||||
return &global_charset;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
frg::stack_buffer_logger<InfoSink, 512> infoLogger;
|
||||
frg::stack_buffer_logger<PanicSink, 512> panicLogger;
|
||||
|
||||
void InfoSink::operator() (const char *message) {
|
||||
sys_libc_log(message);
|
||||
}
|
||||
|
||||
void PanicSink::operator() (const char *message) {
|
||||
// sys_libc_log("mlibc: Write to PanicSink");
|
||||
sys_libc_log(message);
|
||||
sys_libc_panic();
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
void __ensure_fail(const char *assertion, const char *file, unsigned int line,
|
||||
const char *function) {
|
||||
mlibc::panicLogger() << "In function " << function
|
||||
<< ", file " << file << ":" << line << "\n"
|
||||
<< "__ensure(" << assertion << ") failed" << frg::endlog;
|
||||
}
|
||||
|
||||
void __ensure_warn(const char *assertion, const char *file, unsigned int line,
|
||||
const char *function) {
|
||||
mlibc::infoLogger() << "In function " << function
|
||||
<< ", file " << file << ":" << line << "\n"
|
||||
<< "__ensure(" << assertion << ") failed" << frg::endlog;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace {
|
||||
template<typename T>
|
||||
[[gnu::always_inline]]
|
||||
inline T alias_load(const unsigned char *&p) {
|
||||
T value;
|
||||
__builtin_memcpy(&value, p, sizeof(value));
|
||||
p += sizeof(T);
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[gnu::always_inline]]
|
||||
inline void alias_store(unsigned char *&p, T value) {
|
||||
__builtin_memcpy(p, &value, sizeof(value));
|
||||
p += sizeof(T);
|
||||
}
|
||||
|
||||
#if defined(__LP64__) && !defined(__riscv)
|
||||
void *forward_copy(void *__restrict dest, const void *__restrict src, size_t n) {
|
||||
auto curDest = reinterpret_cast<unsigned char *>(dest);
|
||||
auto curSrc = reinterpret_cast<const unsigned char *>(src);
|
||||
|
||||
while(n >= 8 * 8) {
|
||||
auto w1 = alias_load<uint64_t>(curSrc);
|
||||
auto w2 = alias_load<uint64_t>(curSrc);
|
||||
auto w3 = alias_load<uint64_t>(curSrc);
|
||||
auto w4 = alias_load<uint64_t>(curSrc);
|
||||
auto w5 = alias_load<uint64_t>(curSrc);
|
||||
auto w6 = alias_load<uint64_t>(curSrc);
|
||||
auto w7 = alias_load<uint64_t>(curSrc);
|
||||
auto w8 = alias_load<uint64_t>(curSrc);
|
||||
alias_store<uint64_t>(curDest, w1);
|
||||
alias_store<uint64_t>(curDest, w2);
|
||||
alias_store<uint64_t>(curDest, w3);
|
||||
alias_store<uint64_t>(curDest, w4);
|
||||
alias_store<uint64_t>(curDest, w5);
|
||||
alias_store<uint64_t>(curDest, w6);
|
||||
alias_store<uint64_t>(curDest, w7);
|
||||
alias_store<uint64_t>(curDest, w8);
|
||||
n -= 8 * 8;
|
||||
}
|
||||
if(n >= 4 * 8) {
|
||||
auto w1 = alias_load<uint64_t>(curSrc);
|
||||
auto w2 = alias_load<uint64_t>(curSrc);
|
||||
auto w3 = alias_load<uint64_t>(curSrc);
|
||||
auto w4 = alias_load<uint64_t>(curSrc);
|
||||
alias_store<uint64_t>(curDest, w1);
|
||||
alias_store<uint64_t>(curDest, w2);
|
||||
alias_store<uint64_t>(curDest, w3);
|
||||
alias_store<uint64_t>(curDest, w4);
|
||||
n -= 4 * 8;
|
||||
}
|
||||
if(n >= 2 * 8) {
|
||||
auto w1 = alias_load<uint64_t>(curSrc);
|
||||
auto w2 = alias_load<uint64_t>(curSrc);
|
||||
alias_store<uint64_t>(curDest, w1);
|
||||
alias_store<uint64_t>(curDest, w2);
|
||||
n -= 2 * 8;
|
||||
}
|
||||
if(n >= 8) {
|
||||
auto w = alias_load<uint64_t>(curSrc);
|
||||
alias_store<uint64_t>(curDest, w);
|
||||
n -= 8;
|
||||
}
|
||||
if(n >= 4) {
|
||||
auto w = alias_load<uint32_t>(curSrc);
|
||||
alias_store<uint32_t>(curDest, w);
|
||||
n -= 4;
|
||||
}
|
||||
if(n >= 2) {
|
||||
auto w = alias_load<uint16_t>(curSrc);
|
||||
alias_store<uint16_t>(curDest, w);
|
||||
n -= 2;
|
||||
}
|
||||
if(n)
|
||||
*curDest = *curSrc;
|
||||
return dest;
|
||||
}
|
||||
#else // !__LP64__
|
||||
void *forward_copy(void *dest, const void *src, size_t n) {
|
||||
for(size_t i = 0; i < n; i++)
|
||||
((char *)dest)[i] = ((const char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
#endif // __LP64__ / !__LP64__
|
||||
} // namespace
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// memcpy() implementation.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
void *memcpy(void *__restrict dest, const void *__restrict src, size_t n) {
|
||||
return forward_copy(dest, src, n);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// memset() implementation.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __LP64__
|
||||
|
||||
void *memset(void *dest, int val, size_t n) {
|
||||
auto curDest = reinterpret_cast<unsigned char *>(dest);
|
||||
unsigned char byte = val;
|
||||
|
||||
// Get rid of misalignment.
|
||||
while(n && (uintptr_t(curDest) & 7)) {
|
||||
*curDest++ = byte;
|
||||
--n;
|
||||
}
|
||||
|
||||
auto pattern64 = static_cast<uint64_t>(
|
||||
static_cast<uint64_t>(byte)
|
||||
| (static_cast<uint64_t>(byte) << 8)
|
||||
| (static_cast<uint64_t>(byte) << 16)
|
||||
| (static_cast<uint64_t>(byte) << 24)
|
||||
| (static_cast<uint64_t>(byte) << 32)
|
||||
| (static_cast<uint64_t>(byte) << 40)
|
||||
| (static_cast<uint64_t>(byte) << 48)
|
||||
| (static_cast<uint64_t>(byte) << 56));
|
||||
|
||||
auto pattern32 = static_cast<uint32_t>(
|
||||
static_cast<uint32_t>(byte)
|
||||
| (static_cast<uint32_t>(byte) << 8)
|
||||
| (static_cast<uint32_t>(byte) << 16)
|
||||
| (static_cast<uint32_t>(byte) << 24));
|
||||
|
||||
auto pattern16 = static_cast<uint16_t>(
|
||||
static_cast<uint16_t>(byte)
|
||||
| (static_cast<uint16_t>(byte) << 8));
|
||||
|
||||
while(n >= 8 * 8) {
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
n -= 8 * 8;
|
||||
}
|
||||
if(n >= 4 * 8) {
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
n -= 4 * 8;
|
||||
}
|
||||
if(n >= 2 * 8) {
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
n -= 2 * 8;
|
||||
}
|
||||
if(n >= 8) {
|
||||
alias_store<uint64_t>(curDest, pattern64);
|
||||
n -= 8;
|
||||
}
|
||||
if(n >= 4) {
|
||||
alias_store<uint32_t>(curDest, pattern32);
|
||||
n -= 4;
|
||||
}
|
||||
if(n >= 2) {
|
||||
alias_store<uint16_t>(curDest, pattern16);
|
||||
n -= 2;
|
||||
}
|
||||
if(n)
|
||||
*curDest = byte;
|
||||
return dest;
|
||||
}
|
||||
|
||||
#else // !__LP64__
|
||||
|
||||
void *memset(void *dest, int byte, size_t count) {
|
||||
for(size_t i = 0; i < count; i++)
|
||||
((char *)dest)[i] = (char)byte;
|
||||
return dest;
|
||||
}
|
||||
|
||||
#endif // __LP64__ / !__LP64__
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// "Non-optimized" functions.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t size) {
|
||||
// Use uintptr_t for pointer comparisons because otherwise it's undefined behaviour
|
||||
// when dest and src point to different objects.
|
||||
uintptr_t udest = reinterpret_cast<uintptr_t>(dest);
|
||||
uintptr_t usrc = reinterpret_cast<uintptr_t>(src);
|
||||
|
||||
if(udest < usrc || usrc + size <= udest) {
|
||||
return forward_copy(dest, src, size);
|
||||
} else if(udest > usrc) {
|
||||
char *dest_bytes = (char *)dest;
|
||||
char *src_bytes = (char *)src;
|
||||
|
||||
for(size_t i = 0; i < size; i++)
|
||||
dest_bytes[size - i - 1] = src_bytes[size - i - 1];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
size_t len = 0;
|
||||
for(size_t i = 0; s[i]; i++)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
|
||||
extern "C" void frg_panic(const char *mstr) {
|
||||
// mlibc::sys_libc_log("mlibc: Call to frg_panic");
|
||||
mlibc::sys_libc_log(mstr);
|
||||
mlibc::sys_libc_panic();
|
||||
}
|
||||
|
||||
extern "C" void frg_log(const char *mstr) {
|
||||
mlibc::sys_libc_log(mstr);
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
#include <assert.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <bits/getopt.h>
|
||||
#include <frg/optional.hpp>
|
||||
#include <mlibc-config.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/getopt.hpp>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <variant>
|
||||
|
||||
char *optarg;
|
||||
int optind = 1;
|
||||
int opterr = 1;
|
||||
int optopt;
|
||||
|
||||
namespace {
|
||||
|
||||
int __optpos = 1;
|
||||
|
||||
int getopt_common_internal(int argc, char * const argv[], const char *optstring, const struct option *longopts,
|
||||
int *longindex, enum mlibc::GetoptMode mode) {
|
||||
// find a matching longopt for an `arg` of length `n`
|
||||
// returns a size_t of the index of the matched longopt, preferring an exact over a partial match
|
||||
// returns a char of the error that getopt should return if multiple matches were available
|
||||
// returns a std::monostate if no longopt resulted in a exact or partial match
|
||||
auto longopt_find = [&](const char *arg, size_t n) -> std::variant<size_t, char, std::monostate> {
|
||||
assert(mode != mlibc::GetoptMode::Short);
|
||||
|
||||
frg::optional<size_t> i = frg::null_opt;
|
||||
|
||||
// first, attempt to find exactly one exact match
|
||||
for(size_t longopt = 0; longopts[longopt].name; longopt++) {
|
||||
if(strncmp(arg, longopts[longopt].name, n) || longopts[longopt].name[n])
|
||||
continue;
|
||||
|
||||
if(i) {
|
||||
if(opterr)
|
||||
fprintf(stderr, "Multiple option declaration detected: %s\n", arg);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
i = longopt;
|
||||
}
|
||||
|
||||
if(i)
|
||||
return *i;
|
||||
|
||||
// because no exact match was found, we now search for longopts with partial matches
|
||||
for(size_t longopt = 0; longopts[longopt].name; longopt++) {
|
||||
if(strncmp(arg, longopts[longopt].name, n))
|
||||
continue;
|
||||
|
||||
if(i) {
|
||||
if(opterr)
|
||||
fprintf(stderr, "Multiple option declaration detected: %s\n", arg);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
i = longopt;
|
||||
}
|
||||
|
||||
if(i)
|
||||
return *i;
|
||||
|
||||
return std::monostate{};
|
||||
};
|
||||
|
||||
auto longopt_consume = [&](const char *arg, char *s, int k, bool colon) -> frg::optional<int> {
|
||||
assert(mode != mlibc::GetoptMode::Short);
|
||||
|
||||
// Consume the option and its argument.
|
||||
if(longopts[k].has_arg == required_argument) {
|
||||
if(s) {
|
||||
// Consume the long option and its argument.
|
||||
optarg = s + 1;
|
||||
optind++;
|
||||
}else if(optind + 1 < argc && argv[optind + 1]) {
|
||||
// Consume the long option.
|
||||
optind++;
|
||||
|
||||
// Consume the option's argument.
|
||||
optarg = argv[optind];
|
||||
optind++;
|
||||
}else{
|
||||
/* If an error was detected, and the first character of optstring is not a colon,
|
||||
and the external variable opterr is nonzero (which is the default),
|
||||
getopt() prints an error message. */
|
||||
if(!colon && opterr)
|
||||
fprintf(stderr, "--%s requires an argument.\n", arg);
|
||||
|
||||
optopt = longopts[k].val;
|
||||
optind++;
|
||||
|
||||
/* If the first character of optstring is a colon (':'), then getopt()
|
||||
returns ':' instead of '?' to indicate a missing option argument. */
|
||||
return colon ? ':' : '?';
|
||||
}
|
||||
}else if(longopts[k].has_arg == optional_argument) {
|
||||
if(s) {
|
||||
// Consume the long option and its argument.
|
||||
optarg = s + 1;
|
||||
optind++;
|
||||
}else{
|
||||
// Consume the long option.
|
||||
optarg = nullptr;
|
||||
optind++;
|
||||
}
|
||||
}else{
|
||||
__ensure(longopts[k].has_arg == no_argument);
|
||||
|
||||
// did we get passed a value?
|
||||
if(s && strlen(s)) {
|
||||
optind++;
|
||||
return colon ? ':' : '?';
|
||||
}
|
||||
|
||||
// Consume the long option.
|
||||
optind++;
|
||||
optarg = nullptr;
|
||||
}
|
||||
|
||||
return frg::null_opt;
|
||||
};
|
||||
|
||||
bool colon = optstring[0] == ':';
|
||||
bool stop_at_first_nonarg = (optstring[0] == '+' || getenv("POSIXLY_CORRECT"));
|
||||
|
||||
// if optstring contains "W;", then "-W foo" is treated as the long option "--foo".
|
||||
bool w_long_options = [&]{
|
||||
if(mode == mlibc::GetoptMode::Short)
|
||||
return false;
|
||||
|
||||
const char *W = strchr(optstring, 'W');
|
||||
if (!W)
|
||||
return false;
|
||||
return W[1] == ';';
|
||||
}();
|
||||
|
||||
auto isOptionArg = [](char *arg){
|
||||
// If the first character of arg '-', and the arg is not exactly
|
||||
// equal to "-" or "--", then the arg is an option argument.
|
||||
return arg[0] == '-' && strcmp(arg, "-") && strcmp(arg, "--");
|
||||
};
|
||||
|
||||
while(optind < argc) {
|
||||
char *arg = argv[optind];
|
||||
if(!isOptionArg(arg)) {
|
||||
if(!strcmp(arg, "--")) {
|
||||
optind++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stop_at_first_nonarg) {
|
||||
optarg = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool further_options = false;
|
||||
int skip = optind;
|
||||
|
||||
for(; skip < argc; ++skip) {
|
||||
if(isOptionArg(argv[skip])) {
|
||||
further_options = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(further_options) {
|
||||
optind += skip - optind;
|
||||
continue;
|
||||
} else {
|
||||
optarg = nullptr;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(arg[1] == '-' && mode != mlibc::GetoptMode::Short) {
|
||||
arg += 2;
|
||||
|
||||
// Determine the end of the option name (vs. the start of the argument).
|
||||
auto s = strchr(arg, '=');
|
||||
size_t n = s ? (s - arg) : strlen(arg);
|
||||
|
||||
auto k = longopt_find(arg, n);
|
||||
if(std::holds_alternative<std::monostate>(k)) {
|
||||
if(opterr)
|
||||
fprintf(stderr, "--%s is not a valid option.\n", arg);
|
||||
optind++;
|
||||
return '?';
|
||||
} else if(std::holds_alternative<char>(k)) {
|
||||
return std::get<char>(k);
|
||||
}
|
||||
|
||||
if(longindex)
|
||||
*longindex = std::get<size_t>(k);
|
||||
|
||||
if(auto r = longopt_consume(arg, s, std::get<size_t>(k), colon); r)
|
||||
return r.value();
|
||||
|
||||
if(!longopts[std::get<size_t>(k)].flag) {
|
||||
return longopts[std::get<size_t>(k)].val;
|
||||
}else{
|
||||
*longopts[std::get<size_t>(k)].flag = longopts[std::get<size_t>(k)].val;
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
/* handle short options, i.e. options with only one dash prefixed; e.g. `program -s` */
|
||||
unsigned int i = __optpos;
|
||||
while(true) {
|
||||
if(mode == mlibc::GetoptMode::LongOnly) {
|
||||
const char *lo_arg = &arg[1];
|
||||
auto s = strchr(lo_arg, '=');
|
||||
size_t n = s ? (s - lo_arg) : strlen(lo_arg);
|
||||
|
||||
auto longopt_res = longopt_find(lo_arg, n);
|
||||
|
||||
if(std::holds_alternative<char>(longopt_res)) {
|
||||
return std::get<char>(longopt_res);
|
||||
} else if(std::holds_alternative<size_t>(longopt_res)) {
|
||||
auto k = std::get<size_t>(longopt_res);
|
||||
if(auto r = longopt_consume(lo_arg, s, k, colon); r)
|
||||
return r.value();
|
||||
|
||||
if(!longopts[k].flag) {
|
||||
return longopts[k].val;
|
||||
}else{
|
||||
*longopts[k].flag = longopts[k].val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto opt = strchr(optstring, arg[i]);
|
||||
if(opt) {
|
||||
if(opt[0] == 'W' && w_long_options) {
|
||||
const char *lo_arg = [&]() {
|
||||
if(opt[1]) {
|
||||
return &arg[i] + 1;
|
||||
} else {
|
||||
return &arg[i + 1];
|
||||
}
|
||||
}();
|
||||
|
||||
auto s = strchr(lo_arg, '=');
|
||||
size_t n = s ? (s - lo_arg) : strlen(lo_arg);
|
||||
|
||||
if(!n) {
|
||||
optopt = 'W';
|
||||
optind++;
|
||||
return colon ? ':' : '?';
|
||||
}
|
||||
|
||||
auto longopt_res = longopt_find(lo_arg, n);
|
||||
|
||||
if(std::holds_alternative<char>(longopt_res)) {
|
||||
return std::get<char>(longopt_res);
|
||||
} else if(std::holds_alternative<size_t>(longopt_res)) {
|
||||
auto k = std::get<size_t>(longopt_res);
|
||||
if(auto r = longopt_consume(lo_arg, s, k, colon); r)
|
||||
return r.value();
|
||||
|
||||
if(!longopts[k].flag) {
|
||||
return longopts[k].val;
|
||||
}else{
|
||||
*longopts[k].flag = longopts[k].val;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
optind++;
|
||||
return colon ? ':' : '?';
|
||||
}
|
||||
} else if(opt[1] == ':') {
|
||||
// one colon means the option requires an argument
|
||||
// two colons mean the option takes an optional argument as part of the
|
||||
// same argv element (in the same word as the option name itself)
|
||||
bool required = (opt[2] != ':');
|
||||
|
||||
if(arg[i+1]) {
|
||||
optarg = arg + i + 1;
|
||||
} else if(optind + 1 < argc && argv[optind + 1] && required && argv[optind + 1][0] != '-') {
|
||||
/* there is an argument to this short option, separated by a space,
|
||||
* and the shortopt specification does not specify an optional arg */
|
||||
optarg = argv[optind + 1];
|
||||
optind++;
|
||||
__optpos = 1;
|
||||
} else if(!required) {
|
||||
optarg = nullptr;
|
||||
} else {
|
||||
__optpos = 1;
|
||||
optopt = arg[i];
|
||||
return colon ? ':' : '?';
|
||||
}
|
||||
optind++;
|
||||
} else {
|
||||
if(arg[i+1]) {
|
||||
__optpos++;
|
||||
} else if(arg[i]) {
|
||||
optind++;
|
||||
} else {
|
||||
optarg = nullptr;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return arg[i];
|
||||
} else {
|
||||
/* If getopt() does not recognize an option character, it prints an error message to stderr,
|
||||
stores the character in optopt, and returns '?'. The calling program may prevent
|
||||
the error message by setting opterr to 0. */
|
||||
optopt = arg[1];
|
||||
if(opterr)
|
||||
fprintf(stderr, "%s is not a valid option.\n", arg);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optarg = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void permute(char **argv, int dest, int src) {
|
||||
assert(src > dest);
|
||||
char *tmp = argv[src];
|
||||
for(int i = src; i > dest; i--) {
|
||||
argv[i] = argv[i - 1];
|
||||
}
|
||||
argv[dest] = tmp;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if __MLIBC_BSD_OPTION
|
||||
extern "C" int optreset;
|
||||
#endif /*__MLIBC_BSD_OPTION */
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int getopt_common(int argc, char * const argv[], const char *optstring,
|
||||
const struct option *longopts, int *longindex, enum GetoptMode mode) {
|
||||
// glibc extension: Setting optind to zero causes a full reset.
|
||||
// TODO: Should we really reset opterr and the other flags?
|
||||
if(!optind
|
||||
#if __MLIBC_BSD_OPTION
|
||||
|| optreset
|
||||
#endif //__MLIBC_BSD_OPTION
|
||||
) {
|
||||
optarg = nullptr;
|
||||
optind = 1;
|
||||
optopt = 0;
|
||||
__optpos = 1;
|
||||
#if __MLIBC_BSD_OPTION
|
||||
optreset = 0;
|
||||
#endif //__MLIBC_BSD_OPTION
|
||||
}
|
||||
|
||||
int skipped = optind;
|
||||
|
||||
if(optstring[0] != '+' && optstring[0] != '-') {
|
||||
int i = optind;
|
||||
|
||||
for(;; i++) {
|
||||
if(i >= argc || !argv[i]) {
|
||||
optarg = nullptr;
|
||||
return -1;
|
||||
}
|
||||
if(argv[i][0] == '-' && argv[i][1])
|
||||
break;
|
||||
}
|
||||
|
||||
optind = i;
|
||||
}
|
||||
|
||||
int resumed = optind;
|
||||
auto ret = getopt_common_internal(argc, argv, optstring, longopts, longindex, mode);
|
||||
|
||||
if(resumed > skipped) {
|
||||
for(int i = 0; i < (optind - resumed); i++) {
|
||||
permute(const_cast<char **>(argv), skipped, optind - 1);
|
||||
}
|
||||
optind = skipped + (optind - resumed);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mlibc/global-config.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct GlobalConfigGuard {
|
||||
GlobalConfigGuard();
|
||||
};
|
||||
|
||||
GlobalConfigGuard guard;
|
||||
|
||||
GlobalConfigGuard::GlobalConfigGuard() {
|
||||
// Force the config to be created during initialization of libc.so.
|
||||
mlibc::globalConfig();
|
||||
}
|
||||
|
||||
static bool envEnabled(const char *env) {
|
||||
auto value = getenv(env);
|
||||
return value && *value && *value != '0';
|
||||
}
|
||||
|
||||
GlobalConfig::GlobalConfig() {
|
||||
debugMalloc = envEnabled("MLIBC_DEBUG_MALLOC");
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,16 @@
|
||||
// This translation unit provides symbols for functions marked with __MLIBC_INLINE_DEFINITION.
|
||||
// All headers with such functions must be included here.
|
||||
|
||||
#define __MLIBC_EMIT_INLINE_DEFINITIONS
|
||||
|
||||
#include <mlibc-config.h>
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
#include <sys/sysmacros.h>
|
||||
#endif /* __MLIBC_LINUX_OPTION */
|
||||
|
||||
#ifndef MLIBC_BUILDING_RTLD
|
||||
#include <math.h>
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/locale.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
char *nl_langinfo(nl_item item) {
|
||||
if(item == CODESET) {
|
||||
return const_cast<char *>("UTF-8");
|
||||
} else if(item >= ABMON_1 && item <= ABMON_12) {
|
||||
switch(item) {
|
||||
case ABMON_1: return const_cast<char *>("Jan");
|
||||
case ABMON_2: return const_cast<char *>("Feb");
|
||||
case ABMON_3: return const_cast<char *>("Mar");
|
||||
case ABMON_4: return const_cast<char *>("Apr");
|
||||
case ABMON_5: return const_cast<char *>("May");
|
||||
case ABMON_6: return const_cast<char *>("Jun");
|
||||
case ABMON_7: return const_cast<char *>("Jul");
|
||||
case ABMON_8: return const_cast<char *>("Aug");
|
||||
case ABMON_9: return const_cast<char *>("Sep");
|
||||
case ABMON_10: return const_cast<char *>("Oct");
|
||||
case ABMON_11: return const_cast<char *>("Nov");
|
||||
case ABMON_12: return const_cast<char *>("Dec");
|
||||
default:
|
||||
__ensure(!"ABMON_* constants don't seem to be contiguous!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
} else if(item >= MON_1 && item <= MON_12) {
|
||||
switch(item) {
|
||||
case MON_1: return const_cast<char *>("January");
|
||||
case MON_2: return const_cast<char *>("Feburary");
|
||||
case MON_3: return const_cast<char *>("March");
|
||||
case MON_4: return const_cast<char *>("April");
|
||||
case MON_5: return const_cast<char *>("May");
|
||||
case MON_6: return const_cast<char *>("June");
|
||||
case MON_7: return const_cast<char *>("July");
|
||||
case MON_8: return const_cast<char *>("August");
|
||||
case MON_9: return const_cast<char *>("September");
|
||||
case MON_10: return const_cast<char *>("October");
|
||||
case MON_11: return const_cast<char *>("November");
|
||||
case MON_12: return const_cast<char *>("December");
|
||||
default:
|
||||
__ensure(!"MON_* constants don't seem to be contiguous!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
} else if(item == AM_STR) {
|
||||
return const_cast<char *>("AM");
|
||||
} else if(item == PM_STR) {
|
||||
return const_cast<char *>("PM");
|
||||
} else if(item >= DAY_1 && item <= DAY_7) {
|
||||
switch(item) {
|
||||
case DAY_1: return const_cast<char *>("Sunday");
|
||||
case DAY_2: return const_cast<char *>("Monday");
|
||||
case DAY_3: return const_cast<char *>("Tuesday");
|
||||
case DAY_4: return const_cast<char *>("Wednesday");
|
||||
case DAY_5: return const_cast<char *>("Thursday");
|
||||
case DAY_6: return const_cast<char *>("Friday");
|
||||
case DAY_7: return const_cast<char *>("Saturday");
|
||||
default:
|
||||
__ensure(!"DAY_* constants don't seem to be contiguous!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
} else if(item >= ABDAY_1 && item <= ABDAY_7) {
|
||||
switch(item) {
|
||||
case ABDAY_1: return const_cast<char *>("Sun");
|
||||
case ABDAY_2: return const_cast<char *>("Mon");
|
||||
case ABDAY_3: return const_cast<char *>("Tue");
|
||||
case ABDAY_4: return const_cast<char *>("Wed");
|
||||
case ABDAY_5: return const_cast<char *>("Thu");
|
||||
case ABDAY_6: return const_cast<char *>("Fri");
|
||||
case ABDAY_7: return const_cast<char *>("Sat");
|
||||
default:
|
||||
__ensure(!"ABDAY_* constants don't seem to be contiguous!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}else if(item == D_FMT) {
|
||||
return const_cast<char *>("%m/%d/%y");
|
||||
}else if(item == T_FMT) {
|
||||
return const_cast<char *>("%H:%M:%S");
|
||||
}else if(item == T_FMT_AMPM) {
|
||||
return const_cast<char *>("%I:%M:%S %p");
|
||||
}else if(item == D_T_FMT) {
|
||||
return const_cast<char *>("%a %b %e %T %Y");
|
||||
} else if (item == RADIXCHAR) {
|
||||
return const_cast<char *>(".");
|
||||
} else if (item == THOUSEP) {
|
||||
return const_cast<char *>("");
|
||||
}else if(item == YESEXPR) {
|
||||
return const_cast<char *>("^[yY]");
|
||||
}else if(item == NOEXPR) {
|
||||
return const_cast<char *>("^[nN]");
|
||||
}else{
|
||||
mlibc::infoLogger() << "mlibc: nl_langinfo item "
|
||||
<< item << " is not implemented properly" << frg::endlog;
|
||||
return const_cast<char *>("");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,98 @@
|
||||
#include <mlibc/search.hpp>
|
||||
#include <frg/string.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct _ENTRY {
|
||||
ENTRY entry;
|
||||
bool used;
|
||||
};
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int hcreate_r(size_t num_entries, struct hsearch_data *htab) {
|
||||
if(!htab) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
htab->table = static_cast<_ENTRY*>(calloc(num_entries, sizeof(_ENTRY)));
|
||||
if(!htab->table) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
htab->filled = 0;
|
||||
htab->size = num_entries;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void hdestroy_r(struct hsearch_data *htab) {
|
||||
if(!htab) {
|
||||
errno = EINVAL;
|
||||
return;
|
||||
}
|
||||
free(htab->table);
|
||||
htab->table = nullptr;
|
||||
htab->size = 0;
|
||||
htab->filled = 0;
|
||||
}
|
||||
|
||||
|
||||
int hsearch_r(ENTRY item, ACTION action, ENTRY **ret, struct hsearch_data *htab) {
|
||||
auto key = frg::string_view{item.key};
|
||||
auto hash = frg::hash<frg::string_view>{}(key);
|
||||
|
||||
size_t bucket_index = hash % htab->size;
|
||||
size_t start = bucket_index;
|
||||
while(true) {
|
||||
auto &bucket = htab->table[bucket_index];
|
||||
|
||||
if(bucket.used) {
|
||||
if(bucket.entry.key == key) {
|
||||
*ret = &bucket.entry;
|
||||
return 1;
|
||||
}
|
||||
} else if(action == FIND) {
|
||||
errno = ESRCH;
|
||||
*ret = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bucket_index = (bucket_index + 1) % htab->size;
|
||||
|
||||
if(bucket_index == start) {
|
||||
if(action == FIND) {
|
||||
errno = ESRCH;
|
||||
*ret = nullptr;
|
||||
return 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insert a new entry.
|
||||
if(htab->size == htab->filled) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
++htab->filled;
|
||||
|
||||
bucket_index = start;
|
||||
while(true) {
|
||||
auto &bucket = htab->table[bucket_index];
|
||||
if(!bucket.used) {
|
||||
bucket.used = true;
|
||||
bucket.entry = item;
|
||||
*ret = &bucket.entry;
|
||||
break;
|
||||
}
|
||||
|
||||
bucket_index = (bucket_index + 1) % htab->size;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <bits/sigset_t.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace {
|
||||
|
||||
template<class T> struct remove_reference { typedef T type; };
|
||||
template<class T> struct remove_reference<T&> { typedef T type; };
|
||||
|
||||
// Assume that the struct has a member named 'sig'.
|
||||
template<typename T>
|
||||
struct sigset_type_helper {
|
||||
using type = typename remove_reference<decltype(T::sig[0])>::type;
|
||||
static_assert(offsetof(T, sig) == 0);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct sigset_type_helper<unsigned long> { using type = unsigned long; };
|
||||
|
||||
template<>
|
||||
struct sigset_type_helper<unsigned long long> { using type = unsigned long long; };
|
||||
|
||||
template<>
|
||||
struct sigset_type_helper<long> { using type = long; };
|
||||
|
||||
template<>
|
||||
struct sigset_type_helper<long long> { using type = long long; };
|
||||
|
||||
// Some ABIs define sigset_t as a simple integer (e.g unsigned long),
|
||||
// while others define it as a struct containing an array of integers.
|
||||
using sigset_underlying_type = sigset_type_helper<sigset_t>::type;
|
||||
|
||||
size_t signo_to_field(int signo) {
|
||||
return signo / (sizeof(sigset_underlying_type) * CHAR_BIT);
|
||||
}
|
||||
|
||||
size_t signo_to_bit(int signo) {
|
||||
return signo % (sizeof(sigset_underlying_type) * CHAR_BIT);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int sigemptyset(sigset_t *sigset) {
|
||||
memset(sigset, 0, sizeof(*sigset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigfillset(sigset_t *sigset) {
|
||||
memset(sigset, ~0, sizeof(*sigset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigaddset(sigset_t *sigset, int sig) {
|
||||
int signo = sig - 1;
|
||||
if(signo < 0 || static_cast<unsigned int>(signo) >= (sizeof(sigset_t) * CHAR_BIT)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
auto ptr = reinterpret_cast<sigset_underlying_type *>(sigset);
|
||||
auto field = signo_to_field(signo);
|
||||
auto bit = signo_to_bit(signo);
|
||||
ptr[field] |= (1UL << bit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigdelset(sigset_t *sigset, int sig) {
|
||||
int signo = sig - 1;
|
||||
if(signo < 0 || static_cast<unsigned int>(signo) >= (sizeof(sigset_t) * CHAR_BIT)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
auto ptr = reinterpret_cast<sigset_underlying_type *>(sigset);
|
||||
auto field = signo_to_field(signo);
|
||||
auto bit = signo_to_bit(signo);
|
||||
ptr[field] &= ~(1UL << bit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigismember(const sigset_t *sigset, int sig) {
|
||||
int signo = sig - 1;
|
||||
if(signo < 0 || static_cast<unsigned int>(signo) >= (sizeof(sigset_t) * CHAR_BIT)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
auto ptr = reinterpret_cast<const sigset_underlying_type *>(sigset);
|
||||
auto field = signo_to_field(signo);
|
||||
auto bit = signo_to_bit(signo);
|
||||
return (ptr[field] & (1UL << bit)) != 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <mlibc/strings.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int strncasecmp(const char *a, const char *b, size_t size) {
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
unsigned char a_byte = tolower(a[i]);
|
||||
unsigned char b_byte = tolower(b[i]);
|
||||
if(!a_byte && !b_byte)
|
||||
return 0;
|
||||
// If only one char is null, one of the following cases applies.
|
||||
if(a_byte < b_byte)
|
||||
return -1;
|
||||
if(a_byte > b_byte)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,346 @@
|
||||
#include <abi-bits/errno.h>
|
||||
#include <bits/threads.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/lock.hpp>
|
||||
#include <mlibc/threads.hpp>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
extern "C" Tcb *__rtld_allocateTcb();
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int thread_create(struct __mlibc_thread_data **__restrict thread, const struct __mlibc_threadattr *__restrict attrp, void *entry, void *__restrict user_arg, bool returns_int) {
|
||||
auto new_tcb = __rtld_allocateTcb();
|
||||
pid_t tid;
|
||||
struct __mlibc_threadattr attr = {};
|
||||
if (!attrp)
|
||||
thread_attr_init(&attr);
|
||||
else
|
||||
attr = *attrp;
|
||||
|
||||
if (attr.__mlibc_cpuset)
|
||||
mlibc::infoLogger() << "pthread_create(): cpuset is ignored!" << frg::endlog;
|
||||
if (attr.__mlibc_sigmaskset)
|
||||
mlibc::infoLogger() << "pthread_create(): sigmask is ignored!" << frg::endlog;
|
||||
|
||||
// TODO: due to alignment guarantees, the stackaddr and stacksize might change
|
||||
// when the stack is allocated. Currently this isn't propagated to the TCB,
|
||||
// but it should be.
|
||||
void *stack = attr.__mlibc_stackaddr;
|
||||
if (!mlibc::sys_prepare_stack) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
int ret = mlibc::sys_prepare_stack(&stack, entry,
|
||||
user_arg, new_tcb, &attr.__mlibc_stacksize, &attr.__mlibc_guardsize, &new_tcb->stackAddr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!mlibc::sys_clone) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
new_tcb->stackSize = attr.__mlibc_stacksize;
|
||||
new_tcb->guardSize = attr.__mlibc_guardsize;
|
||||
new_tcb->returnValueType = (returns_int) ? TcbThreadReturnValue::Integer : TcbThreadReturnValue::Pointer;
|
||||
new_tcb->isJoinable = (attr.__mlibc_detachstate == __MLIBC_THREAD_CREATE_JOINABLE);
|
||||
mlibc::sys_clone(new_tcb, &tid, stack);
|
||||
*thread = reinterpret_cast<struct __mlibc_thread_data *>(new_tcb);
|
||||
|
||||
__atomic_store_n(&new_tcb->tid, tid, __ATOMIC_RELAXED);
|
||||
mlibc::sys_futex_wake(&new_tcb->tid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_join(struct __mlibc_thread_data *thread, void *ret) {
|
||||
auto tcb = reinterpret_cast<Tcb *>(thread);
|
||||
|
||||
if(!tcb->isJoinable) {
|
||||
mlibc::infoLogger() << "mlibc: pthread_join() called on a detached thread" << frg::endlog;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (!__atomic_load_n(&tcb->isJoinable, __ATOMIC_ACQUIRE))
|
||||
return EINVAL;
|
||||
|
||||
while (!__atomic_load_n(&tcb->didExit, __ATOMIC_ACQUIRE)) {
|
||||
mlibc::sys_futex_wait(&tcb->didExit, 0, nullptr);
|
||||
}
|
||||
|
||||
if(ret && tcb->returnValueType == TcbThreadReturnValue::Pointer)
|
||||
*reinterpret_cast<void **>(ret) = tcb->returnValue.voidPtr;
|
||||
else if(ret && tcb->returnValueType == TcbThreadReturnValue::Integer)
|
||||
*reinterpret_cast<int *>(ret) = tcb->returnValue.intVal;
|
||||
|
||||
// FIXME: destroy tcb here, currently we leak it
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr size_t default_stacksize = 0x200000;
|
||||
static constexpr size_t default_guardsize = 4096;
|
||||
|
||||
int thread_attr_init(struct __mlibc_threadattr *attr) {
|
||||
*attr = __mlibc_threadattr{};
|
||||
attr->__mlibc_stacksize = default_stacksize;
|
||||
attr->__mlibc_guardsize = default_guardsize;
|
||||
attr->__mlibc_detachstate = __MLIBC_THREAD_CREATE_JOINABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr unsigned int mutexRecursive = 1;
|
||||
static constexpr unsigned int mutexErrorCheck = 2;
|
||||
|
||||
// TODO: either use uint32_t or determine the bit based on sizeof(int).
|
||||
static constexpr unsigned int mutex_owner_mask = (static_cast<uint32_t>(1) << 30) - 1;
|
||||
static constexpr unsigned int mutex_waiters_bit = static_cast<uint32_t>(1) << 31;
|
||||
|
||||
int thread_mutex_init(struct __mlibc_mutex *__restrict mutex,
|
||||
const struct __mlibc_mutexattr *__restrict attr) {
|
||||
auto type = attr ? attr->__mlibc_type : __MLIBC_THREAD_MUTEX_DEFAULT;
|
||||
auto robust = attr ? attr->__mlibc_robust : __MLIBC_THREAD_MUTEX_STALLED;
|
||||
auto protocol = attr ? attr->__mlibc_protocol : __MLIBC_THREAD_PRIO_NONE;
|
||||
auto pshared = attr ? attr->__mlibc_pshared : __MLIBC_THREAD_PROCESS_PRIVATE;
|
||||
|
||||
mutex->__mlibc_state = 0;
|
||||
mutex->__mlibc_recursion = 0;
|
||||
mutex->__mlibc_flags = 0;
|
||||
mutex->__mlibc_prioceiling = 0; // TODO: We don't implement this.
|
||||
|
||||
if(type == __MLIBC_THREAD_MUTEX_RECURSIVE) {
|
||||
mutex->__mlibc_flags |= mutexRecursive;
|
||||
}else if(type == __MLIBC_THREAD_MUTEX_ERRORCHECK) {
|
||||
mutex->__mlibc_flags |= mutexErrorCheck;
|
||||
}else{
|
||||
__ensure(type == __MLIBC_THREAD_MUTEX_NORMAL);
|
||||
}
|
||||
|
||||
// TODO: Other values aren't supported yet.
|
||||
__ensure(robust == __MLIBC_THREAD_MUTEX_STALLED);
|
||||
__ensure(protocol == __MLIBC_THREAD_PRIO_NONE);
|
||||
__ensure(pshared == __MLIBC_THREAD_PROCESS_PRIVATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_mutex_destroy(struct __mlibc_mutex *mutex) {
|
||||
__ensure(!mutex->__mlibc_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_mutex_lock(struct __mlibc_mutex *mutex) {
|
||||
unsigned int this_tid = mlibc::this_tid();
|
||||
unsigned int expected = 0;
|
||||
while(true) {
|
||||
if(!expected) {
|
||||
// Try to take the mutex here.
|
||||
if(__atomic_compare_exchange_n(&mutex->__mlibc_state,
|
||||
&expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) {
|
||||
__ensure(!mutex->__mlibc_recursion);
|
||||
mutex->__mlibc_recursion = 1;
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
// If this (recursive) mutex is already owned by us, increment the recursion level.
|
||||
if((expected & mutex_owner_mask) == this_tid) {
|
||||
if(!(mutex->__mlibc_flags & mutexRecursive)) {
|
||||
if (mutex->__mlibc_flags & mutexErrorCheck)
|
||||
return EDEADLK;
|
||||
else
|
||||
mlibc::panicLogger() << "mlibc: pthread_mutex deadlock detected!"
|
||||
<< frg::endlog;
|
||||
}
|
||||
++mutex->__mlibc_recursion;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wait on the futex if the waiters flag is set.
|
||||
if(expected & mutex_waiters_bit) {
|
||||
int e = mlibc::sys_futex_wait((int *)&mutex->__mlibc_state, expected, nullptr);
|
||||
|
||||
// If the wait returns EAGAIN, that means that the mutex_waiters_bit was just unset by
|
||||
// some other thread. In this case, we should loop back around.
|
||||
// Also do so in case of a signal being caught.
|
||||
if (e && e != EAGAIN && e != EINTR)
|
||||
mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog;
|
||||
|
||||
// Opportunistically try to take the lock after we wake up.
|
||||
expected = 0;
|
||||
}else{
|
||||
// Otherwise we have to set the waiters flag first.
|
||||
unsigned int desired = expected | mutex_waiters_bit;
|
||||
if(__atomic_compare_exchange_n((int *)&mutex->__mlibc_state,
|
||||
reinterpret_cast<int*>(&expected), desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
|
||||
expected = desired;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int thread_mutex_unlock(struct __mlibc_mutex *mutex) {
|
||||
// Decrement the recursion level and unlock if we hit zero.
|
||||
__ensure(mutex->__mlibc_recursion);
|
||||
if(--mutex->__mlibc_recursion)
|
||||
return 0;
|
||||
|
||||
auto flags = mutex->__mlibc_flags;
|
||||
|
||||
// Reset the mutex to the unlocked state.
|
||||
auto state = __atomic_exchange_n(&mutex->__mlibc_state, 0, __ATOMIC_RELEASE);
|
||||
|
||||
// After this point the mutex is unlocked, and therefore we cannot access its contents as it
|
||||
// may have been destroyed by another thread.
|
||||
|
||||
unsigned int this_tid = mlibc::this_tid();
|
||||
if ((flags & mutexErrorCheck) && (state & mutex_owner_mask) != this_tid)
|
||||
return EPERM;
|
||||
|
||||
if ((flags & mutexErrorCheck) && !(state & mutex_owner_mask))
|
||||
return EINVAL;
|
||||
|
||||
__ensure((state & mutex_owner_mask) == this_tid);
|
||||
|
||||
if(state & mutex_waiters_bit) {
|
||||
// Wake the futex if there were waiters. Since the mutex might not exist at this location
|
||||
// anymore, we must conservatively ignore EACCES and EINVAL which may occur as a result.
|
||||
int e = mlibc::sys_futex_wake((int *)&mutex->__mlibc_state);
|
||||
__ensure(e >= 0 || e == EACCES || e == EINVAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_mutexattr_init(struct __mlibc_mutexattr *attr) {
|
||||
attr->__mlibc_type = __MLIBC_THREAD_MUTEX_DEFAULT;
|
||||
attr->__mlibc_robust = __MLIBC_THREAD_MUTEX_STALLED;
|
||||
attr->__mlibc_pshared = __MLIBC_THREAD_PROCESS_PRIVATE;
|
||||
attr->__mlibc_protocol = __MLIBC_THREAD_PRIO_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_mutexattr_destroy(struct __mlibc_mutexattr *attr) {
|
||||
memset(attr, 0, sizeof(*attr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_mutexattr_gettype(const struct __mlibc_mutexattr *__restrict attr, int *__restrict type) {
|
||||
*type = attr->__mlibc_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_mutexattr_settype(struct __mlibc_mutexattr *attr, int type) {
|
||||
if (type != __MLIBC_THREAD_MUTEX_NORMAL && type != __MLIBC_THREAD_MUTEX_ERRORCHECK
|
||||
&& type != __MLIBC_THREAD_MUTEX_RECURSIVE)
|
||||
return EINVAL;
|
||||
|
||||
attr->__mlibc_type = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_cond_init(struct __mlibc_cond *__restrict cond, const struct __mlibc_condattr *__restrict attr) {
|
||||
auto clock = attr ? attr->__mlibc_clock : CLOCK_REALTIME;
|
||||
auto pshared = attr ? attr->__mlibc_pshared : __MLIBC_THREAD_PROCESS_PRIVATE;
|
||||
|
||||
cond->__mlibc_clock = clock;
|
||||
cond->__mlibc_flags = pshared;
|
||||
|
||||
__atomic_store_n(&cond->__mlibc_seq, 1, __ATOMIC_RELAXED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_cond_destroy(struct __mlibc_cond *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_cond_broadcast(struct __mlibc_cond *cond) {
|
||||
__atomic_fetch_add(&cond->__mlibc_seq, 1, __ATOMIC_RELEASE);
|
||||
if(int e = mlibc::sys_futex_wake((int *)&cond->__mlibc_seq); e)
|
||||
__ensure(!"sys_futex_wake() failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_cond_timedwait(struct __mlibc_cond *__restrict cond, __mlibc_mutex *__restrict mutex,
|
||||
const struct timespec *__restrict abstime) {
|
||||
// TODO: pshared isn't supported yet.
|
||||
__ensure(cond->__mlibc_flags == 0);
|
||||
|
||||
constexpr long nanos_per_second = 1'000'000'000;
|
||||
if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= nanos_per_second))
|
||||
return EINVAL;
|
||||
|
||||
auto seq = __atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE);
|
||||
|
||||
// TODO: handle locking errors and cancellation properly.
|
||||
while (true) {
|
||||
if (thread_mutex_unlock(mutex))
|
||||
__ensure(!"Failed to unlock the mutex");
|
||||
|
||||
int e;
|
||||
if (abstime) {
|
||||
// Adjust for the fact that sys_futex_wait accepts a *timeout*, but
|
||||
// pthread_cond_timedwait accepts an *absolute time*.
|
||||
// Note: mlibc::sys_clock_get is available unconditionally.
|
||||
struct timespec now;
|
||||
if (mlibc::sys_clock_get(cond->__mlibc_clock, &now.tv_sec, &now.tv_nsec))
|
||||
__ensure(!"sys_clock_get() failed");
|
||||
|
||||
struct timespec timeout;
|
||||
timeout.tv_sec = abstime->tv_sec - now.tv_sec;
|
||||
timeout.tv_nsec = abstime->tv_nsec - now.tv_nsec;
|
||||
|
||||
// Check if abstime has already passed.
|
||||
if (timeout.tv_sec < 0 || (timeout.tv_sec == 0 && timeout.tv_nsec < 0)) {
|
||||
if (thread_mutex_lock(mutex))
|
||||
__ensure(!"Failed to lock the mutex");
|
||||
return ETIMEDOUT;
|
||||
} else if (timeout.tv_nsec >= nanos_per_second) {
|
||||
timeout.tv_nsec -= nanos_per_second;
|
||||
timeout.tv_sec++;
|
||||
__ensure(timeout.tv_nsec < nanos_per_second);
|
||||
} else if (timeout.tv_nsec < 0) {
|
||||
timeout.tv_nsec += nanos_per_second;
|
||||
timeout.tv_sec--;
|
||||
__ensure(timeout.tv_nsec >= 0);
|
||||
}
|
||||
|
||||
e = mlibc::sys_futex_wait((int *)&cond->__mlibc_seq, seq, &timeout);
|
||||
} else {
|
||||
e = mlibc::sys_futex_wait((int *)&cond->__mlibc_seq, seq, nullptr);
|
||||
}
|
||||
|
||||
if (thread_mutex_lock(mutex))
|
||||
__ensure(!"Failed to lock the mutex");
|
||||
|
||||
// There are four cases to handle:
|
||||
// 1. e == 0: this indicates a (potentially spurious) wakeup. The value of
|
||||
// seq *must* be checked to distinguish these two cases.
|
||||
// 2. e == EAGAIN: this indicates that the value of seq changed before we
|
||||
// went to sleep. We don't need to check seq in this case.
|
||||
// 3. e == EINTR: a signal was delivered. The man page allows us to choose
|
||||
// whether to go to sleep again or to return 0, but we do the former
|
||||
// to match other libcs.
|
||||
// 4. e == ETIMEDOUT: this should only happen if abstime is set.
|
||||
if (e == 0) {
|
||||
auto cur_seq = __atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE);
|
||||
if (cur_seq > seq)
|
||||
return 0;
|
||||
} else if (e == EAGAIN) {
|
||||
__ensure(__atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE) > seq);
|
||||
return 0;
|
||||
} else if (e == EINTR) {
|
||||
continue;
|
||||
} else if (e == ETIMEDOUT) {
|
||||
__ensure(abstime);
|
||||
return ETIMEDOUT;
|
||||
} else {
|
||||
mlibc::panicLogger() << "sys_futex_wait() failed with error " << e << frg::endlog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,282 @@
|
||||
#include <limits.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
#define FMT(obj) format_object((obj), opts, formatter)
|
||||
|
||||
#define LOG_NAME_LOC(name, loc) "ubsan: " name " at " << loc << "\n "
|
||||
#define LOG_LHS_RHS(lhs, rhs) "LHS = " << (lhs) << ", RHS = " << (rhs)
|
||||
|
||||
struct SourceLocation {
|
||||
const char *filename;
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
template<class F>
|
||||
void format_object(const SourceLocation &loc, frg::format_options opts, F &formatter) {
|
||||
FMT(loc.filename);
|
||||
FMT(":");
|
||||
FMT(loc.line);
|
||||
FMT(":");
|
||||
FMT(loc.column);
|
||||
}
|
||||
|
||||
using ValueHandle = uintptr_t;
|
||||
|
||||
struct TypeDescriptor {
|
||||
enum class Kind : uint16_t {
|
||||
Integer = 0x0000,
|
||||
Float = 0x0001,
|
||||
Unknown = 0xffff
|
||||
} kind;
|
||||
|
||||
uint16_t info;
|
||||
char name[];
|
||||
|
||||
unsigned bitWidthInt() const {
|
||||
return 1 << (info >> 1);
|
||||
}
|
||||
|
||||
bool isInlineInt() const {
|
||||
if (kind != Kind::Integer)
|
||||
return false;
|
||||
|
||||
auto inlineBits = sizeof(ValueHandle) * CHAR_BIT;
|
||||
auto valueBits = bitWidthInt();
|
||||
return inlineBits <= valueBits;
|
||||
}
|
||||
|
||||
bool isSigned() const {
|
||||
return info & 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<class F>
|
||||
void format_object(const TypeDescriptor &type, frg::format_options opts, F &formatter) {
|
||||
FMT(type.name);
|
||||
}
|
||||
|
||||
struct Value {
|
||||
const TypeDescriptor &type;
|
||||
ValueHandle val;
|
||||
|
||||
Value(const TypeDescriptor &type, ValueHandle val) : type(type), val(val) {}
|
||||
};
|
||||
|
||||
template<class F>
|
||||
void format_object(const Value &val, frg::format_options opts, F &formatter) {
|
||||
if (val.type.isInlineInt() && val.type.isSigned()) {
|
||||
auto signedValue = static_cast<int64_t>(val.val);
|
||||
FMT(signedValue);
|
||||
} else if (val.type.isInlineInt() && !val.type.isSigned()) {
|
||||
auto unsignedValue = static_cast<uint64_t>(val.val);
|
||||
FMT(unsignedValue);
|
||||
}
|
||||
|
||||
FMT(" (");
|
||||
FMT(val.type);
|
||||
FMT(")");
|
||||
}
|
||||
|
||||
|
||||
// --- Hook implementations ---
|
||||
|
||||
struct TypeMismatch {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &type;
|
||||
unsigned char logAlignment;
|
||||
unsigned char kind;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_type_mismatch_v1(TypeMismatch *tm, ValueHandle pointer) {
|
||||
// TODO: Make this print more information.
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("type mismatch", tm->loc)
|
||||
<< "accessed address " << (void *)pointer << " but type "
|
||||
<< tm->type << " requires alignment " << (1 << tm->logAlignment)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct PointerOverflowData {
|
||||
SourceLocation loc;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_pointer_overflow(PointerOverflowData *pod, ValueHandle base, ValueHandle result) {
|
||||
(void)base;
|
||||
(void)result;
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("pointer overflow", pod->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct InvalidValueData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &type;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_load_invalid_value(InvalidValueData *ivd, ValueHandle value) {
|
||||
(void)value;
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("load of invalid value", ivd->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct OverflowData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &type;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_add_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("add overflowed ", od->loc)
|
||||
<< LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_sub_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("sub overflowed", od->loc)
|
||||
<< LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_mul_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("mul overflowed", od->loc)
|
||||
<< LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_divrem_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("divrem overflowed", od->loc)
|
||||
<< LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_negate_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("negate overflowed", od->loc)
|
||||
<< LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct ShiftOutOfBoundsData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &lhsType;
|
||||
const TypeDescriptor &rhsType;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *soob, ValueHandle lhs, ValueHandle rhs) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("shift out of bounds", soob->loc)
|
||||
<< LOG_LHS_RHS(Value(soob->lhsType, lhs), Value(soob->rhsType, rhs))
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct OutOfBoundsData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &arrayType;
|
||||
const TypeDescriptor &indexType;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_out_of_bounds(OutOfBoundsData *oobd, ValueHandle data) {
|
||||
(void)data;
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("out of bounds access", oobd->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct UnreachableData {
|
||||
SourceLocation loc;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_builtin_unreachable(UnreachableData *ubd) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("reached __builtin_unreachable()", ubd->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct InvalidBuiltinData {
|
||||
SourceLocation loc;
|
||||
unsigned char kind;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_invalid_builtin(InvalidBuiltinData *ibd) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("reached invalid builtin", ibd->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct VLABoundData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &type;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_vla_bound_not_positive(VLABoundData *vlabd) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("VLA bound not positive", vlabd->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_missing_return(UnreachableData *data) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("reached end of a value-returning function without returning a value", data->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
|
||||
struct NonNullArgData {
|
||||
SourceLocation loc;
|
||||
SourceLocation attr_loc;
|
||||
int arg_index;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_nonnull_arg(NonNullArgData *data) {
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("null pointer passed to non-null argument", data->loc)
|
||||
<< "argument " << data->arg_index << " is required to be non-null in "
|
||||
<< data->attr_loc << frg::endlog;
|
||||
}
|
||||
|
||||
struct FloatCastOverflowData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &from_type;
|
||||
const TypeDescriptor &to_type;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_float_cast_overflow(FloatCastOverflowData *data, ValueHandle from) {
|
||||
(void) from;
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("float cast overflow", data->loc)
|
||||
<< "from " << data->from_type << " to "
|
||||
<< data->to_type << frg::endlog;
|
||||
}
|
||||
|
||||
struct FunctionTypeMismatchData {
|
||||
SourceLocation loc;
|
||||
const TypeDescriptor &type;
|
||||
};
|
||||
|
||||
extern "C" [[gnu::visibility("hidden")]]
|
||||
void __ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *data, ValueHandle from) {
|
||||
(void) from;
|
||||
mlibc::panicLogger()
|
||||
<< LOG_NAME_LOC("function type mismatch", data->loc)
|
||||
<< frg::endlog;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef _MLIBC_INTERNAL_CPU_SET_H
|
||||
#define _MLIBC_INTERNAL_CPU_SET_H
|
||||
|
||||
typedef unsigned long __cpu_mask;
|
||||
|
||||
#define CPU_SETSIZE 1024
|
||||
#define __NCPUBITS (8 * sizeof(__cpu_mask))
|
||||
|
||||
typedef struct {
|
||||
__cpu_mask __bits[CPU_SETSIZE / __NCPUBITS];
|
||||
} cpu_set_t;
|
||||
|
||||
#endif /* _MLIBC_INTERNAL_CPU_SET_H */
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef MLIBC_ENSURE_H
|
||||
#define MLIBC_ENSURE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
void __ensure_fail(const char *assertion, const char *file, unsigned int line,
|
||||
const char *function);
|
||||
|
||||
void __ensure_warn(const char *assertion, const char *file, unsigned int line,
|
||||
const char *function);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#define __ensure(assertion) do { if(!(assertion)) \
|
||||
__ensure_fail(#assertion, __FILE__, __LINE__, __func__); } while(0)
|
||||
|
||||
#define MLIBC_UNIMPLEMENTED() __ensure_fail("Functionality is not implemented", \
|
||||
__FILE__, __LINE__, __func__)
|
||||
|
||||
#define MLIBC_MISSING_SYSDEP() __ensure_warn("Library function fails due to missing sysdep", \
|
||||
__FILE__, __LINE__, __func__)
|
||||
|
||||
#define MLIBC_CHECK_OR_ENOSYS(sysdep, ret) ({ \
|
||||
if (!(sysdep)) { \
|
||||
__ensure_warn("Library function fails due to missing sysdep", \
|
||||
__FILE__, __LINE__, __func__); \
|
||||
errno = ENOSYS; \
|
||||
return (ret); \
|
||||
} \
|
||||
sysdep; \
|
||||
})
|
||||
|
||||
#define MLIBC_STUB_BODY ({ MLIBC_UNIMPLEMENTED(); __builtin_unreachable(); })
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_ENSURE_H */
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef MLIBC_ETHER_ADDR_H
|
||||
#define MLIBC_ETHER_ADDR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct ether_addr {
|
||||
uint8_t ether_addr_octet[6];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#endif /* MLIBC_ETHER_ADDR_H */
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef MLIBC_FILE_T_H
|
||||
#define MLIBC_FILE_T_H
|
||||
|
||||
typedef struct __mlibc_file_base FILE;
|
||||
|
||||
#endif /* MLIBC_FILE_T_H */
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef MLIBC_BITS_GETOPT
|
||||
#define MLIBC_BITS_GETOPT
|
||||
|
||||
struct option {
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#endif /* MLIBC_BITS_GETOPT */
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef MLIBC_INLINE_DEFINITION_H
|
||||
#define MLIBC_INLINE_DEFINITION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __MLIBC_EMIT_INLINE_DEFINITIONS
|
||||
#define __MLIBC_INLINE_DEFINITION
|
||||
#else
|
||||
#define __MLIBC_INLINE_DEFINITION __attribute__((__gnu_inline__)) extern __inline__
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_INLINE_DEFINITION_H */
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
|
||||
#ifndef MLIBC_MACHINE_H
|
||||
#define MLIBC_MACHINE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined (__i386__)
|
||||
struct __mlibc_jmpbuf_register_state {
|
||||
uint32_t ebx;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint32_t esp;
|
||||
uint32_t eip;
|
||||
};
|
||||
#elif defined (__x86_64__)
|
||||
struct __mlibc_jmpbuf_register_state {
|
||||
uint64_t rbx;
|
||||
uint64_t rbp;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t rsp;
|
||||
uint64_t rip;
|
||||
};
|
||||
#elif defined (__aarch64__)
|
||||
struct __mlibc_jmpbuf_register_state {
|
||||
uint64_t x19;
|
||||
uint64_t x20;
|
||||
uint64_t x21;
|
||||
uint64_t x22;
|
||||
uint64_t x23;
|
||||
uint64_t x24;
|
||||
uint64_t x25;
|
||||
uint64_t x26;
|
||||
uint64_t x27;
|
||||
uint64_t x28;
|
||||
uint64_t x29;
|
||||
uint64_t x30;
|
||||
uint64_t sp;
|
||||
uint64_t pad;
|
||||
uint64_t d8;
|
||||
uint64_t d9;
|
||||
uint64_t d10;
|
||||
uint64_t d11;
|
||||
uint64_t d12;
|
||||
uint64_t d13;
|
||||
uint64_t d14;
|
||||
uint64_t d15;
|
||||
};
|
||||
#elif defined (__riscv) && __riscv_xlen == 64
|
||||
struct __mlibc_jmpbuf_register_state {
|
||||
uint64_t ra;
|
||||
uint64_t s0;
|
||||
uint64_t s1;
|
||||
uint64_t s2;
|
||||
uint64_t s3;
|
||||
uint64_t s4;
|
||||
uint64_t s5;
|
||||
uint64_t s6;
|
||||
uint64_t s7;
|
||||
uint64_t s8;
|
||||
uint64_t s9;
|
||||
uint64_t s10;
|
||||
uint64_t s11;
|
||||
uint64_t sp;
|
||||
double fs0;
|
||||
double fs1;
|
||||
double fs2;
|
||||
double fs3;
|
||||
double fs4;
|
||||
double fs5;
|
||||
double fs6;
|
||||
double fs7;
|
||||
double fs8;
|
||||
double fs9;
|
||||
double fs10;
|
||||
double fs11;
|
||||
};
|
||||
#elif defined (__m68k__)
|
||||
struct __mlibc_jmpbuf_register_state {
|
||||
uint32_t d2;
|
||||
uint32_t d3;
|
||||
uint32_t d4;
|
||||
uint32_t d5;
|
||||
uint32_t d6;
|
||||
uint32_t d7;
|
||||
uint32_t a2;
|
||||
uint32_t a3;
|
||||
uint32_t a4;
|
||||
uint32_t a5;
|
||||
uint32_t a6;
|
||||
uint32_t a7;
|
||||
uint32_t sp;
|
||||
uint32_t pc;
|
||||
};
|
||||
#elif defined (__loongarch64)
|
||||
struct __mlibc_jmpbuf_register_state {
|
||||
uint64_t ra;
|
||||
uint64_t sp;
|
||||
uint64_t u0;
|
||||
uint64_t s0;
|
||||
uint64_t s1;
|
||||
uint64_t s2;
|
||||
uint64_t s3;
|
||||
uint64_t s4;
|
||||
uint64_t s5;
|
||||
uint64_t s6;
|
||||
uint64_t s7;
|
||||
uint64_t s8;
|
||||
double fs0;
|
||||
double fs1;
|
||||
double fs2;
|
||||
double fs3;
|
||||
double fs4;
|
||||
double fs5;
|
||||
double fs6;
|
||||
double fs7;
|
||||
};
|
||||
#else
|
||||
# error "Missing architecture specific code"
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_MACHINE_H */
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_MBSTATE_H
|
||||
#define MLIBC_MBSTATE_H
|
||||
|
||||
typedef struct __mlibc_mbstate {
|
||||
short __progress;
|
||||
short __shift;
|
||||
unsigned int __cpoint;
|
||||
} mbstate_t;
|
||||
|
||||
#define __MLIBC_MBSTATE_INITIALIZER {0, 0, 0}
|
||||
|
||||
#endif /* MLIBC_MBSTATE_H */
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
#ifndef _NL_ITEM_H
|
||||
#define _NL_ITEM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int nl_item;
|
||||
|
||||
#define ABDAY_1 0x60000
|
||||
#define ABDAY_2 0x60001
|
||||
#define ABDAY_3 0x60002
|
||||
#define ABDAY_4 0x60003
|
||||
#define ABDAY_5 0x60004
|
||||
#define ABDAY_6 0x60005
|
||||
#define ABDAY_7 0x60006
|
||||
|
||||
#define DAY_1 0x60007
|
||||
#define DAY_2 0x60008
|
||||
#define DAY_3 0x60009
|
||||
#define DAY_4 0x6000A
|
||||
#define DAY_5 0x6000B
|
||||
#define DAY_6 0x6000C
|
||||
#define DAY_7 0x6000D
|
||||
|
||||
#define ABMON_1 0x6000E
|
||||
#define ABMON_2 0x6000F
|
||||
#define ABMON_3 0x60010
|
||||
#define ABMON_4 0x60011
|
||||
#define ABMON_5 0x60012
|
||||
#define ABMON_6 0x60013
|
||||
#define ABMON_7 0x60014
|
||||
#define ABMON_8 0x60015
|
||||
#define ABMON_9 0x60016
|
||||
#define ABMON_10 0x60017
|
||||
#define ABMON_11 0x60018
|
||||
#define ABMON_12 0x60019
|
||||
|
||||
#define MON_1 0x6001A
|
||||
#define MON_2 0x6001B
|
||||
#define MON_3 0x6001C
|
||||
#define MON_4 0x6001D
|
||||
#define MON_5 0x6001E
|
||||
#define MON_6 0x6001F
|
||||
#define MON_7 0x60020
|
||||
#define MON_8 0x60021
|
||||
#define MON_9 0x60022
|
||||
#define MON_10 0x60023
|
||||
#define MON_11 0x60024
|
||||
#define MON_12 0x60025
|
||||
|
||||
#define AM_STR 0x60026
|
||||
#define PM_STR 0x60027
|
||||
|
||||
#define D_T_FMT 0x60028
|
||||
#define D_FMT 0x60029
|
||||
#define T_FMT 0x6002A
|
||||
#define T_FMT_AMPM 0x6002B
|
||||
|
||||
#define ERA 0x6002C
|
||||
#define ERA_D_FMT 0x6002D
|
||||
#define ALT_DIGITS 0x6002E
|
||||
#define ERA_D_T_FMT 0x6002F
|
||||
#define ERA_T_FMT 0x60030
|
||||
|
||||
#define CODESET 0x30000
|
||||
|
||||
#define CRNCYSTR 0x40000
|
||||
|
||||
#define RADIXCHAR 0x50000
|
||||
#define DECIMAL_POINT RADIXCHAR
|
||||
#define THOUSEP 0x50001
|
||||
#define THOUSANDS_SEP THOUSEP
|
||||
|
||||
#define YESEXPR 0x70000
|
||||
#define NOEXPR 0x70001
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NL_ITEM_H */
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef MLIBC_NULL_H
|
||||
#define MLIBC_NULL_H
|
||||
|
||||
#ifdef NULL
|
||||
#undef NULL
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
# define NULL ((void *)0)
|
||||
#else
|
||||
# define NULL 0
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_NULL_H */
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef MLIBC_OFF_T_H
|
||||
#define MLIBC_OFF_T_H
|
||||
|
||||
/* TODO: use something like int64_t instead? */
|
||||
typedef long off_t;
|
||||
typedef long off64_t;
|
||||
|
||||
#endif /* MLIBC_OFF_T_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef _MLIBC_INTERNAL_SEARCH_H
|
||||
#define _MLIBC_INTERNAL_SEARCH_H
|
||||
|
||||
#include <bits/size_t.h>
|
||||
|
||||
typedef enum {
|
||||
FIND,
|
||||
ENTER
|
||||
} ACTION;
|
||||
|
||||
typedef struct entry {
|
||||
char *key;
|
||||
void *data;
|
||||
} ENTRY;
|
||||
|
||||
struct _ENTRY;
|
||||
|
||||
struct hsearch_data {
|
||||
struct _ENTRY *table;
|
||||
unsigned int size;
|
||||
unsigned int filled;
|
||||
};
|
||||
|
||||
#endif /* _MLIBC_INTERNAL_SEARCH_H */
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef MLIBC_BITS_SIGSET_T_H
|
||||
#define MLIBC_BITS_SIGSET_T_H
|
||||
|
||||
#include <abi-bits/signal.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
/* functions to manage sigset_t */
|
||||
int sigemptyset(sigset_t *__sigset);
|
||||
int sigfillset(sigset_t *__sigset);
|
||||
int sigaddset(sigset_t *__sigset, int __sig);
|
||||
int sigdelset(sigset_t *__sigset, int __sig);
|
||||
int sigismember(const sigset_t *__sigset, int __sig);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*MLIBC_BITS_SIGSET_T_H */
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef MLIBC_SIZE_T_H
|
||||
#define MLIBC_SIZE_T_H
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#endif /* MLIBC_SIZE_T_H */
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
#ifndef MLIBC_SSIZE_T_H
|
||||
#define MLIBC_SSIZE_T_H
|
||||
|
||||
/* TODO: use ptrdiff_t instead? */
|
||||
#if __UINTPTR_MAX__ == __UINT64_MAX__
|
||||
typedef long ssize_t;
|
||||
#elif __UINTPTR_MAX__ == __UINT32_MAX__
|
||||
typedef int ssize_t;
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_SSIZE_T_H */
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef _INTERNAL_THREADS_H
|
||||
#define _INTERNAL_THREADS_H
|
||||
|
||||
#include <abi-bits/clockid_t.h>
|
||||
#include <bits/size_t.h>
|
||||
#include <bits/cpu_set.h>
|
||||
#include <bits/sigset_t.h>
|
||||
|
||||
/* values for pthread_attr_{get,set}detachstate(). */
|
||||
#define __MLIBC_THREAD_CREATE_JOINABLE 0
|
||||
#define __MLIBC_THREAD_CREATE_DETACHED 1
|
||||
|
||||
/* values for pthread_mutexattr_{get,set}type(). */
|
||||
#define __MLIBC_THREAD_MUTEX_DEFAULT 0
|
||||
#define __MLIBC_THREAD_MUTEX_NORMAL 0
|
||||
#define __MLIBC_THREAD_MUTEX_ERRORCHECK 1
|
||||
#define __MLIBC_THREAD_MUTEX_RECURSIVE 2
|
||||
|
||||
/* values for pthread_mutexattr_{get,set}pshared(). */
|
||||
#define __MLIBC_THREAD_PROCESS_PRIVATE 0
|
||||
#define __MLIBC_THREAD_PROCESS_SHARED 1
|
||||
|
||||
/* values for pthread_mutexattr_{get,set}robust(). */
|
||||
#define __MLIBC_THREAD_MUTEX_STALLED 0
|
||||
#define __MLIBC_THREAD_MUTEX_ROBUST 1
|
||||
|
||||
/* Values for pthread_mutexattr_{get,set}protocol() */
|
||||
#define __MLIBC_THREAD_PRIO_NONE 0
|
||||
#define __MLIBC_THREAD_PRIO_INHERIT 1
|
||||
#define __MLIBC_THREAD_PRIO_PROTECT 2
|
||||
|
||||
#define __MLIBC_THREAD_MUTEX_INITIALIZER {0, 0, 0, 0}
|
||||
|
||||
struct sched_param {
|
||||
int sched_priority;
|
||||
};
|
||||
|
||||
struct __mlibc_thread_data;
|
||||
|
||||
struct __mlibc_threadattr {
|
||||
size_t __mlibc_guardsize;
|
||||
size_t __mlibc_stacksize;
|
||||
void *__mlibc_stackaddr;
|
||||
int __mlibc_detachstate;
|
||||
int __mlibc_scope;
|
||||
int __mlibc_inheritsched;
|
||||
struct sched_param __mlibc_schedparam;
|
||||
int __mlibc_schedpolicy;
|
||||
cpu_set_t *__mlibc_cpuset;
|
||||
size_t __mlibc_cpusetsize;
|
||||
sigset_t __mlibc_sigmask;
|
||||
int __mlibc_sigmaskset;
|
||||
};
|
||||
|
||||
struct __mlibc_mutex {
|
||||
unsigned int __mlibc_state;
|
||||
unsigned int __mlibc_recursion;
|
||||
unsigned int __mlibc_flags;
|
||||
int __mlibc_prioceiling;
|
||||
};
|
||||
|
||||
struct __mlibc_mutexattr {
|
||||
int __mlibc_type;
|
||||
int __mlibc_robust;
|
||||
int __mlibc_protocol;
|
||||
int __mlibc_pshared;
|
||||
int __mlibc_prioceiling;
|
||||
};
|
||||
|
||||
struct __mlibc_cond {
|
||||
unsigned int __mlibc_seq;
|
||||
unsigned int __mlibc_flags;
|
||||
clockid_t __mlibc_clock;
|
||||
};
|
||||
|
||||
struct __mlibc_condattr {
|
||||
int __mlibc_pshared;
|
||||
clockid_t __mlibc_clock;
|
||||
};
|
||||
|
||||
#endif /* _INTERNAL_THREADS_H */
|
||||
@@ -0,0 +1,408 @@
|
||||
#ifndef _MLIBC_INTERNAL_TYPES_H
|
||||
#define _MLIBC_INTERNAL_TYPES_H
|
||||
|
||||
typedef __UINT8_TYPE__ __mlibc_uint8;
|
||||
typedef __UINT16_TYPE__ __mlibc_uint16;
|
||||
typedef __UINT32_TYPE__ __mlibc_uint32;
|
||||
typedef __UINT64_TYPE__ __mlibc_uint64;
|
||||
|
||||
typedef __INT8_TYPE__ __mlibc_int8;
|
||||
typedef __INT16_TYPE__ __mlibc_int16;
|
||||
typedef __INT32_TYPE__ __mlibc_int32;
|
||||
typedef __INT64_TYPE__ __mlibc_int64;
|
||||
|
||||
/* Clang and GCC have different mechanisms for INT32_C and friends. */
|
||||
#ifdef __clang__
|
||||
# define __MLIBC_C_EXPAND_JOIN(x, suffix) x ## suffix
|
||||
# define __MLIBC_C_JOIN(x, suffix) __MLIBC_C_EXPAND_JOIN(x, suffix)
|
||||
|
||||
# define __MLIBC_INT8_C(x) __MLIBC_C_JOIN(x, __INT8_C_SUFFIX__)
|
||||
# define __MLIBC_INT16_C(x) __MLIBC_C_JOIN(x, __INT16_C_SUFFIX__)
|
||||
# define __MLIBC_INT32_C(x) __MLIBC_C_JOIN(x, __INT32_C_SUFFIX__)
|
||||
# define __MLIBC_INT64_C(x) __MLIBC_C_JOIN(x, __INT64_C_SUFFIX__)
|
||||
|
||||
# define __MLIBC_UINT8_C(x) __MLIBC_C_JOIN(x, __UINT8_C_SUFFIX__)
|
||||
# define __MLIBC_UINT16_C(x) __MLIBC_C_JOIN(x, __UINT16_C_SUFFIX__)
|
||||
# define __MLIBC_UINT32_C(x) __MLIBC_C_JOIN(x, __UINT32_C_SUFFIX__)
|
||||
# define __MLIBC_UINT64_C(x) __MLIBC_C_JOIN(x, __UINT64_C_SUFFIX__)
|
||||
|
||||
# define __MLIBC_INTMAX_C(x) __MLIBC_C_JOIN(x, __INTMAX_C_SUFFIX__)
|
||||
# define __MLIBC_UINTMAX_C(x) __MLIBC_C_JOIN(x, __UINTMAX_C_SUFFIX__)
|
||||
#else
|
||||
# define __MLIBC_INT8_C(x) __INT8_C(x)
|
||||
# define __MLIBC_INT16_C(x) __INT16_C(x)
|
||||
# define __MLIBC_INT32_C(x) __INT32_C(x)
|
||||
# define __MLIBC_INT64_C(x) __INT64_C(x)
|
||||
|
||||
# define __MLIBC_UINT8_C(x) __UINT8_C(x)
|
||||
# define __MLIBC_UINT16_C(x) __UINT16_C(x)
|
||||
# define __MLIBC_UINT32_C(x) __UINT32_C(x)
|
||||
# define __MLIBC_UINT64_C(x) __UINT64_C(x)
|
||||
|
||||
# define __MLIBC_INTMAX_C(x) __INTMAX_C(x)
|
||||
# define __MLIBC_UINTMAX_C(x) __UINTMAX_C(x)
|
||||
#endif
|
||||
|
||||
#define __MLIBC_INT8_MAX __INT8_MAX__
|
||||
#define __MLIBC_INT16_MAX __INT16_MAX__
|
||||
#define __MLIBC_INT32_MAX __INT32_MAX__
|
||||
#define __MLIBC_INT64_MAX __INT64_MAX__
|
||||
|
||||
#define __MLIBC_INT8_MIN (-__MLIBC_INT8_MAX - 1)
|
||||
#define __MLIBC_INT16_MIN (-__MLIBC_INT16_MAX - 1)
|
||||
#define __MLIBC_INT32_MIN (-__MLIBC_INT32_MAX - 1)
|
||||
#define __MLIBC_INT64_MIN (-__MLIBC_INT64_MAX - 1)
|
||||
|
||||
#define __MLIBC_UINT8_MAX __UINT8_MAX__
|
||||
#define __MLIBC_UINT16_MAX __UINT16_MAX__
|
||||
#define __MLIBC_UINT32_MAX __UINT32_MAX__
|
||||
#define __MLIBC_UINT64_MAX __UINT64_MAX__
|
||||
|
||||
/* Fast types (signed). */
|
||||
|
||||
#if defined (__i386__)
|
||||
|
||||
typedef __mlibc_int8 __mlibc_int_fast8;
|
||||
#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x)
|
||||
#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX
|
||||
#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN
|
||||
|
||||
typedef __mlibc_int32 __mlibc_int_fast16;
|
||||
#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT32_C(x)
|
||||
#define __MLIBC_INT_FAST16_MAX __MLIBC_INT32_MAX
|
||||
#define __MLIBC_INT_FAST16_MIN __MLIBC_INT32_MIN
|
||||
|
||||
typedef __mlibc_int32 __mlibc_int_fast32;
|
||||
#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x)
|
||||
#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX
|
||||
#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast64;
|
||||
#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
#elif defined (__x86_64__)
|
||||
|
||||
typedef __mlibc_int8 __mlibc_int_fast8;
|
||||
#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x)
|
||||
#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX
|
||||
#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast16;
|
||||
#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast32;
|
||||
#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast64;
|
||||
#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
#elif defined (__aarch64__)
|
||||
|
||||
typedef __mlibc_int8 __mlibc_int_fast8;
|
||||
#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x)
|
||||
#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX
|
||||
#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast16;
|
||||
#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast32;
|
||||
#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast64;
|
||||
#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
#elif defined (__riscv) && __riscv_xlen == 64
|
||||
|
||||
typedef __mlibc_int8 __mlibc_int_fast8;
|
||||
#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x)
|
||||
#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX
|
||||
#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast16;
|
||||
#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast32;
|
||||
#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast64;
|
||||
#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
#elif defined (__m68k__)
|
||||
|
||||
typedef __mlibc_int8 __mlibc_int_fast8;
|
||||
#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x)
|
||||
#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX
|
||||
#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN
|
||||
|
||||
typedef __mlibc_int32 __mlibc_int_fast16;
|
||||
#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT16_C(x)
|
||||
#define __MLIBC_INT_FAST16_MAX __MLIBC_INT16_MAX
|
||||
#define __MLIBC_INT_FAST16_MIN __MLIBC_INT16_MIN
|
||||
|
||||
typedef __mlibc_int32 __mlibc_int_fast32;
|
||||
#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x)
|
||||
#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX
|
||||
#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast64;
|
||||
#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
#elif defined (__loongarch64)
|
||||
|
||||
typedef __mlibc_int8 __mlibc_int_fast8;
|
||||
#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x)
|
||||
#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX
|
||||
#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast16;
|
||||
#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast32;
|
||||
#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN
|
||||
|
||||
typedef __mlibc_int64 __mlibc_int_fast64;
|
||||
#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x)
|
||||
#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX
|
||||
#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
#else
|
||||
# error "Missing architecture specific code"
|
||||
#endif
|
||||
|
||||
/* Fast types (unsigned). */
|
||||
|
||||
#if defined (__i386__)
|
||||
|
||||
typedef __mlibc_uint8 __mlibc_uint_fast8;
|
||||
#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN
|
||||
|
||||
typedef __mlibc_uint32 __mlibc_uint_fast16;
|
||||
#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT32_C(x)
|
||||
#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT32_MAX
|
||||
#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT32_MIN
|
||||
|
||||
typedef __mlibc_uint32 __mlibc_uint_fast32;
|
||||
#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x)
|
||||
#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX
|
||||
#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast64;
|
||||
#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
#elif defined (__x86_64__)
|
||||
|
||||
typedef __mlibc_uint8 __mlibc_uint_fast8;
|
||||
#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast16;
|
||||
#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast32;
|
||||
#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast64;
|
||||
#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
#elif defined (__aarch64__)
|
||||
|
||||
typedef __mlibc_uint8 __mlibc_uint_fast8;
|
||||
#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast16;
|
||||
#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast32;
|
||||
#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast64;
|
||||
#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
#elif defined (__riscv) && __riscv_xlen == 64
|
||||
|
||||
typedef __mlibc_uint8 __mlibc_uint_fast8;
|
||||
#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast16;
|
||||
#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast32;
|
||||
#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast64;
|
||||
#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
#elif defined (__m68k__)
|
||||
|
||||
typedef __mlibc_uint8 __mlibc_uint_fast8;
|
||||
#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN
|
||||
|
||||
typedef __mlibc_uint32 __mlibc_uint_fast16;
|
||||
#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT16_C(x)
|
||||
#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT16_MAX
|
||||
#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT16_MIN
|
||||
|
||||
typedef __mlibc_uint32 __mlibc_uint_fast32;
|
||||
#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x)
|
||||
#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX
|
||||
#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast64;
|
||||
#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
#elif defined (__loongarch64)
|
||||
|
||||
typedef __mlibc_uint8 __mlibc_uint_fast8;
|
||||
#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast16;
|
||||
#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast32;
|
||||
#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
typedef __mlibc_uint64 __mlibc_uint_fast64;
|
||||
#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX
|
||||
#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN
|
||||
|
||||
#else
|
||||
# error "Missing architecture specific code"
|
||||
#endif
|
||||
|
||||
/* Special types. */
|
||||
|
||||
typedef __INTMAX_TYPE__ __mlibc_intmax;
|
||||
typedef __INTPTR_TYPE__ __mlibc_intptr;
|
||||
typedef __PTRDIFF_TYPE__ __mlibc_ptrdiff;
|
||||
#define __MLIBC_INTMAX_MAX __INTMAX_MAX__
|
||||
#define __MLIBC_INTMAX_MIN (-__INTMAX_MAX__ - 1)
|
||||
#define __MLIBC_INTPTR_MAX __INTPTR_MAX__
|
||||
#define __MLIBC_INTPTR_MIN (-__INTPTR_MAX__ - 1)
|
||||
#define __MLIBC_PTRDIFF_MAX __PTRDIFF_MAX__
|
||||
#define __MLIBC_PTRDIFF_MIN (-__PTRDIFF_MAX__ - 1)
|
||||
|
||||
typedef __UINTMAX_TYPE__ __mlibc_uintmax;
|
||||
typedef __UINTPTR_TYPE__ __mlibc_uintptr;
|
||||
typedef __SIZE_TYPE__ __mlibc_size;
|
||||
#define __MLIBC_UINTMAX_MAX __UINTMAX_MAX__
|
||||
#define __MLIBC_UINTPTR_MAX __UINTPTR_MAX__
|
||||
#define __MLIBC_SIZE_MAX __SIZE_MAX__
|
||||
|
||||
/* Other limits. */
|
||||
|
||||
#define __MLIBC_WCHAR_MAX __WCHAR_MAX__
|
||||
#define __MLIBC_WCHAR_MIN __WCHAR_MIN__
|
||||
|
||||
#define __MLIBC_WINT_MAX __WINT_MAX__
|
||||
#define __MLIBC_WINT_MIN __WINT_MIN__
|
||||
|
||||
#define __MLIBC_SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
|
||||
#define __MLIBC_SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Sanity checking. Make sure that we agree with the compiler's ABI. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(__cplusplus) && defined(__cpp_static_assert) && __cpp_static_assert >= 200410L
|
||||
# define __MLIBC_STATIC_ASSERT(c, text) static_assert(c, text)
|
||||
#elif !defined(__cplusplus)
|
||||
/* _Static_assert is an extension in C89/C99. */
|
||||
# define __MLIBC_STATIC_ASSERT(c, text) __extension__ _Static_assert(c, text)
|
||||
#else
|
||||
# define __MLIBC_STATIC_ASSERT(c, text) extern int __static_assert_unavailable
|
||||
#endif
|
||||
|
||||
#define __MLIBC_CHECK_TYPE(T1, T2) __MLIBC_STATIC_ASSERT(sizeof(T1) == sizeof(T2),\
|
||||
#T1 " != " #T2)
|
||||
|
||||
/* Least-width. */
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int8, __INT_LEAST8_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int16, __INT_LEAST16_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int32, __INT_LEAST32_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int64, __INT_LEAST64_TYPE__);
|
||||
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint8, __UINT_LEAST8_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint16, __UINT_LEAST16_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint32, __UINT_LEAST32_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint64, __UINT_LEAST64_TYPE__);
|
||||
|
||||
/* Fast-width. */
|
||||
/* Unfortunately, GCC and Clang disagree about fast types. */
|
||||
#ifndef __clang__
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int_fast8, __INT_FAST8_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int_fast16, __INT_FAST16_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int_fast32, __INT_FAST32_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_int_fast64, __INT_FAST64_TYPE__);
|
||||
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint_fast8, __UINT_FAST8_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint_fast16, __UINT_FAST16_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint_fast32, __UINT_FAST32_TYPE__);
|
||||
__MLIBC_CHECK_TYPE(__mlibc_uint_fast64, __UINT_FAST64_TYPE__);
|
||||
#endif
|
||||
|
||||
#endif /* _MLIBC_INTERNAL_TYPES_H */
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef MLIBC_WCHAR_H
|
||||
#define MLIBC_WCHAR_H
|
||||
|
||||
#include <bits/types.h>
|
||||
|
||||
#define WCHAR_MAX __MLIBC_WCHAR_MAX
|
||||
#define WCHAR_MIN __MLIBC_WCHAR_MIN
|
||||
|
||||
#endif /* MLIBC_WCHAR_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef MLIBC_WCHAR_T_H
|
||||
#define MLIBC_WCHAR_T_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
typedef __WCHAR_TYPE__ wchar_t;
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_WCHAR_T_H */
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef MLIBC_WCTRANS_T_H
|
||||
#define MLIBC_WCTRANS_T_H
|
||||
|
||||
typedef unsigned long wctrans_t;
|
||||
|
||||
#endif /* MLIBC_WCTRANS_T_H */
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef MLIBC_WCTYPE_T_H
|
||||
#define MLIBC_WCTYPE_T_H
|
||||
|
||||
typedef unsigned long wctype_t;
|
||||
|
||||
#endif /* MLIBC_WCTYPE_T_H */
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef MLIBC_WINSIZE_H
|
||||
#define MLIBC_WINSIZE_H
|
||||
|
||||
struct winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
|
||||
#endif /* MLIBC_WINSIZE_H */
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef MLIBC_WINT_T_H
|
||||
#define MLIBC_WINT_T_H
|
||||
|
||||
typedef __WINT_TYPE__ wint_t;
|
||||
|
||||
#endif /* MLIBC_WINT_T_H */
|
||||
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
// DWARF expressions
|
||||
#define DW_OP_deref 0x06
|
||||
#define DW_OP_breg0 0x70
|
||||
|
||||
#define DW_CFA_def_cfa_expression 0x0f
|
||||
#define DW_CFA_expression 0x10
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
#define DWARF_REG_RAX 0
|
||||
#define DWARF_REG_RDX 1
|
||||
#define DWARF_REG_RCX 2
|
||||
#define DWARF_REG_RBX 3
|
||||
#define DWARF_REG_RSI 4
|
||||
#define DWARF_REG_RDI 5
|
||||
#define DWARF_REG_RBP 6
|
||||
#define DWARF_REG_RSP 7
|
||||
#define DWARF_REG_R8 8
|
||||
#define DWARF_REG_R9 9
|
||||
#define DWARF_REG_R10 10
|
||||
#define DWARF_REG_R11 11
|
||||
#define DWARF_REG_R12 12
|
||||
#define DWARF_REG_R13 13
|
||||
#define DWARF_REG_R14 14
|
||||
#define DWARF_REG_R15 15
|
||||
#define DWARF_REG_RETURN_ADDRESS 16
|
||||
|
||||
#define DWARF_REG_XMM0 17
|
||||
#define DWARF_REG_XMM1 18
|
||||
#define DWARF_REG_XMM2 19
|
||||
#define DWARF_REG_XMM3 20
|
||||
#define DWARF_REG_XMM4 21
|
||||
#define DWARF_REG_XMM5 22
|
||||
#define DWARF_REG_XMM6 23
|
||||
#define DWARF_REG_XMM7 24
|
||||
#define DWARF_REG_XMM8 25
|
||||
#define DWARF_REG_XMM9 26
|
||||
#define DWARF_REG_XMM10 27
|
||||
#define DWARF_REG_XMM11 28
|
||||
#define DWARF_REG_XMM12 29
|
||||
#define DWARF_REG_XMM13 30
|
||||
#define DWARF_REG_XMM14 31
|
||||
#define DWARF_REG_XMM15 32
|
||||
|
||||
#define DWARF_REG_ST0 33
|
||||
#define DWARF_REG_ST1 34
|
||||
#define DWARF_REG_ST2 35
|
||||
#define DWARF_REG_ST3 36
|
||||
#define DWARF_REG_ST4 37
|
||||
#define DWARF_REG_ST5 38
|
||||
#define DWARF_REG_ST6 39
|
||||
#define DWARF_REG_ST7 40
|
||||
|
||||
#define DWARF_REG_MM0 41
|
||||
#define DWARF_REG_MM1 42
|
||||
#define DWARF_REG_MM2 43
|
||||
#define DWARF_REG_MM3 44
|
||||
#define DWARF_REG_MM4 45
|
||||
#define DWARF_REG_MM5 46
|
||||
#define DWARF_REG_MM6 47
|
||||
#define DWARF_REG_MM7 48
|
||||
|
||||
#define DWARF_REG_RFLAGS 49
|
||||
#define DWARF_REG_ES 50
|
||||
#define DWARF_REG_CS 51
|
||||
#define DWARF_REG_SS 52
|
||||
#define DWARF_REG_DS 53
|
||||
#define DWARF_REG_FS 54
|
||||
#define DWARF_REG_GS 55
|
||||
|
||||
#define DWARF_REG_TR 62
|
||||
#define DWARF_REG_LDTR 63
|
||||
#define DWARF_REG_MXCSR 64
|
||||
#define DWARF_REG_FCW 65
|
||||
#define DWARF_REG_FSW 66
|
||||
|
||||
#endif // defined(__x86_64__)
|
||||
|
||||
#if defined(__ASSEMBLER__)
|
||||
|
||||
#define DWARF_ULEB128_14BIT_SIZE(n) (1 + (((n) > 0x7f) & 1))
|
||||
#define DWARF_SLEB128_14BIT_SIZE(n) (1 + (((n) < -0x40) & 1) + (((n) > 0x3f) & 1))
|
||||
|
||||
// write an up to 2-byte signed leb128 value
|
||||
.macro cfi_emit_sleb128 val
|
||||
.if (\val) < -0x2000 || (\val) > 0x1fff // doesn't fit in 2 bytes
|
||||
.error "cfi_emit_sleb128 value is out of range (\val)"
|
||||
.elseif (\val) < -0x40 || (\val) > 0x3f // doesn't fit in 1 byte
|
||||
.cfi_escape ((\val) & 0x7f) | 0x80
|
||||
.cfi_escape ((\val) >> 7) & 0x7f
|
||||
.else // fits in 1 byte
|
||||
.cfi_escape (\val) & 0x7f
|
||||
.endif
|
||||
.endm
|
||||
|
||||
// write an up to 2-byte unsigned leb128 value
|
||||
.macro cfi_emit_uleb128 val
|
||||
.if (\val) < 0 || (\val) > 0x3fff // doesn't fit in 2 bytes
|
||||
.error "cfi_emit_uleb128 value is out of range (\val)"
|
||||
.elseif (\val) > 0x7f // doesn't fit in 1 byte
|
||||
.cfi_escape ((\val) & 0x7f) | 0x80
|
||||
.cfi_escape (\val) >> 7
|
||||
.else
|
||||
.cfi_escape (\val)
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro cfi_set_cfa_to_ptr_with_offset target_reg, offset
|
||||
.cfi_escape DW_CFA_def_cfa_expression
|
||||
cfi_emit_uleb128 (1 + DWARF_SLEB128_14BIT_SIZE(\offset) + 1)
|
||||
.cfi_escape DW_OP_breg0 + (\target_reg)
|
||||
cfi_emit_sleb128 (\offset)
|
||||
.cfi_escape DW_OP_deref
|
||||
.endm
|
||||
|
||||
// Set previous value of the register 'target_reg' to (context_reg + offset)
|
||||
.macro cfi_set_prev_reg_value target_reg, context_reg, offset
|
||||
.cfi_escape DW_CFA_expression
|
||||
cfi_emit_uleb128 (\target_reg)
|
||||
cfi_emit_uleb128 (1 + DWARF_SLEB128_14BIT_SIZE(\offset))
|
||||
.cfi_escape DW_OP_breg0 + (\context_reg)
|
||||
cfi_emit_sleb128 (\offset)
|
||||
.endm
|
||||
|
||||
#endif // defined(__ASSEMBLER__)
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(__ASSEMBLER__)
|
||||
#error "This file can only be used by assembly files."
|
||||
#endif
|
||||
|
||||
#define PROC_START(name) \
|
||||
.global name; \
|
||||
.type name, @function; \
|
||||
.cfi_startproc; \
|
||||
name:
|
||||
|
||||
#define PROC_START_NOCFI(name) \
|
||||
.global name; \
|
||||
.type name, @function; \
|
||||
name:
|
||||
|
||||
#define PROC_END(name) \
|
||||
.cfi_endproc; \
|
||||
.size name, . - name
|
||||
|
||||
#define PROC_END_NOCFI(name) \
|
||||
.size name, . - name
|
||||
|
||||
#define PROC_ALIAS(name, alias) \
|
||||
.global alias; \
|
||||
.type alias, @function; \
|
||||
.set alias, name
|
||||
|
||||
#define PROC_HIDDEN_ALIAS(name, alias) \
|
||||
.hidden alias; \
|
||||
.type alias, @function; \
|
||||
.set alias, name
|
||||
|
||||
#define GNU_STACK_NOTE() \
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef MLIBC_ALL_SYSDEPS
|
||||
#define MLIBC_ALL_SYSDEPS
|
||||
|
||||
#include <mlibc-config.h>
|
||||
#include <internal-config.h>
|
||||
|
||||
/* The ANSI option is always enabled. */
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
|
||||
#if __MLIBC_POSIX_OPTION
|
||||
# include <mlibc/posix-sysdeps.hpp>
|
||||
#endif /* __MLIBC_POSIX_OPTION */
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
# include <mlibc/linux-sysdeps.hpp>
|
||||
#endif /* __MLIBC_LINUX_OPTION */
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
# include <mlibc/glibc-sysdeps.hpp>
|
||||
#endif /* __MLIBC_GLIBC_OPTION */
|
||||
|
||||
#if __MLIBC_BSD_OPTION
|
||||
# include <mlibc/bsd-sysdeps.hpp>
|
||||
#endif /* __MLIBC_BSD_OPTION */
|
||||
|
||||
#if MLIBC_BUILDING_RTLD
|
||||
# include <mlibc/rtld-sysdeps.hpp>
|
||||
#endif /* MLIBC_BUILDING_RTLD */
|
||||
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
|
||||
#endif /* MLIBC_ALL_SYSDEPS */
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef MLIBC_FRIGG_ALLOC
|
||||
#define MLIBC_FRIGG_ALLOC
|
||||
|
||||
#include <mlibc/lock.hpp>
|
||||
#include <bits/ensure.h>
|
||||
#include <frg/slab.hpp>
|
||||
#include <internal-config.h>
|
||||
|
||||
#if !MLIBC_DEBUG_ALLOCATOR
|
||||
|
||||
struct VirtualAllocator {
|
||||
public:
|
||||
uintptr_t map(size_t length);
|
||||
|
||||
void unmap(uintptr_t address, size_t length);
|
||||
};
|
||||
|
||||
typedef frg::slab_pool<VirtualAllocator, FutexLock> MemoryPool;
|
||||
|
||||
typedef frg::slab_allocator<VirtualAllocator, FutexLock> MemoryAllocator;
|
||||
|
||||
MemoryAllocator &getAllocator();
|
||||
|
||||
#else
|
||||
|
||||
struct MemoryAllocator {
|
||||
void *allocate(size_t size);
|
||||
void free(void *ptr);
|
||||
void deallocate(void *ptr, size_t size);
|
||||
void *reallocate(void *ptr, size_t size);
|
||||
size_t get_size(void *ptr);
|
||||
};
|
||||
|
||||
MemoryAllocator &getAllocator();
|
||||
|
||||
#endif // !MLIBC_DEBUG_ALLOCATOR
|
||||
|
||||
#endif // MLIBC_FRIGG_ALLOC
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef MLIBC_BITUTIL
|
||||
#define MLIBC_BITUTIL
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
template<typename T>
|
||||
struct bit_util;
|
||||
|
||||
template<>
|
||||
struct bit_util<uint64_t> {
|
||||
static uint64_t byteswap(uint64_t x) {
|
||||
return __builtin_bswap64(x);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct bit_util<uint32_t> {
|
||||
static uint32_t byteswap(uint32_t x) {
|
||||
return __builtin_bswap32(x);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct bit_util<uint16_t> {
|
||||
static uint16_t byteswap(uint16_t x) {
|
||||
return __builtin_bswap16(x);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_BITUTIL
|
||||
@@ -0,0 +1,124 @@
|
||||
#ifndef MLIBC_CHARCODE_HPP
|
||||
#define MLIBC_CHARCODE_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <bits/mbstate.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
enum class charcode_error {
|
||||
null,
|
||||
dirty,
|
||||
illegal_input,
|
||||
input_underflow,
|
||||
output_overflow
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct code_seq {
|
||||
C *it;
|
||||
const C *end;
|
||||
|
||||
explicit operator bool () {
|
||||
return it != end;
|
||||
}
|
||||
};
|
||||
|
||||
// Some encodings (e.g. the one defined in RFC 1843) have "shift states",
|
||||
// i.e. escape sequences that switch between different encodings (e.g. between single-byte ASCII
|
||||
// and 2-byte encoding of Chinese characters).
|
||||
// TODO: Implement that using the __shift member of __mlibc_mbstate.
|
||||
|
||||
typedef uint32_t codepoint;
|
||||
|
||||
// The following class deals with decoding/encoding "code units" (of type char)
|
||||
// to "code points" that are defined by unicode (of type codepoint).
|
||||
// It also offers convenience functions to transcode to wchar_t, char16_t and char32_t.
|
||||
// We assume that the encoding of wchar_t (and char16_t, char32_t) is fixed.
|
||||
// char is allowed to have an arbitrary encoding.
|
||||
// TODO: char16_t and char32_t variants are missing.
|
||||
// TODO: For iconv(), first decode and then encode to the destination encoding.
|
||||
struct polymorphic_charcode {
|
||||
virtual ~polymorphic_charcode();
|
||||
|
||||
// Helper function to decode a single char.
|
||||
charcode_error promote(char nc, codepoint &wc) {
|
||||
auto uc = static_cast<unsigned char>(nc);
|
||||
if(uc <= 0x7F && preserves_7bit_units) {
|
||||
wc = uc;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
code_seq<const char> nseq{&nc, &nc + 1};
|
||||
code_seq<codepoint> wseq{&wc, &wc + 1};
|
||||
__mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER;
|
||||
|
||||
if(auto e = decode(nseq, wseq, st); e != charcode_error::null)
|
||||
return e;
|
||||
// This should have read/written exactly one code unit/code point.
|
||||
__ensure(nseq.it == nseq.end);
|
||||
__ensure(wseq.it == wseq.end);
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
// Helper function to decode a single char.
|
||||
charcode_error promote_wtranscode(char nc, wchar_t &wc) {
|
||||
auto uc = static_cast<unsigned char>(nc);
|
||||
if(uc <= 0x7F && preserves_7bit_units) { // TODO: Use "wtranscode_preserves_7bit_units".
|
||||
wc = uc;
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
code_seq<const char> nseq{&nc, &nc + 1};
|
||||
code_seq<wchar_t> wseq{&wc, &wc + 1};
|
||||
__mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER;
|
||||
|
||||
if(auto e = decode_wtranscode(nseq, wseq, st); e != charcode_error::null)
|
||||
return e;
|
||||
// This should have read/written exactly one code unit/code point.
|
||||
__ensure(nseq.it == nseq.end);
|
||||
__ensure(wseq.it == wseq.end);
|
||||
return charcode_error::null;
|
||||
}
|
||||
|
||||
polymorphic_charcode(bool preserves_7bit_units_, bool has_shift_states_)
|
||||
: preserves_7bit_units{preserves_7bit_units_}, has_shift_states{has_shift_states_} { }
|
||||
|
||||
virtual charcode_error decode(code_seq<const char> &nseq, code_seq<codepoint> &wseq,
|
||||
__mlibc_mbstate &st) = 0;
|
||||
|
||||
virtual charcode_error decode_wtranscode(code_seq<const char> &nseq, code_seq<wchar_t> &wseq,
|
||||
__mlibc_mbstate &st) = 0;
|
||||
|
||||
virtual charcode_error decode_wtranscode_length(code_seq<const char> &nseq, size_t *n,
|
||||
__mlibc_mbstate &st) = 0;
|
||||
|
||||
virtual charcode_error encode_wtranscode(code_seq<char> &nseq, code_seq<const wchar_t> &wseq,
|
||||
__mlibc_mbstate &st) = 0;
|
||||
|
||||
virtual charcode_error encode_wtranscode_length(code_seq<const wchar_t> &wseq, size_t *n,
|
||||
__mlibc_mbstate &st) = 0;
|
||||
|
||||
// True if promotion only zero-extends units below 0x7F.
|
||||
const bool preserves_7bit_units;
|
||||
|
||||
// Whether the encoding has shift states.
|
||||
const bool has_shift_states;
|
||||
};
|
||||
|
||||
polymorphic_charcode *current_charcode();
|
||||
|
||||
// Similar to polymorphic_charcode but for wchar_t. Note that this encoding is fixed per-platform;
|
||||
// thus, it does not need to be polymorphic.
|
||||
struct wide_charcode {
|
||||
charcode_error promote(wchar_t nc, codepoint &wc);
|
||||
};
|
||||
|
||||
wide_charcode *platform_wide_charcode();
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_CHARCODE_HPP
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef MLIBC_CHARSET_HPP
|
||||
#define MLIBC_CHARSET_HPP
|
||||
|
||||
#include <mlibc/charcode.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
// Represents the charset of a certain locale. We define the charset as
|
||||
// a set of characters, together with their properties and conversion rules
|
||||
// *but not* their encoding (e.g. to UTF-8 or UTF-16).
|
||||
struct charset {
|
||||
// Returns true iif the meaning of the first 0x7F characters matches ASCII.
|
||||
bool is_ascii_superset();
|
||||
|
||||
bool is_alpha(codepoint c);
|
||||
bool is_digit(codepoint c);
|
||||
bool is_xdigit(codepoint c);
|
||||
bool is_alnum(codepoint c);
|
||||
bool is_punct(codepoint c);
|
||||
bool is_graph(codepoint c);
|
||||
bool is_blank(codepoint c);
|
||||
bool is_space(codepoint c);
|
||||
bool is_print(codepoint c);
|
||||
|
||||
bool is_lower(codepoint c);
|
||||
bool is_upper(codepoint c);
|
||||
codepoint to_lower(codepoint c);
|
||||
codepoint to_upper(codepoint c);
|
||||
};
|
||||
|
||||
charset *current_charset();
|
||||
|
||||
// The property if a character is a control character is locale-independent.
|
||||
inline bool generic_is_control(codepoint c) {
|
||||
return (c <= 0x1F) || (c == 0x7F) || (c >= 0x80 && c <= 0x9F);
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_CHARSET_HPP
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef MLIBC_DEBUG_HPP
|
||||
#define MLIBC_DEBUG_HPP
|
||||
|
||||
#include <frg/logging.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct InfoSink {
|
||||
// constexpr so that this can be initialized statically.
|
||||
constexpr InfoSink() = default;
|
||||
|
||||
void operator() (const char *message);
|
||||
};
|
||||
|
||||
struct PanicSink {
|
||||
// constexpr so that this can be initialized statically.
|
||||
constexpr PanicSink() = default;
|
||||
|
||||
void operator() (const char *message);
|
||||
};
|
||||
|
||||
extern frg::stack_buffer_logger<InfoSink, 512> infoLogger;
|
||||
extern frg::stack_buffer_logger<PanicSink, 512> panicLogger;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_DEBUG_HPP
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef MLIBC_FILE_WINDOW
|
||||
#define MLIBC_FILE_WINDOW
|
||||
|
||||
#include <abi-bits/fcntl.h>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
#include <internal-config.h>
|
||||
|
||||
struct file_window {
|
||||
file_window(const char *path) {
|
||||
int fd;
|
||||
if(mlibc::sys_open(path, O_RDONLY, 0, &fd))
|
||||
mlibc::panicLogger() << "mlibc: Error opening file_window to "
|
||||
<< path << frg::endlog;
|
||||
|
||||
if(!mlibc::sys_stat) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
__ensure(!"cannot proceed without sys_stat");
|
||||
}
|
||||
struct stat info;
|
||||
if(mlibc::sys_stat(mlibc::fsfd_target::fd, fd, "", 0, &info))
|
||||
mlibc::panicLogger() << "mlibc: Error getting stats for " << path << frg::endlog;
|
||||
|
||||
#if MLIBC_MAP_FILE_WINDOWS
|
||||
if(mlibc::sys_vm_map(nullptr, (size_t)info.st_size, PROT_READ, MAP_PRIVATE,
|
||||
fd, 0, &_ptr))
|
||||
mlibc::panicLogger() << "mlibc: Error mapping file_window to " << path << frg::endlog;
|
||||
#else
|
||||
_ptr = getAllocator().allocate(info.st_size);
|
||||
__ensure(_ptr);
|
||||
|
||||
size_t progress = 0;
|
||||
size_t st_size = static_cast<size_t>(info.st_size);
|
||||
while(progress < st_size) {
|
||||
ssize_t chunk;
|
||||
if(int e = mlibc::sys_read(fd, reinterpret_cast<char *>(_ptr) + progress,
|
||||
st_size - progress, &chunk); e)
|
||||
mlibc::panicLogger() << "mlibc: Read from file_window failed" << frg::endlog;
|
||||
if(!chunk)
|
||||
break;
|
||||
progress += chunk;
|
||||
}
|
||||
if(progress != st_size)
|
||||
mlibc::panicLogger() << "stat reports " << info.st_size << " but we only read "
|
||||
<< progress << " bytes" << frg::endlog;
|
||||
#endif
|
||||
|
||||
if(mlibc::sys_close(fd))
|
||||
mlibc::panicLogger() << "mlibc: Error closing file_window to " << path << frg::endlog;
|
||||
}
|
||||
|
||||
// TODO: Write destructor to deallocate/unmap memory.
|
||||
|
||||
void *get() {
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void *_ptr;
|
||||
};
|
||||
|
||||
#endif // MLIBC_FILE_WINDOW
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef MLIBC_FSFD_TARGET
|
||||
#define MLIBC_FSFD_TARGET
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
enum class fsfd_target {
|
||||
none,
|
||||
path,
|
||||
fd,
|
||||
fd_path
|
||||
};
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_FSFD_TARGET
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef MLIBC_GETOPT
|
||||
#define MLIBC_GETOPT
|
||||
|
||||
struct option;
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
enum GetoptMode {
|
||||
Short,
|
||||
Long,
|
||||
LongOnly,
|
||||
};
|
||||
|
||||
int getopt_common(int argc, char * const argv[], const char *optstring,
|
||||
const struct option *longopts, int *longindex, enum GetoptMode mode);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_GETOPT
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef MLIBC_GLOBAL_CONFIG
|
||||
#define MLIBC_GLOBAL_CONFIG
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct GlobalConfig {
|
||||
GlobalConfig();
|
||||
|
||||
bool debugMalloc;
|
||||
};
|
||||
|
||||
inline const GlobalConfig &globalConfig() {
|
||||
static GlobalConfig cached;
|
||||
return cached;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MLIBC_GLOBAL_CONFIG
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef MLIBC_INTERNAL_SYSDEPS
|
||||
#define MLIBC_INTERNAL_SYSDEPS
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/vm-flags.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <abi-bits/stat.h>
|
||||
#include <mlibc/fsfd_target.hpp>
|
||||
|
||||
#if defined(__riscv)
|
||||
#include <abi-bits/riscv-hwprobe.h>
|
||||
#include <bits/cpu_set.h>
|
||||
#endif
|
||||
|
||||
namespace [[gnu::visibility("hidden")]] mlibc {
|
||||
|
||||
void sys_libc_log(const char *message);
|
||||
[[noreturn]] void sys_libc_panic();
|
||||
|
||||
int sys_tcb_set(void *pointer);
|
||||
|
||||
[[gnu::weak]] int sys_futex_tid();
|
||||
int sys_futex_wait(int *pointer, int expected, const struct timespec *time);
|
||||
int sys_futex_wake(int *pointer);
|
||||
|
||||
int sys_anon_allocate(size_t size, void **pointer);
|
||||
int sys_anon_free(void *pointer, size_t size);
|
||||
|
||||
int sys_open(const char *pathname, int flags, mode_t mode, int *fd);
|
||||
int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read);
|
||||
int sys_seek(int fd, off_t offset, int whence, off_t *new_offset);
|
||||
int sys_close(int fd);
|
||||
|
||||
[[gnu::weak]] int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags,
|
||||
struct stat *statbuf);
|
||||
// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps
|
||||
int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window);
|
||||
int sys_vm_unmap(void *pointer, size_t size);
|
||||
[[gnu::weak]] int sys_vm_protect(void *pointer, size_t size, int prot);
|
||||
|
||||
#if defined(__riscv)
|
||||
[[gnu::weak]] int sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags);
|
||||
#endif
|
||||
|
||||
} //namespace mlibc
|
||||
|
||||
#endif // MLIBC_INTERNAL_SYSDEPS
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_LOCALE
|
||||
#define MLIBC_LOCALE
|
||||
|
||||
#include <bits/nl_item.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
char *nl_langinfo(nl_item item);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_LOCALE
|
||||
@@ -0,0 +1,129 @@
|
||||
#ifndef MLIBC_LOCK_HPP
|
||||
#define MLIBC_LOCK_HPP
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/tid.hpp>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
// alignas(4) is specified for the benefit of m68k, where default alignment is
|
||||
// 2 bytes for a uint32_t, while the futex syscall requires 4-byte alignment.
|
||||
// It is a no-op on any other architecture.
|
||||
|
||||
template<bool Recursive>
|
||||
struct alignas(4) FutexLockImpl {
|
||||
FutexLockImpl() : _state{0}, _recursion{0} { }
|
||||
|
||||
FutexLockImpl(const FutexLockImpl &) = delete;
|
||||
|
||||
FutexLockImpl &operator= (const FutexLockImpl &) = delete;
|
||||
|
||||
static constexpr uint32_t waitersBit = (1 << 31);
|
||||
static constexpr uint32_t ownerMask = (static_cast<uint32_t>(1) << 30) - 1;
|
||||
|
||||
void lock() {
|
||||
unsigned int this_tid = mlibc::this_tid();
|
||||
unsigned int expected = 0;
|
||||
|
||||
while(true) {
|
||||
if(!expected) {
|
||||
// Try to take the mutex here.
|
||||
if(__atomic_compare_exchange_n(&_state,
|
||||
&expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) {
|
||||
if constexpr (Recursive) {
|
||||
__ensure(!_recursion);
|
||||
_recursion = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
// If this (recursive) mutex is already owned by us, increment the recursion level.
|
||||
if((expected & ownerMask) == this_tid) {
|
||||
if constexpr (Recursive)
|
||||
++_recursion;
|
||||
else
|
||||
mlibc::panicLogger() << "mlibc: FutexLock deadlock detected!" << frg::endlog;
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait on the futex if the waiters flag is set.
|
||||
if(expected & waitersBit) {
|
||||
int e = mlibc::sys_futex_wait((int *)&_state, expected, nullptr);
|
||||
|
||||
// If the wait returns EAGAIN, that means that the waitersBit was just unset by
|
||||
// some other thread. In this case, we should loop back around.
|
||||
// Also loop around in case of a signal interrupting the wait
|
||||
if (e && e != EAGAIN && e != EINTR)
|
||||
mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog;
|
||||
|
||||
// Opportunistically try to take the lock after we wake up.
|
||||
expected = 0;
|
||||
}else{
|
||||
// Otherwise we have to set the waiters flag first.
|
||||
unsigned int desired = expected | waitersBit;
|
||||
if(__atomic_compare_exchange_n((int *)&_state,
|
||||
reinterpret_cast<int*>(&expected), desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
|
||||
expected = desired;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock() {
|
||||
unsigned int this_tid = mlibc::this_tid();
|
||||
unsigned int expected = __atomic_load_n(&_state, __ATOMIC_RELAXED);
|
||||
|
||||
if(!expected) {
|
||||
// Try to take the mutex here.
|
||||
if(__atomic_compare_exchange_n(&_state,
|
||||
&expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) {
|
||||
if constexpr (Recursive)
|
||||
_recursion = 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// If this (recursive) mutex is already owned by us, increment the recursion level.
|
||||
if((expected & ownerMask) == this_tid) {
|
||||
if constexpr (Recursive) {
|
||||
__ensure(!_recursion);
|
||||
++_recursion;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
// Decrement the recursion level and unlock if we hit zero.
|
||||
if constexpr (Recursive) {
|
||||
__ensure(_recursion);
|
||||
if(--_recursion)
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the mutex to the unlocked state.
|
||||
auto state = __atomic_exchange_n(&_state, 0, __ATOMIC_RELEASE);
|
||||
__ensure((state & ownerMask) == mlibc::this_tid());
|
||||
|
||||
if(state & waitersBit) {
|
||||
// Wake the futex if there were waiters. Since the mutex might not exist at this location
|
||||
// anymore, we must conservatively ignore EACCES and EINVAL which may occur as a result.
|
||||
int e = mlibc::sys_futex_wake((int *)&_state);
|
||||
__ensure(e >= 0 || e == EACCES || e == EINVAL);
|
||||
}
|
||||
}
|
||||
private:
|
||||
uint32_t _state;
|
||||
uint32_t _recursion;
|
||||
};
|
||||
|
||||
using FutexLock = FutexLockImpl<false>;
|
||||
using RecursiveFutexLock = FutexLockImpl<true>;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef MLIBC_SEARCH
|
||||
#define MLIBC_SEARCH
|
||||
|
||||
#include <bits/search.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int hcreate_r(size_t num_entries, struct hsearch_data *htab);
|
||||
void hdestroy_r(struct hsearch_data *htab);
|
||||
int hsearch_r(ENTRY item, ACTION action, ENTRY **ret, struct hsearch_data *htab);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_SEARCH
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef MLIBC_STACK_PROTECTOR_HPP
|
||||
#define MLIBC_STACK_PROTECTOR_HPP
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
void initStackGuard(void *);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_STACK_PROTECTOR_HPP
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_STRINGS
|
||||
#define MLIBC_STRINGS
|
||||
|
||||
#include <bits/size_t.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int strncasecmp(const char *a, const char *b, size_t size);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_STRINGS
|
||||
@@ -0,0 +1,165 @@
|
||||
#ifndef MLIBC_STRTOFP_HPP
|
||||
#define MLIBC_STRTOFP_HPP
|
||||
|
||||
#include <string.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
template<typename T>
|
||||
T strtofp(const char *str, char **endptr) {
|
||||
if (strcmp(str, "INF") == 0 || strcmp(str, "inf") == 0) {
|
||||
if (endptr)
|
||||
*endptr = (char *)str + 3;
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
return __builtin_inff();
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return __builtin_inf();
|
||||
else
|
||||
return __builtin_infl();
|
||||
} else if (strcmp(str, "INFINITY") == 0 || strcmp(str, "infinity") == 0) {
|
||||
if (endptr)
|
||||
*endptr = (char *)str + 8;
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
return __builtin_inff();
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return __builtin_inf();
|
||||
else
|
||||
return __builtin_infl();
|
||||
} else if (strncmp(str, "NAN", 3) == 0 || strncmp(str, "nan", 3) == 0) {
|
||||
if (endptr)
|
||||
*endptr = (char *)str + 3;
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
return __builtin_nanf("");
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return __builtin_nan("");
|
||||
else
|
||||
return __builtin_nanl("");
|
||||
}
|
||||
|
||||
bool negative = *str == '-';
|
||||
if (*str == '+' || *str == '-')
|
||||
str++;
|
||||
|
||||
bool hex = false;
|
||||
if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
|
||||
str += 2;
|
||||
hex = true;
|
||||
}
|
||||
|
||||
T result = static_cast<T>(0);
|
||||
|
||||
const char *tmp = str;
|
||||
|
||||
if (!hex) {
|
||||
while (true) {
|
||||
if (!isdigit(*tmp))
|
||||
break;
|
||||
result *= static_cast<T>(10);
|
||||
result += static_cast<T>(*tmp - '0');
|
||||
tmp++;
|
||||
}
|
||||
} else {
|
||||
while (true) {
|
||||
if (!isxdigit(*tmp))
|
||||
break;
|
||||
result *= static_cast<T>(16);
|
||||
result += static_cast<T>(*tmp <= '9' ? (*tmp - '0') : (tolower(*tmp) - 'a' + 10));
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*tmp == '.') {
|
||||
tmp++;
|
||||
|
||||
if (!hex) {
|
||||
T d = static_cast<T>(10);
|
||||
|
||||
while (true) {
|
||||
if (!isdigit(*tmp))
|
||||
break;
|
||||
result += static_cast<T>(*tmp - '0') / d;
|
||||
d *= static_cast<T>(10);
|
||||
tmp++;
|
||||
}
|
||||
} else {
|
||||
T d = static_cast<T>(16);
|
||||
|
||||
while (true) {
|
||||
if (!isxdigit(*tmp))
|
||||
break;
|
||||
result += static_cast<T>(*tmp <= '9' ? (*tmp - '0') : (tolower(*tmp) - 'a' + 10)) / d;
|
||||
d *= static_cast<T>(16);
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hex) {
|
||||
if (*tmp == 'e' || *tmp == 'E') {
|
||||
tmp++;
|
||||
|
||||
bool exp_negative = *tmp == '-';
|
||||
if (*tmp == '+' || *tmp == '-')
|
||||
tmp++;
|
||||
|
||||
int exp = 0;
|
||||
while (true) {
|
||||
if (!isdigit(*tmp))
|
||||
break;
|
||||
exp *= 10;
|
||||
exp += *tmp - '0';
|
||||
tmp++;
|
||||
}
|
||||
|
||||
if (!exp_negative) {
|
||||
for (int i = 0; i < exp; ++i) {
|
||||
result *= static_cast<T>(10);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < exp; ++i) {
|
||||
result /= static_cast<T>(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (*tmp == 'p' || *tmp == 'P') {
|
||||
tmp++;
|
||||
|
||||
bool exp_negative = *tmp == '-';
|
||||
if (*tmp == '+' || *tmp == '-')
|
||||
tmp++;
|
||||
|
||||
int exp = 0;
|
||||
while (true) {
|
||||
if (!isdigit(*tmp))
|
||||
break;
|
||||
exp *= 10;
|
||||
exp += *tmp - '0';
|
||||
tmp++;
|
||||
}
|
||||
|
||||
if (!exp_negative) {
|
||||
for (int i = 0; i < exp; ++i) {
|
||||
result *= static_cast<T>(2);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < exp; ++i) {
|
||||
result /= static_cast<T>(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (endptr)
|
||||
*endptr = const_cast<char *>(tmp);
|
||||
if (negative)
|
||||
result = -result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MLIBC_STRTOFP_HPP
|
||||
@@ -0,0 +1,163 @@
|
||||
#ifndef MLIBC_STRTOL_HPP
|
||||
#define MLIBC_STRTOL_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <ctype.h>
|
||||
#include <wctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
template<typename T> struct int_limits {};
|
||||
|
||||
template<>
|
||||
struct int_limits<long> {
|
||||
static long max() { return LONG_MAX; }
|
||||
static long min() { return LONG_MIN; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct int_limits<unsigned long> {
|
||||
static unsigned long max() { return ULONG_MAX; }
|
||||
static unsigned long min() { return 0; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct int_limits<long long> {
|
||||
static long long max() { return LLONG_MAX; }
|
||||
static long long min() { return LLONG_MIN; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct int_limits<unsigned long long> {
|
||||
static unsigned long long max() { return ULLONG_MAX; }
|
||||
static unsigned long long min() { return 0; }
|
||||
};
|
||||
|
||||
template<typename T> struct char_detail {};
|
||||
|
||||
template<>
|
||||
struct char_detail<char> {
|
||||
static bool isSpace(char c) { return isspace(c); }
|
||||
static bool isDigit(char c) { return isdigit(c); }
|
||||
static bool isHexDigit(char c) { return isxdigit(c); }
|
||||
static bool isLower(char c) { return islower(c); }
|
||||
static bool isUpper(char c) { return isupper(c); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_detail<wchar_t> {
|
||||
static bool isSpace(wchar_t c) { return iswspace(c); }
|
||||
static bool isDigit(wchar_t c) { return iswdigit(c); }
|
||||
static bool isHexDigit(wchar_t c) { return iswxdigit(c); }
|
||||
static bool isLower(wchar_t c) { return iswlower(c); }
|
||||
static bool isUpper(wchar_t c) { return iswupper(c); }
|
||||
};
|
||||
|
||||
template<typename Char> Char widen(char c) { return static_cast<Char>(c); }
|
||||
|
||||
template<typename Return, typename Char>
|
||||
Return stringToInteger(const Char *__restrict nptr, Char **__restrict endptr, int baseInt) {
|
||||
using UnsignedReturn = std::make_unsigned_t<Return>;
|
||||
|
||||
auto base = static_cast<Return>(baseInt);
|
||||
auto s = nptr;
|
||||
|
||||
if (base < 0 || base == 1) {
|
||||
if (endptr)
|
||||
*endptr = const_cast<Char *>(nptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (char_detail<Char>::isSpace(*s))
|
||||
s++;
|
||||
|
||||
bool negative = false;
|
||||
if (*s == widen<Char>('-')) {
|
||||
negative = true;
|
||||
s++;
|
||||
} else if (*s == widen<Char>('+')) {
|
||||
s++;
|
||||
}
|
||||
|
||||
|
||||
bool hasOctalPrefix = s[0] == widen<Char>('0');
|
||||
bool hasHexPrefix = hasOctalPrefix && (s[1] == widen<Char>('x') || s[1] == widen<Char>('X'));
|
||||
bool hasBinPrefix = hasOctalPrefix && (s[1] == widen<Char>('b') || s[1] == widen<Char>('B'));
|
||||
|
||||
// There's two tricky cases we need to keep in mind here:
|
||||
// 1. We should interpret "0x5" as hex 5 rather than octal 0.
|
||||
// 2. We should interpret "0x" as octal 0 (and set endptr correctly).
|
||||
// To deal with 2, we check the charcacter following the hex prefix.
|
||||
if ((base == 0 || base == 16) && hasHexPrefix && char_detail<Char>::isHexDigit(s[2])) {
|
||||
s += 2;
|
||||
base = 16;
|
||||
} else if ((base == 0 || base == 2) && hasBinPrefix) {
|
||||
s += 2;
|
||||
base = 2;
|
||||
} else if ((base == 0 || base == 8) && hasOctalPrefix) {
|
||||
base = 8;
|
||||
} else if (base == 0) {
|
||||
base = 10;
|
||||
}
|
||||
|
||||
// Compute the range of acceptable values.
|
||||
UnsignedReturn cutoff, cutlim;
|
||||
if (std::is_unsigned_v<Return>) {
|
||||
cutoff = int_limits<Return>::max() / base;
|
||||
cutlim = int_limits<Return>::max() % base;
|
||||
} else {
|
||||
Return co = negative ? int_limits<Return>::min() : int_limits<Return>::max();
|
||||
cutlim = negative ? -(co % base) : co % base;
|
||||
co /= negative ? -base : base;
|
||||
cutoff = co;
|
||||
}
|
||||
|
||||
UnsignedReturn totalValue = 0;
|
||||
bool convertedAny = false;
|
||||
bool outOfRange = false;
|
||||
for (Char c = *s; c != widen<Char>('\0'); c = *++s) {
|
||||
UnsignedReturn digitValue;
|
||||
if (char_detail<Char>::isDigit(c))
|
||||
digitValue = c - widen<Char>('0');
|
||||
else if (char_detail<Char>::isUpper(c))
|
||||
digitValue = c - widen<Char>('A') + 10;
|
||||
else if (char_detail<Char>::isLower(c))
|
||||
digitValue = c - widen<Char>('a') + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
if (digitValue >= static_cast<UnsignedReturn>(base))
|
||||
break;
|
||||
|
||||
if (outOfRange) {
|
||||
// The value is already known to be out of range, but we need to keep
|
||||
// consuming characters until we can't (to set endptr correctly).
|
||||
} else if (totalValue > cutoff || (totalValue == cutoff && digitValue > cutlim)) {
|
||||
// The value will be out of range if we accumulate digitValue.
|
||||
outOfRange = true;
|
||||
} else {
|
||||
totalValue = (totalValue * base) + digitValue;
|
||||
convertedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (endptr)
|
||||
*endptr = const_cast<Char *>(convertedAny ? s : nptr);
|
||||
|
||||
if (outOfRange) {
|
||||
errno = ERANGE;
|
||||
|
||||
if (std::is_unsigned_v<Return>) {
|
||||
return int_limits<Return>::max();
|
||||
} else {
|
||||
return negative ? int_limits<Return>::min() : int_limits<Return>::max();
|
||||
}
|
||||
}
|
||||
|
||||
return negative ? -totalValue : totalValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MLIBC_STRTOL_HPP
|
||||
@@ -0,0 +1,370 @@
|
||||
#ifndef MLIBC_SYSDEP_SIGNATURES
|
||||
#define MLIBC_SYSDEP_SIGNATURES
|
||||
|
||||
#include <abi-bits/mode_t.h>
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <abi-bits/resource.h>
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/signal.h>
|
||||
#include <abi-bits/stat.h>
|
||||
#include <abi-bits/uid_t.h>
|
||||
#include <abi-bits/vm-flags.h>
|
||||
#include <bits/ansi/time_t.h>
|
||||
#include <bits/ansi/timespec.h>
|
||||
#include <bits/cpu_set.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <concepts>
|
||||
#include <mlibc-config.h>
|
||||
#include <mlibc/fsfd_target.hpp>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <mlibc/sysdep-tags.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
template<typename Tag>
|
||||
struct SysdepImpl;
|
||||
|
||||
struct NoImpl {};
|
||||
|
||||
template<typename ST, typename Tag>
|
||||
using SysdepOf = std::conditional_t<
|
||||
std::derived_from<ST, Tag>,
|
||||
mlibc::SysdepImpl<Tag>,
|
||||
NoImpl
|
||||
>;
|
||||
|
||||
#define SYSDEP_FUNC(name, ...) template <> struct SysdepImpl<name> { static int operator()(__VA_ARGS__); }
|
||||
#define SYSDEP_FUNC_RET(rettype, name, ...) template <> struct SysdepImpl<name> { static rettype operator()(__VA_ARGS__); }
|
||||
#define SYSDEP_FUNC_NORETURN(name, ...) template <> struct SysdepImpl<name> { [[noreturn]] static void operator()(__VA_ARGS__); }
|
||||
|
||||
SYSDEP_FUNC_RET(void, LibcLog, const char *message);
|
||||
SYSDEP_FUNC_NORETURN(LibcPanic);
|
||||
|
||||
SYSDEP_FUNC_RET(pid_t, FutexTid);
|
||||
SYSDEP_FUNC(AnonAllocate, size_t size, void **pointer);
|
||||
SYSDEP_FUNC(AnonFree, void *pointer, size_t size);
|
||||
SYSDEP_FUNC(Stat, mlibc::fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf);
|
||||
SYSDEP_FUNC(VmMap, void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window);
|
||||
SYSDEP_FUNC(VmUnmap, void *pointer, size_t size);
|
||||
SYSDEP_FUNC(VmProtect, void *pointer, size_t size, int prot);
|
||||
SYSDEP_FUNC(TcbSet, void *pointer);
|
||||
#if defined(__riscv)
|
||||
SYSDEP_FUNC(RiscvHwprobe, struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags);
|
||||
#endif
|
||||
|
||||
// ANSI option sysdeps
|
||||
SYSDEP_FUNC_NORETURN(Exit, int status);
|
||||
SYSDEP_FUNC_NORETURN(ThreadExit);
|
||||
SYSDEP_FUNC(PrepareStack, void **stack, void *entry, void *user_arg, void* tcb, size_t *stack_size, size_t *guard_size, void **stack_base);
|
||||
SYSDEP_FUNC(Clone, void *tcb, pid_t *pid_out, void *stack);
|
||||
SYSDEP_FUNC(FutexWait, int *pointer, int expected, const struct timespec *time);
|
||||
SYSDEP_FUNC(FutexWake, int *pointer, bool all);
|
||||
SYSDEP_FUNC(Open, const char *pathname, int flags, mode_t mode, int *fd);
|
||||
SYSDEP_FUNC(Flock, int fd, int options);
|
||||
SYSDEP_FUNC(OpenDir, const char *path, int *handle);
|
||||
SYSDEP_FUNC(ReadEntries, int handle, void *buffer, size_t max_size, size_t *bytes_read);
|
||||
SYSDEP_FUNC(Read, int fd, void *buf, size_t count, ssize_t *bytes_read);
|
||||
SYSDEP_FUNC(Write, int fd, const void *buf, size_t count, ssize_t *bytes_written);
|
||||
SYSDEP_FUNC(Pread, int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read);
|
||||
SYSDEP_FUNC(Seek, int fd, off_t offset, int whence, off_t *new_offset);
|
||||
SYSDEP_FUNC(Close, int fd);
|
||||
SYSDEP_FUNC(ClockGet, int clock, time_t *secs, long *nanos);
|
||||
SYSDEP_FUNC(ClockSet, int clock, time_t secs, long nanos);
|
||||
SYSDEP_FUNC(ClockGetres, int clock, time_t *secs, long *nanos);
|
||||
SYSDEP_FUNC(Sleep, time_t *secs, long *nanos);
|
||||
SYSDEP_FUNC(Isatty, int fd);
|
||||
SYSDEP_FUNC(Rmdir, const char *path);
|
||||
SYSDEP_FUNC(Unlinkat, int dirfd, const char *path, int flags);
|
||||
SYSDEP_FUNC(Rename, const char *path, const char *new_path);
|
||||
SYSDEP_FUNC(FdToPath, int fd, char **out);
|
||||
SYSDEP_FUNC(Sigprocmask, int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve);
|
||||
SYSDEP_FUNC(Sigaction, int, const struct sigaction *__restrict, struct sigaction *__restrict);
|
||||
SYSDEP_FUNC(Fork, pid_t *child);
|
||||
SYSDEP_FUNC(Waitpid, pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid);
|
||||
SYSDEP_FUNC(Execve, const char *path, char *const argv[], char *const envp[]);
|
||||
SYSDEP_FUNC_RET(void, Yield);
|
||||
SYSDEP_FUNC_RET(pid_t, GetPid);
|
||||
SYSDEP_FUNC(Kill, pid_t, int);
|
||||
|
||||
#if MLIBC_BUILDING_RTLD
|
||||
SYSDEP_FUNC(VmReadahead, void *pointer, size_t size);
|
||||
#endif /* MLIBC_BUILDING_RTLD */
|
||||
|
||||
#if __MLIBC_POSIX_OPTION
|
||||
SYSDEP_FUNC(Readv, int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read);
|
||||
SYSDEP_FUNC(Writev, int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written);
|
||||
SYSDEP_FUNC(Pwrite, int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read);
|
||||
SYSDEP_FUNC(Access, const char *path, int mode);
|
||||
SYSDEP_FUNC(Faccessat, int dirfd, const char *pathname, int mode, int flags);
|
||||
SYSDEP_FUNC(Dup, int fd, int flags, int *newfd);
|
||||
SYSDEP_FUNC(Dup2, int fd, int flags, int newfd);
|
||||
SYSDEP_FUNC(Statvfs, const char *path, struct statvfs *out);
|
||||
SYSDEP_FUNC(Fstatvfs, int fd, struct statvfs *out);
|
||||
SYSDEP_FUNC(Readlink, const char *path, void *buffer, size_t max_size, ssize_t *length);
|
||||
SYSDEP_FUNC(Readlinkat, int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length);
|
||||
SYSDEP_FUNC(Truncate, const char *path, off_t length);
|
||||
SYSDEP_FUNC(Ftruncate, int fd, size_t size);
|
||||
SYSDEP_FUNC(Fallocate, int fd, off_t offset, size_t size);
|
||||
SYSDEP_FUNC(Openat, int dirfd, const char *path, int flags, mode_t mode, int *fd);
|
||||
SYSDEP_FUNC(Socket, int family, int type, int protocol, int *fd);
|
||||
SYSDEP_FUNC(MsgSend, int fd, const struct msghdr *hdr, int flags, ssize_t *length);
|
||||
SYSDEP_FUNC(Sendto, int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length);
|
||||
SYSDEP_FUNC(MsgRecv, int fd, struct msghdr *hdr, int flags, ssize_t *length);
|
||||
SYSDEP_FUNC(Recvfrom, int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length);
|
||||
SYSDEP_FUNC(Listen, int fd, int backlog);
|
||||
SYSDEP_FUNC_RET(gid_t, GetGid);
|
||||
SYSDEP_FUNC_RET(gid_t, GetEgid);
|
||||
SYSDEP_FUNC_RET(uid_t, GetUid);
|
||||
SYSDEP_FUNC_RET(uid_t, GetEuid);
|
||||
SYSDEP_FUNC_RET(pid_t, GetTid);
|
||||
SYSDEP_FUNC_RET(pid_t, GetPpid);
|
||||
SYSDEP_FUNC(GetPgid, pid_t pid, pid_t *pgid);
|
||||
SYSDEP_FUNC(GetSid, pid_t pid, pid_t *sid);
|
||||
SYSDEP_FUNC(SetPgid, pid_t pid, pid_t pgid);
|
||||
SYSDEP_FUNC(SetUid, uid_t uid);
|
||||
SYSDEP_FUNC(SetEuid, uid_t euid);
|
||||
SYSDEP_FUNC(SetGid, gid_t gid);
|
||||
SYSDEP_FUNC(SetEgid, gid_t egid);
|
||||
SYSDEP_FUNC(GetGroups, size_t size, gid_t *list, int *ret);
|
||||
SYSDEP_FUNC(Fexecve, int fd, char *const argv[], char *const envp[]);
|
||||
SYSDEP_FUNC(Pselect, int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events);
|
||||
SYSDEP_FUNC(GetRusage, int scope, struct rusage *usage);
|
||||
SYSDEP_FUNC(GetRlimit, int resource, struct rlimit *limit);
|
||||
SYSDEP_FUNC(SetRlimit, int resource, const struct rlimit *limit);
|
||||
SYSDEP_FUNC(GetPriority, int which, id_t who, int *value);
|
||||
SYSDEP_FUNC(SetPriority, int which, id_t who, int prio);
|
||||
SYSDEP_FUNC(GetSchedparam, void *tcb, int *policy, struct sched_param *param);
|
||||
SYSDEP_FUNC(SetSchedparam, void *tcb, int policy, const struct sched_param *param);
|
||||
SYSDEP_FUNC(GetScheduler, pid_t pid, int *policy);
|
||||
SYSDEP_FUNC(SetScheduler, pid_t pid, int policy, const struct sched_param *param);
|
||||
SYSDEP_FUNC(GetParam, pid_t pid, struct sched_param *param);
|
||||
SYSDEP_FUNC(SetParam, pid_t pid, const struct sched_param *param);
|
||||
SYSDEP_FUNC(GetMaxPriority, int policy, int *out);
|
||||
SYSDEP_FUNC(GetMinPriority, int policy, int *out);
|
||||
SYSDEP_FUNC(GetCwd, char *buffer, size_t size);
|
||||
SYSDEP_FUNC(Chdir, const char *path);
|
||||
SYSDEP_FUNC(Fchdir, int fd);
|
||||
SYSDEP_FUNC(Chroot, const char *path);
|
||||
SYSDEP_FUNC(Mkdir, const char *path, mode_t mode);
|
||||
SYSDEP_FUNC(Mkdirat, int dirfd, const char *path, mode_t mode);
|
||||
SYSDEP_FUNC(Link, const char *old_path, const char *new_path);
|
||||
SYSDEP_FUNC(Linkat, int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags);
|
||||
SYSDEP_FUNC(Symlink, const char *target_path, const char *link_path);
|
||||
SYSDEP_FUNC(Symlinkat, const char *target_path, int dirfd, const char *link_path);
|
||||
SYSDEP_FUNC(Renameat, int olddirfd, const char *old_path, int newdirfd, const char *new_path);
|
||||
SYSDEP_FUNC(Fcntl, int fd, int request, va_list args, int *result);
|
||||
SYSDEP_FUNC(Ttyname, int fd, char *buf, size_t size);
|
||||
SYSDEP_FUNC(Fadvise, int fd, off_t offset, off_t length, int advice);
|
||||
SYSDEP_FUNC_RET(void, Sync);
|
||||
SYSDEP_FUNC(Fsync, int fd);
|
||||
SYSDEP_FUNC(Fdatasync, int fd);
|
||||
SYSDEP_FUNC(Chmod, const char *pathname, mode_t mode);
|
||||
SYSDEP_FUNC(Fchmod, int fd, mode_t mode);
|
||||
SYSDEP_FUNC(Fchmodat, int fd, const char *pathname, mode_t mode, int flags);
|
||||
SYSDEP_FUNC(Utimensat, int dirfd, const char *pathname, const struct timespec times[2], int flags);
|
||||
SYSDEP_FUNC(Mlock, const void *addr, size_t length);
|
||||
SYSDEP_FUNC(Munlock, const void *addr, size_t length);
|
||||
SYSDEP_FUNC(Mlockall, int flags);
|
||||
SYSDEP_FUNC(Munlockall);
|
||||
SYSDEP_FUNC(Mincore, void *addr, size_t length, unsigned char *vec);
|
||||
SYSDEP_FUNC(VmRemap, void *pointer, size_t size, size_t new_size, void **window);
|
||||
SYSDEP_FUNC(SetSid, pid_t *sid);
|
||||
SYSDEP_FUNC(Tcgetattr, int fd, struct termios *attr);
|
||||
SYSDEP_FUNC(Tcsetattr, int, int, const struct termios *attr);
|
||||
SYSDEP_FUNC(Tcsendbreak, int fd, int dur);
|
||||
SYSDEP_FUNC(Tcflow, int, int);
|
||||
SYSDEP_FUNC(Tcflush, int fd, int queue);
|
||||
SYSDEP_FUNC(Tcdrain, int);
|
||||
SYSDEP_FUNC(Tcgetwinsize, int fd, struct winsize *winsz);
|
||||
SYSDEP_FUNC(Tcsetwinsize, int fd, const struct winsize *winsz);
|
||||
SYSDEP_FUNC(Pipe, int *fds, int flags);
|
||||
SYSDEP_FUNC(Socketpair, int domain, int type_and_flags, int proto, int *fds);
|
||||
SYSDEP_FUNC(Poll, struct pollfd *fds, nfds_t count, int timeout, int *num_events);
|
||||
SYSDEP_FUNC(Ppoll, struct pollfd *fds, nfds_t count, const struct timespec *ts, const sigset_t *mask, int *num_events);
|
||||
SYSDEP_FUNC(Ioctl, int fd, unsigned long request, void *arg, int *result);
|
||||
SYSDEP_FUNC(PosixDevctl, int fd, int dcmd, void *__restrict dev_data_ptr, size_t nbyte, int *__restrict dev_info_ptr);
|
||||
SYSDEP_FUNC(GetSockopt, int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size);
|
||||
SYSDEP_FUNC(SetSockopt, int fd, int layer, int number, const void *buffer, socklen_t size);
|
||||
SYSDEP_FUNC(Shutdown, int sockfd, int how);
|
||||
SYSDEP_FUNC(Sockatmark, int sockfd, int *out);
|
||||
SYSDEP_FUNC(ThreadSigmask, int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve);
|
||||
SYSDEP_FUNC(Sigtimedwait, const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal);
|
||||
SYSDEP_FUNC(Accept, int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags);
|
||||
SYSDEP_FUNC(Bind, int fd, const struct sockaddr *addr_ptr, socklen_t addr_length);
|
||||
SYSDEP_FUNC(Connect, int fd, const struct sockaddr *addr_ptr, socklen_t addr_length);
|
||||
SYSDEP_FUNC(Sockname, int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length);
|
||||
SYSDEP_FUNC(Peername, int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length);
|
||||
SYSDEP_FUNC(GetHostname, char *buffer, size_t bufsize);
|
||||
SYSDEP_FUNC(SetHostname, const char *buffer, size_t bufsize);
|
||||
SYSDEP_FUNC(Mkfifoat, int dirfd, const char *path, mode_t mode);
|
||||
SYSDEP_FUNC(GetEntropy, void *buffer, size_t length);
|
||||
SYSDEP_FUNC(Mknodat, int dirfd, const char *path, int mode, int dev);
|
||||
SYSDEP_FUNC(Umask, mode_t mode, mode_t *old);
|
||||
SYSDEP_FUNC(BeforeCancellableSyscall, ucontext_t *uctx);
|
||||
SYSDEP_FUNC(Tgkill, int tgid, int tid, int sig);
|
||||
SYSDEP_FUNC(Fchownat, int dirfd, const char *pathname, uid_t owner, gid_t group, int flags);
|
||||
SYSDEP_FUNC(Sigaltstack, const stack_t *ss, stack_t *oss);
|
||||
SYSDEP_FUNC(Sigsuspend, const sigset_t *set);
|
||||
SYSDEP_FUNC(Sigpending, sigset_t *set);
|
||||
SYSDEP_FUNC(Sigqueue, pid_t pid, int sig, const union sigval val);
|
||||
SYSDEP_FUNC(SetGroups, size_t size, const gid_t *list);
|
||||
SYSDEP_FUNC(MemfdCreate, const char *name, int flags, int *fd);
|
||||
SYSDEP_FUNC(Madvise, void *addr, size_t length, int advice);
|
||||
SYSDEP_FUNC(PosixMadvise, void *addr, size_t length, int advice);
|
||||
SYSDEP_FUNC(Msync, void *addr, size_t length, int flags);
|
||||
SYSDEP_FUNC(GetItimer, int which, struct itimerval *curr_value);
|
||||
SYSDEP_FUNC(SetItimer, int which, const struct itimerval *new_value, struct itimerval *old_value);
|
||||
SYSDEP_FUNC(TimerCreate, clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res);
|
||||
SYSDEP_FUNC(TimerSettime, timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old);
|
||||
SYSDEP_FUNC(TimerGettime, timer_t t, struct itimerspec *val);
|
||||
SYSDEP_FUNC(TimerDelete, timer_t t);
|
||||
SYSDEP_FUNC(TimerGetoverrun, timer_t t, int *out);
|
||||
SYSDEP_FUNC(Times, struct tms *tms, clock_t *out);
|
||||
SYSDEP_FUNC(Uname, struct utsname *buf);
|
||||
SYSDEP_FUNC(Pause);
|
||||
SYSDEP_FUNC(SetResuid, uid_t ruid, uid_t euid, uid_t suid);
|
||||
SYSDEP_FUNC(SetResgid, gid_t rgid, gid_t egid, gid_t sgid);
|
||||
SYSDEP_FUNC(GetResuid, uid_t *ruid, uid_t *euid, uid_t *suid);
|
||||
SYSDEP_FUNC(GetResgid, gid_t *rgid, gid_t *egid, gid_t *sgid);
|
||||
SYSDEP_FUNC(SetReuid, uid_t ruid, uid_t euid);
|
||||
SYSDEP_FUNC(SetRegid, gid_t rgid, gid_t egid);
|
||||
SYSDEP_FUNC(GetLoginR, char *name, size_t name_len);
|
||||
SYSDEP_FUNC(IfIndextoname, unsigned int index, char *name);
|
||||
SYSDEP_FUNC(IfNametoindex, const char *name, unsigned int *ret);
|
||||
SYSDEP_FUNC(Ptsname, int fd, char *buffer, size_t length);
|
||||
SYSDEP_FUNC(Unlockpt, int fd);
|
||||
SYSDEP_FUNC(ThreadSetname, void *tcb, const char *name);
|
||||
SYSDEP_FUNC(ThreadGetname, void *tcb, char *name, size_t size);
|
||||
SYSDEP_FUNC(Sysconf, int num, long *ret);
|
||||
SYSDEP_FUNC(Semget, key_t key, int n, int fl, int *id);
|
||||
SYSDEP_FUNC(Semctl, int semid, int semnum, int cmd, void *semun, int *ret);
|
||||
SYSDEP_FUNC(GetAffinity, pid_t pid, size_t cpusetsize, cpu_set_t *mask);
|
||||
SYSDEP_FUNC(GetThreadaffinity, pid_t tid, size_t cpusetsize, cpu_set_t *mask);
|
||||
SYSDEP_FUNC(SetAffinity, pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
|
||||
SYSDEP_FUNC(SetThreadaffinity, pid_t tid, size_t cpusetsize, const cpu_set_t *mask);
|
||||
SYSDEP_FUNC(GetCurrentStackInfo, void **stack_base, size_t *stack_size);
|
||||
SYSDEP_FUNC(Waitid, idtype_t idtype, id_t id, siginfo_t *info, int options);
|
||||
SYSDEP_FUNC(NameToHandleAt, int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags);
|
||||
SYSDEP_FUNC(Splice, int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out);
|
||||
SYSDEP_FUNC(Shmat, void **seg_start, int shmid, const void *shmaddr, int shmflg);
|
||||
SYSDEP_FUNC(Shmctl, int *idx, int shmid, int cmd, struct shmid_ds *buf);
|
||||
SYSDEP_FUNC(Shmdt, const void *shmaddr);
|
||||
SYSDEP_FUNC(Shmget, int *shm_id, key_t key, size_t size, int shmflg);
|
||||
SYSDEP_FUNC(InetConfigured, bool *ipv4, bool *ipv6);
|
||||
SYSDEP_FUNC(Nice, int nice, int *new_nice);
|
||||
SYSDEP_FUNC(Openpt, int oflags, int *fd);
|
||||
SYSDEP_FUNC(Msgctl, int q, int cmd, struct msqid_ds *buf);
|
||||
SYSDEP_FUNC(Msgget, key_t k, int flag, int *out);
|
||||
SYSDEP_FUNC(Msgrcv, int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg, ssize_t *out);
|
||||
SYSDEP_FUNC(Msgsnd, int msqid, const void *msgp, size_t msgsz, int msgflg);
|
||||
SYSDEP_FUNC(MqOpen, const char *name, int oflag, mode_t mode, mq_attr *attr, mqd_t *out);
|
||||
SYSDEP_FUNC(MqUnlink, const char *name);
|
||||
SYSDEP_FUNC(MqReceive, mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
|
||||
SYSDEP_FUNC(MqGetAttr, mqd_t mqdes, mq_attr *mqstat);
|
||||
SYSDEP_FUNC(MqSetAttr, mqd_t mqdes, const mq_attr *mqstat, mq_attr *omqstat);
|
||||
#endif // __MLIBC_POSIX_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
SYSDEP_FUNC(InotifyCreate, int flags, int *fd);
|
||||
SYSDEP_FUNC(InotifyAddWatch, int ifd, const char *path, uint32_t mask, int *wd);
|
||||
SYSDEP_FUNC(InotifyRmWatch, int ifd, int wd);
|
||||
SYSDEP_FUNC(Mount, const char *source, const char *target, const char *fstype, unsigned long flags, const void *data);
|
||||
SYSDEP_FUNC(Umount2, const char *target, int flags);
|
||||
SYSDEP_FUNC(Ptrace, long req, pid_t pid, void *addr, void *data, long *out);
|
||||
SYSDEP_FUNC(Capget, cap_user_header_t hdrp, cap_user_data_t datap);
|
||||
SYSDEP_FUNC(Capset, cap_user_header_t hdrp, const cap_user_data_t datap);
|
||||
SYSDEP_FUNC(Prctl, int option, va_list va, int *out);
|
||||
SYSDEP_FUNC(InitModule, void *module, unsigned long length, const char *args);
|
||||
SYSDEP_FUNC(DeleteModule, const char *name, unsigned flags);
|
||||
SYSDEP_FUNC(Klogctl, int type, char *bufp, int len, int *out);
|
||||
SYSDEP_FUNC(Getcpu, int *cpu);
|
||||
SYSDEP_FUNC(Sysinfo, struct sysinfo *info);
|
||||
SYSDEP_FUNC(Swapon, const char *path, int flags);
|
||||
SYSDEP_FUNC(Swapoff, const char *path);
|
||||
SYSDEP_FUNC(Setxattr, const char *path, const char *name, const void *val, size_t size, int flags);
|
||||
SYSDEP_FUNC(Lsetxattr, const char *path, const char *name, const void *val, size_t size, int flags);
|
||||
SYSDEP_FUNC(Fsetxattr, int fd, const char *name, const void *val, size_t size, int flags);
|
||||
SYSDEP_FUNC(Getxattr, const char *path, const char *name, void *val, size_t size, ssize_t *nread);
|
||||
SYSDEP_FUNC(Lgetxattr, const char *path, const char *name, void *val, size_t size, ssize_t *nread);
|
||||
SYSDEP_FUNC(Fgetxattr, int fd, const char *name, void *val, size_t size, ssize_t *nread);
|
||||
SYSDEP_FUNC(Listxattr, const char *path, char *list, size_t size, ssize_t *nread);
|
||||
SYSDEP_FUNC(Llistxattr, const char *path, char *list, size_t size, ssize_t *nread);
|
||||
SYSDEP_FUNC(Flistxattr, int fd, char *list, size_t size, ssize_t *nread);
|
||||
SYSDEP_FUNC(Removexattr, const char *path, const char *name);
|
||||
SYSDEP_FUNC(Lremovexattr, const char *path, const char *name);
|
||||
SYSDEP_FUNC(Fremovexattr, int fd, const char *name);
|
||||
SYSDEP_FUNC(Statfs, const char *path, struct statfs *buf);
|
||||
SYSDEP_FUNC(Fstatfs, int fd, struct statfs *buf);
|
||||
SYSDEP_FUNC(Statx, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf);
|
||||
SYSDEP_FUNC(Getifaddrs, struct ifaddrs **);
|
||||
SYSDEP_FUNC(Sendfile, int outfd, int infd, off_t *offset, size_t count, ssize_t *out);
|
||||
SYSDEP_FUNC(Syncfs, int fd);
|
||||
SYSDEP_FUNC(Unshare, int flags);
|
||||
SYSDEP_FUNC(SetNs, int fd, int nstype);
|
||||
SYSDEP_FUNC(PidfdOpen, pid_t pid, unsigned int flags, int *outfd);
|
||||
SYSDEP_FUNC(PidfdGetpid, int fd, pid_t *outpid);
|
||||
SYSDEP_FUNC(PidfdSendSignal, int pidfd, int sig, siginfo_t *info, unsigned int flags);
|
||||
SYSDEP_FUNC(ProcessVmReadv, pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out);
|
||||
SYSDEP_FUNC(ProcessVmWritev, pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out);
|
||||
SYSDEP_FUNC(Fsopen, const char *fsname, unsigned int flags, int *outfd);
|
||||
SYSDEP_FUNC(Fsmount, int fsfd, unsigned int flags, unsigned int mountflags, int *outfd);
|
||||
SYSDEP_FUNC(Fsconfig, int fd, unsigned int cmd, const char *key, const void *val, int aux);
|
||||
SYSDEP_FUNC(MoveMount, int from_dirfd, const char *from_path, int to_dirfd, const char *to_path, unsigned int flags);
|
||||
SYSDEP_FUNC(OpenTree, int dirfd, const char *path, unsigned int flags, int *outfd);
|
||||
SYSDEP_FUNC(CopyFileRange, int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t count, unsigned int flags, ssize_t *bytes_copied);
|
||||
#endif // __MLIBC_LINUX_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_EPOLL_OPTION
|
||||
SYSDEP_FUNC(EpollCreate, int flags, int *fd);
|
||||
SYSDEP_FUNC(EpollCtl, int epfd, int mode, int fd, struct epoll_event *ev);
|
||||
SYSDEP_FUNC(EpollPwait, int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised);
|
||||
#endif // __MLIBC_LINUX_EPOLL_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_TIMERFD_OPTION
|
||||
SYSDEP_FUNC(TimerfdCreate, int clockid, int flags, int *fd);
|
||||
SYSDEP_FUNC(TimerfdSettime, int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue);
|
||||
SYSDEP_FUNC(TimerfdGettime, int fd, struct itimerspec *its);
|
||||
#endif // __MLIBC_LINUX_TIMERFD_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_SIGNALFD_OPTION
|
||||
SYSDEP_FUNC(SignalfdCreate, const sigset_t *, int flags, int *fd);
|
||||
#endif // __MLIBC_LINUX_SIGNALFD_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_EVENTFD_OPTION
|
||||
SYSDEP_FUNC(EventfdCreate, unsigned int initval, int flags, int *fd);
|
||||
#endif // __MLIBC_LINUX_EVENTFD_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_REBOOT_OPTION
|
||||
SYSDEP_FUNC(Reboot, int cmd);
|
||||
#endif // __MLIBC_LINUX_REBOOT_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_WRAPPERS_OPTION
|
||||
SYSDEP_FUNC(RtSigqueueinfo, pid_t tgid, int sig, siginfo_t *uinfo);
|
||||
SYSDEP_FUNC(RtTgSigqueueinfo, pid_t tgid, pid_t tid, int sig, siginfo_t *uinfo);
|
||||
#endif // __MLIBC_LINUX_WRAPPERS_OPTION
|
||||
|
||||
#if __MLIBC_BSD_OPTION
|
||||
SYSDEP_FUNC(Brk, void **out);
|
||||
SYSDEP_FUNC(GetLoadavg, double *samples);
|
||||
SYSDEP_FUNC(Openpty, int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win);
|
||||
#endif // __MLIBC_BSD_OPTION
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
SYSDEP_FUNC(Personality, unsigned long persona, int *out);
|
||||
SYSDEP_FUNC(Ioperm, unsigned long int from, unsigned long int num, int turn_on);
|
||||
SYSDEP_FUNC(Iopl, int level);
|
||||
#ifdef __riscv
|
||||
SYSDEP_FUNC(RiscvFlushIcache, void *start, void *end, unsigned long flags);
|
||||
#endif // __riscv
|
||||
#endif // __MLIBC_GLIBC_OPTION
|
||||
|
||||
#undef SYSDEP_FUNC
|
||||
#undef SYSDEP_FUNC_RET
|
||||
#undef SYSDEP_FUNC_NORETURN
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif /* MLIBC_SYSDEP_SIGNATURES */
|
||||
@@ -0,0 +1,703 @@
|
||||
#ifndef MLIBC_SYSDEP_TAGS
|
||||
#define MLIBC_SYSDEP_TAGS
|
||||
|
||||
#include <abi-bits/mode_t.h>
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <abi-bits/resource.h>
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/signal.h>
|
||||
#include <abi-bits/stat.h>
|
||||
#include <abi-bits/uid_t.h>
|
||||
#include <abi-bits/vm-flags.h>
|
||||
#include <bits/ansi/time_t.h>
|
||||
#include <bits/ansi/timespec.h>
|
||||
#include <bits/cpu_set.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <concepts>
|
||||
#include <mlibc-config.h>
|
||||
#include <mlibc/fsfd_target.hpp>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// [[noreturn]] void sys_exit(int status);
|
||||
struct Exit { static constexpr bool is_noreturn = true; };
|
||||
// [[noreturn]] void sys_thread_exit();
|
||||
struct ThreadExit { static constexpr bool is_noreturn = true; };
|
||||
|
||||
// If *stack is not null, it should point to the lowest addressable byte of the stack.
|
||||
// Returns the new stack pointer in *stack and the stack base in *stack_base.
|
||||
// int sys_prepare_stack(void **stack, void *entry, void *user_arg, void* tcb, size_t *stack_size, size_t *guard_size, void **stack_base);
|
||||
struct PrepareStack {};
|
||||
|
||||
// int sys_clone(void *tcb, pid_t *pid_out, void *stack);
|
||||
struct Clone {};
|
||||
|
||||
// int sys_futex_wait(int *pointer, int expected, const struct timespec *time);
|
||||
struct FutexWait {};
|
||||
// int sys_futex_wake(int *pointer, bool all);
|
||||
struct FutexWake {};
|
||||
|
||||
// int sys_open(const char *pathname, int flags, mode_t mode, int *fd);
|
||||
struct Open {};
|
||||
// int sys_flock(int fd, int options);
|
||||
struct Flock {};
|
||||
|
||||
// int sys_open_dir(const char *path, int *handle);
|
||||
struct OpenDir {};
|
||||
// int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read);
|
||||
struct ReadEntries {};
|
||||
|
||||
// int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read);
|
||||
struct Read {};
|
||||
|
||||
// int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written);
|
||||
struct Write {};
|
||||
// int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read);
|
||||
struct Pread {};
|
||||
|
||||
// int sys_seek(int fd, off_t offset, int whence, off_t *new_offset);
|
||||
struct Seek {};
|
||||
// int sysdep<Close>(int fd);
|
||||
struct Close {};
|
||||
|
||||
// int sys_clock_get(int clock, time_t *secs, long *nanos);
|
||||
struct ClockGet {};
|
||||
// int sys_clock_set(int clock, time_t secs, long nanos);
|
||||
struct ClockSet {};
|
||||
// int sys_clock_getres(int clock, time_t *secs, long *nanos);
|
||||
struct ClockGetres {};
|
||||
// int sys_sleep(time_t *secs, long *nanos);
|
||||
struct Sleep {};
|
||||
// // In contrast to the isatty() library function, the sysdep function uses return value
|
||||
// // zero (and not one) to indicate that the file is a terminal.
|
||||
// int sys_isatty(int fd);
|
||||
struct Isatty {};
|
||||
// int sys_rmdir(const char *path);
|
||||
struct Rmdir {};
|
||||
// int sys_unlinkat(int dirfd, const char *path, int flags);
|
||||
struct Unlinkat {};
|
||||
// int sys_rename(const char *path, const char *new_path);
|
||||
struct Rename {};
|
||||
// int sys_fd_to_path(int fd, char **path);
|
||||
struct FdToPath {};
|
||||
|
||||
// int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve);
|
||||
struct Sigprocmask {};
|
||||
// int sys_sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict);
|
||||
struct Sigaction {};
|
||||
|
||||
// int sys_fork(pid_t *child);
|
||||
struct Fork {};
|
||||
// int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid);
|
||||
struct Waitpid {};
|
||||
// int sys_execve(const char *path, char *const argv[], char *const envp[]);
|
||||
struct Execve {};
|
||||
// void sys_yield();
|
||||
struct Yield {};
|
||||
|
||||
// pid_t sys_getpid();
|
||||
struct GetPid {};
|
||||
// int sys_kill(pid_t, int);
|
||||
struct Kill {};
|
||||
|
||||
// int sys_tcb_set(void *pointer);
|
||||
struct TcbSet {};
|
||||
|
||||
#if MLIBC_BUILDING_RTLD
|
||||
// int sys_vm_readahead(void *pointer, size_t size);
|
||||
struct VmReadahead {};
|
||||
#endif /* MLIBC_BUILDING_RTLD */
|
||||
|
||||
// void sys_libc_log(const char *message);
|
||||
struct LibcLog {};
|
||||
// [[noreturn]] void sys_libc_panic();
|
||||
struct LibcPanic { static constexpr bool is_noreturn = true; };
|
||||
|
||||
// int sys_futex_tid();
|
||||
struct FutexTid {};
|
||||
|
||||
// int sys_anon_allocate(size_t size, void **pointer);
|
||||
struct AnonAllocate {};
|
||||
// int sys_anon_free(void *pointer, size_t size);
|
||||
struct AnonFree {};
|
||||
|
||||
// int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf);
|
||||
struct Stat {};
|
||||
|
||||
// int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window);
|
||||
struct VmMap {};
|
||||
// int sys_vm_unmap(void *pointer, size_t size);
|
||||
struct VmUnmap {};
|
||||
// int sys_vm_protect(void *pointer, size_t size, int prot);
|
||||
struct VmProtect {};
|
||||
|
||||
#if defined(__riscv)
|
||||
#include <sys/hwprobe.h>
|
||||
|
||||
// int sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags);
|
||||
struct RiscvHwprobe {};
|
||||
#endif
|
||||
|
||||
#if __MLIBC_BSD_OPTION
|
||||
#include <termios.h>
|
||||
|
||||
// int sys_brk(void **out);
|
||||
struct Brk {};
|
||||
// int sys_getloadavg(double *samples);
|
||||
struct GetLoadavg {};
|
||||
// int sys_openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win);
|
||||
struct Openpty {};
|
||||
#endif // __MLIBC_BSD_OPTION
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
// int sys_personality(unsigned long persona, int *out);
|
||||
struct Personality {};
|
||||
// int sys_ioperm(unsigned long int from, unsigned long int num, int turn_on);
|
||||
struct Ioperm {};
|
||||
// int sys_iopl(int level);
|
||||
struct Iopl {};
|
||||
|
||||
#ifdef __riscv
|
||||
// int sys_riscv_flush_icache(void *start, void *end, unsigned long flags);
|
||||
struct RiscvFlushIcache {};
|
||||
#endif
|
||||
#endif // __MLIBC_GLIBC_OPTION
|
||||
|
||||
#if __MLIBC_POSIX_OPTION
|
||||
#include <abi-bits/msg.h>
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/socklen_t.h>
|
||||
#include <abi-bits/vm-flags.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/posix/stat.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <fcntl.h>
|
||||
#include <mlibc/fsfd_target.hpp>
|
||||
#include <mqueue.h>
|
||||
#include <poll.h>
|
||||
#include <sched.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
// int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read);
|
||||
struct Readv {};
|
||||
// int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written);
|
||||
struct Writev {};
|
||||
// int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read);
|
||||
struct Pwrite {};
|
||||
// int sys_access(const char *path, int mode);
|
||||
struct Access {};
|
||||
// int sys_faccessat(int dirfd, const char *pathname, int mode, int flags);
|
||||
struct Faccessat {};
|
||||
// int sys_dup(int fd, int flags, int *newfd);
|
||||
struct Dup {};
|
||||
// int sys_dup2(int fd, int flags, int newfd);
|
||||
struct Dup2 {};
|
||||
// int sys_statvfs(const char *path, struct statvfs *out);
|
||||
struct Statvfs {};
|
||||
// int sys_fstatvfs(int fd, struct statvfs *out);
|
||||
struct Fstatvfs {};
|
||||
// int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length);
|
||||
struct Readlink {};
|
||||
// int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length);
|
||||
struct Readlinkat {};
|
||||
// int sys_truncate(const char *path, off_t length);
|
||||
struct Truncate {};
|
||||
// int sys_ftruncate(int fd, size_t size);
|
||||
struct Ftruncate {};
|
||||
// int sys_fallocate(int fd, off_t offset, size_t size);
|
||||
struct Fallocate {};
|
||||
// int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd);
|
||||
struct Openat {};
|
||||
// int sys_socket(int family, int type, int protocol, int *fd);
|
||||
struct Socket {};
|
||||
// int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length);
|
||||
struct MsgSend {};
|
||||
// int sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length);
|
||||
struct Sendto {};
|
||||
// int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length);
|
||||
struct MsgRecv {};
|
||||
// int sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length);
|
||||
struct Recvfrom {};
|
||||
// int sys_listen(int fd, int backlog);
|
||||
struct Listen {};
|
||||
// gid_t sys_getgid();
|
||||
struct GetGid {};
|
||||
// gid_t sys_getegid();
|
||||
struct GetEgid {};
|
||||
// uid_t sys_getuid();
|
||||
struct GetUid {};
|
||||
// uid_t sys_geteuid();
|
||||
struct GetEuid {};
|
||||
// pid_t sys_gettid();
|
||||
struct GetTid {};
|
||||
// pid_t sys_getppid();
|
||||
struct GetPpid {};
|
||||
// int sys_getpgid(pid_t pid, pid_t *pgid);
|
||||
struct GetPgid {};
|
||||
// int sys_getsid(pid_t pid, pid_t *sid);
|
||||
struct GetSid {};
|
||||
// int sys_setpgid(pid_t pid, pid_t pgid);
|
||||
struct SetPgid {};
|
||||
// int sys_setuid(uid_t uid);
|
||||
struct SetUid {};
|
||||
// int sys_seteuid(uid_t euid);
|
||||
struct SetEuid {};
|
||||
// int sys_setgid(gid_t gid);
|
||||
struct SetGid {};
|
||||
// int sys_setegid(gid_t egid);
|
||||
struct SetEgid {};
|
||||
// int sys_getgroups(size_t size, gid_t *list, int *ret);
|
||||
struct GetGroups {};
|
||||
// int sys_fexecve(int fd, char *const argv[], char *const envp[]);
|
||||
struct Fexecve {};
|
||||
// int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events);
|
||||
struct Pselect {};
|
||||
// int sys_getrusage(int scope, struct rusage *usage);
|
||||
struct GetRusage {};
|
||||
// int sys_getrlimit(int resource, struct rlimit *limit);
|
||||
struct GetRlimit {};
|
||||
// int sys_setrlimit(int resource, const struct rlimit *limit);
|
||||
struct SetRlimit {};
|
||||
// int sys_getpriority(int which, id_t who, int *value);
|
||||
struct GetPriority {};
|
||||
// int sys_setpriority(int which, id_t who, int prio);
|
||||
struct SetPriority {};
|
||||
// int sys_getschedparam(void *tcb, int *policy, struct sched_param *param);
|
||||
struct GetSchedparam {};
|
||||
// int sys_setschedparam(void *tcb, int policy, const struct sched_param *param);
|
||||
struct SetSchedparam {};
|
||||
// int sys_getscheduler(pid_t pid, int *policy);
|
||||
struct GetScheduler {};
|
||||
// int sys_setscheduler(pid_t pid, int policy, const struct sched_param *param);
|
||||
struct SetScheduler {};
|
||||
// int sys_getparam(pid_t pid, struct sched_param *param);
|
||||
struct GetParam {};
|
||||
// int sys_setparam(pid_t pid, const struct sched_param *param);
|
||||
struct SetParam {};
|
||||
// int sys_get_max_priority(int policy, int *out);
|
||||
struct GetMaxPriority {};
|
||||
// int sys_get_min_priority(int policy, int *out);
|
||||
struct GetMinPriority {};
|
||||
// int sys_getcwd(char *buffer, size_t size);
|
||||
struct GetCwd {};
|
||||
// int sys_chdir(const char *path);
|
||||
struct Chdir {};
|
||||
// int sys_fchdir(int fd);
|
||||
struct Fchdir {};
|
||||
// int sys_chroot(const char *path);
|
||||
struct Chroot {};
|
||||
// int sys_mkdir(const char *path, mode_t mode);
|
||||
struct Mkdir {};
|
||||
// int sys_mkdirat(int dirfd, const char *path, mode_t mode);
|
||||
struct Mkdirat {};
|
||||
// int sys_link(const char *old_path, const char *new_path);
|
||||
struct Link {};
|
||||
// int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags);
|
||||
struct Linkat {};
|
||||
// int sys_symlink(const char *target_path, const char *link_path);
|
||||
struct Symlink {};
|
||||
// int sys_symlinkat(const char *target_path, int dirfd, const char *link_path);
|
||||
struct Symlinkat {};
|
||||
// int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path);
|
||||
struct Renameat {};
|
||||
// int sys_fcntl(int fd, int request, va_list args, int *result);
|
||||
struct Fcntl {};
|
||||
// int sys_ttyname(int fd, char *buf, size_t size);
|
||||
struct Ttyname {};
|
||||
// int sys_fadvise(int fd, off_t offset, off_t length, int advice);
|
||||
struct Fadvise {};
|
||||
// void sys_sync();
|
||||
struct Sync {};
|
||||
// int sys_fsync(int fd);
|
||||
struct Fsync {};
|
||||
// int sys_fdatasync(int fd);
|
||||
struct Fdatasync {};
|
||||
// int sys_chmod(const char *pathname, mode_t mode);
|
||||
struct Chmod {};
|
||||
// int sys_fchmod(int fd, mode_t mode);
|
||||
struct Fchmod {};
|
||||
// int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags);
|
||||
struct Fchmodat {};
|
||||
// int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);
|
||||
struct Utimensat {};
|
||||
// int sys_mlock(const void *addr, size_t length);
|
||||
struct Mlock {};
|
||||
// int sys_munlock(const void *addr, size_t length);
|
||||
struct Munlock {};
|
||||
// int sys_mlockall(int flags);
|
||||
struct Mlockall {};
|
||||
// int sys_munlockall(void);
|
||||
struct Munlockall {};
|
||||
// int sys_mincore(void *addr, size_t length, unsigned char *vec);
|
||||
struct Mincore {};
|
||||
// int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window);
|
||||
struct VmRemap {};
|
||||
// int sys_setsid(pid_t *sid);
|
||||
struct SetSid {};
|
||||
// int sys_tcgetattr(int fd, struct termios *attr);
|
||||
struct Tcgetattr {};
|
||||
// int sys_tcsetattr(int, int, const struct termios *attr);
|
||||
struct Tcsetattr {};
|
||||
// int sys_tcsendbreak(int fd, int dur);
|
||||
struct Tcsendbreak {};
|
||||
// int sys_tcflow(int, int);
|
||||
struct Tcflow {};
|
||||
// int sys_tcflush(int fd, int queue);
|
||||
struct Tcflush {};
|
||||
// int sys_tcdrain(int);
|
||||
struct Tcdrain {};
|
||||
// int sys_tcgetwinsize(int fd, struct winsize *winsz);
|
||||
struct Tcgetwinsize {};
|
||||
// int sys_tcsetwinsize(int fd, const struct winsize *winsz);
|
||||
struct Tcsetwinsize {};
|
||||
// int sys_pipe(int *fds, int flags);
|
||||
struct Pipe {};
|
||||
// int sys_socketpair(int domain, int type_and_flags, int proto, int *fds);
|
||||
struct Socketpair {};
|
||||
// int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events);
|
||||
struct Poll {};
|
||||
// int sys_ppoll(struct pollfd *fds, nfds_t count, const struct timespec *ts, const sigset_t *mask, int *num_events);
|
||||
struct Ppoll {};
|
||||
// int sys_ioctl(int fd, unsigned long request, void *arg, int *result);
|
||||
struct Ioctl {};
|
||||
// int sys_posix_devctl(int fd, int dcmd, void *__restrict dev_data_ptr, size_t nbyte, int *__restrict dev_info_ptr);
|
||||
struct PosixDevctl {};
|
||||
// int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size);
|
||||
struct GetSockopt {};
|
||||
// int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size);
|
||||
struct SetSockopt {};
|
||||
// int sys_shutdown(int sockfd, int how);
|
||||
struct Shutdown {};
|
||||
// int sys_sockatmark(int sockfd, int *out);
|
||||
struct Sockatmark {};
|
||||
// int sys_thread_sigmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve);
|
||||
struct ThreadSigmask {};
|
||||
// NOTE: POSIX says that behavior of timeout = nullptr is unspecified. We treat this case
|
||||
// as an infinite timeout, making sigtimedwait(..., nullptr) equivalent to sigwaitinfo(...)
|
||||
// int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal);
|
||||
struct Sigtimedwait {};
|
||||
// int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags);
|
||||
struct Accept {};
|
||||
// int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length);
|
||||
struct Bind {};
|
||||
// int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length);
|
||||
struct Connect {};
|
||||
// int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length);
|
||||
struct Sockname {};
|
||||
// int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length);
|
||||
struct Peername {};
|
||||
// int sys_gethostname(char *buffer, size_t bufsize);
|
||||
struct GetHostname {};
|
||||
// int sys_sethostname(const char *buffer, size_t bufsize);
|
||||
struct SetHostname {};
|
||||
// int sys_mkfifoat(int dirfd, const char *path, mode_t mode);
|
||||
struct Mkfifoat {};
|
||||
// int sys_getentropy(void *buffer, size_t length);
|
||||
struct GetEntropy {};
|
||||
// int sys_mknodat(int dirfd, const char *path, int mode, int dev);
|
||||
struct Mknodat {};
|
||||
// int sys_umask(mode_t mode, mode_t *old);
|
||||
struct Umask {};
|
||||
// int sys_before_cancellable_syscall(ucontext_t *uctx);
|
||||
struct BeforeCancellableSyscall {};
|
||||
// int sys_tgkill(int tgid, int tid, int sig);
|
||||
struct Tgkill {};
|
||||
// int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags);
|
||||
struct Fchownat {};
|
||||
// int sys_sigaltstack(const stack_t *ss, stack_t *oss);
|
||||
struct Sigaltstack {};
|
||||
// int sys_sigsuspend(const sigset_t *set);
|
||||
struct Sigsuspend {};
|
||||
// int sys_sigpending(sigset_t *set);
|
||||
struct Sigpending {};
|
||||
// int sys_sigqueue(pid_t pid, int sig, const union sigval val);
|
||||
struct Sigqueue {};
|
||||
// int sys_setgroups(size_t size, const gid_t *list);
|
||||
struct SetGroups {};
|
||||
// int sys_memfd_create(const char *name, int flags, int *fd);
|
||||
struct MemfdCreate {};
|
||||
// int sys_madvise(void *addr, size_t length, int advice);
|
||||
struct Madvise {};
|
||||
// int sys_posix_madvise(void *addr, size_t length, int advice);
|
||||
struct PosixMadvise {};
|
||||
// int sys_msync(void *addr, size_t length, int flags);
|
||||
struct Msync {};
|
||||
// int sys_getitimer(int which, struct itimerval *curr_value);
|
||||
struct GetItimer {};
|
||||
// int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
|
||||
struct SetItimer {};
|
||||
// int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res);
|
||||
struct TimerCreate {};
|
||||
// int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old);
|
||||
struct TimerSettime {};
|
||||
// int sys_timer_gettime(timer_t t, struct itimerspec *val);
|
||||
struct TimerGettime {};
|
||||
// int sys_timer_delete(timer_t t);
|
||||
struct TimerDelete {};
|
||||
// int sys_timer_getoverrun(timer_t t, int *out);
|
||||
struct TimerGetoverrun {};
|
||||
// int sys_times(struct tms *tms, clock_t *out);
|
||||
struct Times {};
|
||||
// int sys_uname(struct utsname *buf);
|
||||
struct Uname {};
|
||||
// int sys_pause();
|
||||
struct Pause {};
|
||||
// int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
|
||||
struct SetResuid {};
|
||||
// int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
|
||||
struct SetResgid {};
|
||||
// int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
|
||||
struct GetResuid {};
|
||||
// int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
|
||||
struct GetResgid {};
|
||||
// int sys_setreuid(uid_t ruid, uid_t euid);
|
||||
struct SetReuid {};
|
||||
// int sys_setregid(gid_t rgid, gid_t egid);
|
||||
struct SetRegid {};
|
||||
// int sys_getlogin_r(char *name, size_t name_len);
|
||||
struct GetLoginR {};
|
||||
// int sys_if_indextoname(unsigned int index, char *name);
|
||||
struct IfIndextoname {};
|
||||
// int sys_if_nametoindex(const char *name, unsigned int *ret);
|
||||
struct IfNametoindex {};
|
||||
// int sys_ptsname(int fd, char *buffer, size_t length);
|
||||
struct Ptsname {};
|
||||
// int sys_unlockpt(int fd);
|
||||
struct Unlockpt {};
|
||||
// int sys_thread_setname(void *tcb, const char *name);
|
||||
struct ThreadSetname {};
|
||||
// int sys_thread_getname(void *tcb, char *name, size_t size);
|
||||
struct ThreadGetname {};
|
||||
// int sys_sysconf(int num, long *ret);
|
||||
struct Sysconf {};
|
||||
// int sys_semget(key_t key, int n, int fl, int *id);
|
||||
struct Semget {};
|
||||
// int sys_semctl(int semid, int semnum, int cmd, void *semun, int *ret);
|
||||
struct Semctl {};
|
||||
// int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
|
||||
struct GetAffinity {};
|
||||
// int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask);
|
||||
struct GetThreadaffinity {};
|
||||
// int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
|
||||
struct SetAffinity {};
|
||||
// int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask);
|
||||
struct SetThreadaffinity {};
|
||||
// int sys_get_current_stack_info(void **stack_base, size_t *stack_size);
|
||||
struct GetCurrentStackInfo {};
|
||||
// int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options);
|
||||
struct Waitid {};
|
||||
// int sys_name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags);
|
||||
struct NameToHandleAt {};
|
||||
// int sys_splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out);
|
||||
struct Splice {};
|
||||
// int sys_shmat(void **seg_start, int shmid, const void *shmaddr, int shmflg);
|
||||
struct Shmat {};
|
||||
// int sys_shmctl(int *idx, int shmid, int cmd, struct shmid_ds *buf);
|
||||
struct Shmctl {};
|
||||
// int sys_shmdt(const void *shmaddr);
|
||||
struct Shmdt {};
|
||||
// int sys_shmget(int *shm_id, key_t key, size_t size, int shmflg);
|
||||
struct Shmget {};
|
||||
// int sys_inet_configured(bool *ipv4, bool *ipv6);
|
||||
struct InetConfigured {};
|
||||
// int sys_nice(int nice, int *new_nice);
|
||||
struct Nice {};
|
||||
// int sys_openpt(int oflags, int *fd);
|
||||
struct Openpt {};
|
||||
// int sys_msgctl(int q, int cmd, struct msqid_ds *buf);
|
||||
struct Msgctl {};
|
||||
// int sys_msgget(key_t k, int flag, int *out);
|
||||
struct Msgget {};
|
||||
// int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg, ssize_t *out);
|
||||
struct Msgrcv {};
|
||||
// int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
|
||||
struct Msgsnd {};
|
||||
// int sys_mq_open(const char *name, int oflag, mode_t mode, mq_attr *attr, mqd_t *out);
|
||||
struct MqOpen {};
|
||||
// int sys_mq_unlink(const char *name);
|
||||
struct MqUnlink {};
|
||||
// int sys_mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
|
||||
struct MqReceive {};
|
||||
// int sys_mq_get_attr(mqd_t mqdes, mq_attr *mqstat);
|
||||
struct MqGetAttr {};
|
||||
// int sys_mq_set_attr(mqd_t mqdes, mq_attr *mqstat, mq_attr *omqstat);
|
||||
struct MqSetAttr {};
|
||||
#endif // __MLIBC_POSIX_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
#include <ifaddrs.h>
|
||||
#include <sched.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <poll.h>
|
||||
#include <linux/capability.h>
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <abi-bits/mode_t.h>
|
||||
#include <abi-bits/statx.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <bits/size_t.h>
|
||||
|
||||
// int sys_inotify_create(int flags, int *fd);
|
||||
struct InotifyCreate {};
|
||||
// int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd);
|
||||
struct InotifyAddWatch {};
|
||||
// int sys_inotify_rm_watch(int ifd, int wd);
|
||||
struct InotifyRmWatch {};
|
||||
// int sys_mount(const char *source, const char *target, const char *fstype, unsigned long flags, const void *data);
|
||||
struct Mount {};
|
||||
// int sys_umount2(const char *target, int flags);
|
||||
struct Umount2 {};
|
||||
// int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out);
|
||||
struct Ptrace {};
|
||||
// int sys_capget(cap_user_header_t hdrp, cap_user_data_t datap);
|
||||
struct Capget {};
|
||||
// int sys_capset(cap_user_header_t hdrp, const cap_user_data_t datap);
|
||||
struct Capset {};
|
||||
// int sys_prctl(int option, va_list va, int *out);
|
||||
struct Prctl {};
|
||||
// int sys_init_module(void *module, unsigned long length, const char *args);
|
||||
struct InitModule {};
|
||||
// int sys_delete_module(const char *name, unsigned flags);
|
||||
struct DeleteModule {};
|
||||
// int sys_klogctl(int type, char *bufp, int len, int *out);
|
||||
struct Klogctl {};
|
||||
// int sys_getcpu(int *cpu);
|
||||
struct Getcpu {};
|
||||
// int sys_sysinfo(struct sysinfo *info);
|
||||
struct Sysinfo {};
|
||||
// int sys_swapon(const char *path, int flags);
|
||||
struct Swapon {};
|
||||
// int sys_swapoff(const char *path);
|
||||
struct Swapoff {};
|
||||
// int sys_setxattr(const char *path, const char *name, const void *val, size_t size, int flags);
|
||||
struct Setxattr {};
|
||||
// int sys_lsetxattr(const char *path, const char *name, const void *val, size_t size, int flags);
|
||||
struct Lsetxattr {};
|
||||
// int sys_fsetxattr(int fd, const char *name, const void *val, size_t size, int flags);
|
||||
struct Fsetxattr {};
|
||||
// int sys_getxattr(const char *path, const char *name, void *val, size_t size, ssize_t *nread);
|
||||
struct Getxattr {};
|
||||
// int sys_lgetxattr(const char *path, const char *name, void *val, size_t size, ssize_t *nread);
|
||||
struct Lgetxattr {};
|
||||
// int sys_fgetxattr(int fd, const char *name, void *val, size_t size, ssize_t *nread);
|
||||
struct Fgetxattr {};
|
||||
// int sys_listxattr(const char *path, char *list, size_t size, ssize_t *nread);
|
||||
struct Listxattr {};
|
||||
// int sys_llistxattr(const char *path, char *list, size_t size, ssize_t *nread);
|
||||
struct Llistxattr {};
|
||||
// int sys_flistxattr(int fd, char *list, size_t size, ssize_t *nread);
|
||||
struct Flistxattr {};
|
||||
// int sys_removexattr(const char *path, const char *name);
|
||||
struct Removexattr {};
|
||||
// int sys_lremovexattr(const char *path, const char *name);
|
||||
struct Lremovexattr {};
|
||||
// int sys_fremovexattr(int fd, const char *name);
|
||||
struct Fremovexattr {};
|
||||
// int sys_statfs(const char *path, struct statfs *buf);
|
||||
struct Statfs {};
|
||||
// int sys_fstatfs(int fd, struct statfs *buf);
|
||||
struct Fstatfs {};
|
||||
// int sys_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf);
|
||||
struct Statx {};
|
||||
// int sys_getifaddrs(struct ifaddrs **);
|
||||
struct Getifaddrs {};
|
||||
// int sys_sendfile(int outfd, int infd, off_t *offset, size_t count, ssize_t *out);
|
||||
struct Sendfile {};
|
||||
// int sys_syncfs(int fd);
|
||||
struct Syncfs {};
|
||||
// int sys_unshare(int flags);
|
||||
struct Unshare {};
|
||||
// int sys_setns(int fd, int nstype);
|
||||
struct SetNs {};
|
||||
// int sys_pidfd_open(pid_t pid, unsigned int flags, int *outfd);
|
||||
struct PidfdOpen {};
|
||||
// int sys_pidfd_getpid(int fd, pid_t *outpid);
|
||||
struct PidfdGetpid {};
|
||||
// int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags);
|
||||
struct PidfdSendSignal {};
|
||||
// int sys_process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out);
|
||||
struct ProcessVmReadv {};
|
||||
// int sys_process_vm_writev(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out);
|
||||
struct ProcessVmWritev {};
|
||||
// int sys_fsopen(const char *fsname, unsigned int flags, int *outfd);
|
||||
struct Fsopen {};
|
||||
// int sys_fsmount(int fsfd, unsigned int flags, unsigned int mountflags, int *outfd);
|
||||
struct Fsmount {};
|
||||
// int sys_fsconfig(int fd, unsigned int cmd, const char *key, const void *val, int aux);
|
||||
struct Fsconfig {};
|
||||
// int sys_move_mount(int from_dirfd, const char *from_path, int to_dirfd, const char *to_path, unsigned int flags);
|
||||
struct MoveMount {};
|
||||
// int sys_open_tree(int dirfd, const char *path, unsigned int flags, int *outfd);
|
||||
struct OpenTree {};
|
||||
// int sys_copy_file_range(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t count, unsigned int flags, ssize_t *bytes_copied);
|
||||
struct CopyFileRange {};
|
||||
#endif // __MLIBC_LINUX_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_EPOLL_OPTION
|
||||
#include <sys/epoll.h>
|
||||
|
||||
// int sys_epoll_create(int flags, int *fd);
|
||||
struct EpollCreate {};
|
||||
// int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev);
|
||||
struct EpollCtl {};
|
||||
// int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised);
|
||||
struct EpollPwait {};
|
||||
#endif // __MLIBC_LINUX_EPOLL_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_TIMERFD_OPTION
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
// int sys_timerfd_create(int clockid, int flags, int *fd);
|
||||
struct TimerfdCreate {};
|
||||
// int sys_timerfd_settime(int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue);
|
||||
struct TimerfdSettime {};
|
||||
// int sys_timerfd_gettime(int fd, struct itimerspec *its);
|
||||
struct TimerfdGettime {};
|
||||
#endif // __MLIBC_LINUX_TIMERFD_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_SIGNALFD_OPTION
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
// int sys_signalfd_create(const sigset_t *, int flags, int *fd);
|
||||
struct SignalfdCreate {};
|
||||
#endif // __MLIBC_LINUX_SIGNALFD_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_EVENTFD_OPTION
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
// int sys_eventfd_create(unsigned int initval, int flags, int *fd);
|
||||
struct EventfdCreate {};
|
||||
#endif // __MLIBC_LINUX_EVENTFD_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_REBOOT_OPTION
|
||||
#include <sys/reboot.h>
|
||||
|
||||
// int sys_reboot(int cmd);
|
||||
struct Reboot {};
|
||||
#endif // __MLIBC_LINUX_REBOOT_OPTION
|
||||
|
||||
#if __MLIBC_LINUX_WRAPPERS_OPTION
|
||||
// int sys_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *uinfo);
|
||||
struct RtSigqueueinfo {};
|
||||
// int sys_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *uinfo);
|
||||
struct RtTgSigqueueinfo {};
|
||||
#endif // __MLIBC_LINUX_WRAPPERS_OPTION
|
||||
|
||||
#endif /* MLIBC_SYSDEP_TAGS */
|
||||
@@ -0,0 +1,189 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <bits/size_t.h>
|
||||
#include <frg/array.hpp>
|
||||
|
||||
#include "elf.hpp"
|
||||
|
||||
/*
|
||||
* Explanation of cancellation bits:
|
||||
*
|
||||
* tcbCancelEnableBit and tcbCancelAsyncBit should be self-explanatory,
|
||||
* they are set if cancellation is enabled, or asynchronous, respectively.
|
||||
*
|
||||
* tcbCancelTriggerBit is set whenever a cancellation is triggered, which is
|
||||
* in pthread_cancel() or in the signal handler. This bit is used by
|
||||
* pthread_testcancel() to check whether a cancellation has been requested,
|
||||
* and also by cancellable syscalls.
|
||||
*
|
||||
* tcbCancelingBit is set when a cancellation is currently being handled. This
|
||||
* is to avoid a situation in which a cancellation handler gets interrupted by
|
||||
* a SIGCANCEL and a second cancellation handler gets executed on top of the
|
||||
* previous one. Right now this cannot happen, since we stay in signal handler
|
||||
* context when canceling/exiting. In the future this might be done outside
|
||||
* of a signal handler, in which case we shouldn't restart the cancellation process.
|
||||
*
|
||||
* tcbExitingBit is set when the thread starts the exit procedure. Currently
|
||||
* this is just an exit, but in the future this will be a stack unwinding
|
||||
* procedure, which shouldn't be reentered. Not currently set anywhere,
|
||||
* may be done so in the future.
|
||||
*
|
||||
* TODO(geert): update this comment when we do unwinding in the exit procedure.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
// Set when the cancellation is enabled
|
||||
constexpr unsigned int tcbCancelEnableBit = 1 << 0;
|
||||
// 1 - cancellation is asynchronous, 0 - cancellation is deferred
|
||||
constexpr unsigned int tcbCancelAsyncBit = 1 << 1;
|
||||
// Set when the thread has been cancelled
|
||||
constexpr unsigned int tcbCancelTriggerBit = 1 << 2;
|
||||
// Set when the thread is in the process of being cancelled.
|
||||
constexpr unsigned int tcbCancelingBit = 1 << 3;
|
||||
// Set when the thread is exiting.
|
||||
constexpr unsigned int tcbExitingBit = 1 << 4;
|
||||
}
|
||||
|
||||
namespace mlibc {
|
||||
// Returns true when bitmask indicates thread has been asynchronously
|
||||
// cancelled.
|
||||
static constexpr bool tcb_async_cancelled(int value) {
|
||||
return (value & (tcbCancelEnableBit | tcbCancelAsyncBit
|
||||
| tcbCancelTriggerBit)) == (tcbCancelEnableBit
|
||||
| tcbCancelAsyncBit | tcbCancelTriggerBit);
|
||||
}
|
||||
|
||||
// Returns true when bitmask indicates async cancellation is enabled.
|
||||
static constexpr bool tcb_async_cancel(int value) {
|
||||
return (value & (tcbCancelEnableBit | tcbCancelAsyncBit))
|
||||
== (tcbCancelEnableBit | tcbCancelAsyncBit);
|
||||
}
|
||||
|
||||
// Returns true when bitmask indicates cancellation is enabled.
|
||||
static constexpr bool tcb_cancel_enabled(int value) {
|
||||
return (value & tcbCancelEnableBit);
|
||||
}
|
||||
|
||||
// Returns true when bitmask indicates threas has been cancelled.
|
||||
static constexpr bool tcb_cancelled(int value) {
|
||||
return (value & (tcbCancelEnableBit | tcbCancelTriggerBit))
|
||||
== (tcbCancelEnableBit | tcbCancelTriggerBit);
|
||||
}
|
||||
|
||||
#if !MLIBC_STATIC_BUILD && !MLIBC_BUILDING_RTLD
|
||||
// In non-static builds, libc.so always has a TCB available.
|
||||
constexpr bool tcb_available_flag = true;
|
||||
#else
|
||||
// Otherwise this will be set to true after RTLD has initialized the TCB.
|
||||
extern bool tcb_available_flag;
|
||||
#endif
|
||||
}
|
||||
|
||||
enum class TcbThreadReturnValue {
|
||||
Pointer,
|
||||
Integer,
|
||||
};
|
||||
|
||||
struct Tcb {
|
||||
Tcb *selfPointer;
|
||||
size_t dtvSize;
|
||||
void **dtvPointers;
|
||||
int tid;
|
||||
int didExit;
|
||||
#if defined(__x86_64__)
|
||||
uint8_t padding[8];
|
||||
#endif
|
||||
uintptr_t stackCanary;
|
||||
int cancelBits;
|
||||
|
||||
union {
|
||||
void *voidPtr;
|
||||
int intVal;
|
||||
} returnValue;
|
||||
TcbThreadReturnValue returnValueType;
|
||||
|
||||
struct AtforkHandler {
|
||||
void (*prepare)(void);
|
||||
void (*parent)(void);
|
||||
void (*child)(void);
|
||||
|
||||
AtforkHandler *next;
|
||||
AtforkHandler *prev;
|
||||
};
|
||||
|
||||
AtforkHandler *atforkBegin;
|
||||
AtforkHandler *atforkEnd;
|
||||
|
||||
struct CleanupHandler {
|
||||
void (*func)(void *);
|
||||
void *arg;
|
||||
|
||||
CleanupHandler *next;
|
||||
CleanupHandler *prev;
|
||||
};
|
||||
|
||||
CleanupHandler *cleanupBegin;
|
||||
CleanupHandler *cleanupEnd;
|
||||
int isJoinable;
|
||||
|
||||
struct LocalKey {
|
||||
void *value;
|
||||
uint64_t generation;
|
||||
};
|
||||
frg::array<LocalKey, PTHREAD_KEYS_MAX> *localKeys;
|
||||
|
||||
size_t stackSize;
|
||||
void *stackAddr;
|
||||
size_t guardSize;
|
||||
|
||||
inline void invokeThreadFunc(void *entry, void *user_arg) {
|
||||
if(returnValueType == TcbThreadReturnValue::Pointer) {
|
||||
auto func = reinterpret_cast<void *(*)(void *)>(entry);
|
||||
returnValue.voidPtr = func(user_arg);
|
||||
} else {
|
||||
auto func = reinterpret_cast<int (*)(void *)>(entry);
|
||||
returnValue.intVal = func(user_arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// There are a few places where we assume the layout of the TCB:
|
||||
#if defined(__x86_64__)
|
||||
// GCC expects the stack canary to be at fs:0x28.
|
||||
static_assert(offsetof(Tcb, stackCanary) == 0x28);
|
||||
// sysdeps/linux/x86_64/cp_syscall.S uses the offset of cancelBits.
|
||||
static_assert(offsetof(Tcb, cancelBits) == 0x30);
|
||||
// options/linker/x86_64/runtime.S uses the offset of dtvPointers.
|
||||
static_assert(offsetof(Tcb, dtvPointers) == 16);
|
||||
#elif defined(__i386__)
|
||||
// GCC expects the stack canary to be at gs:0x14.
|
||||
// The offset differs from x86_64 due to the change in the pointer size
|
||||
// and removed padding before the stack canary.
|
||||
static_assert(offsetof(Tcb, stackCanary) == 0x14);
|
||||
// sysdeps/linux/x86/cp_syscall.S uses the offset of cancelBits.
|
||||
// It differs from x86_64 for the same reasons as the stack canary.
|
||||
static_assert(offsetof(Tcb, cancelBits) == 0x18);
|
||||
#elif defined(__aarch64__)
|
||||
// The thread pointer on AArch64 points to 16 bytes before the end of the TCB.
|
||||
// options/linker/aarch64/runtime.S uses the offset of dtvPointers.
|
||||
static_assert(sizeof(Tcb) - offsetof(Tcb, dtvPointers) - TP_TCB_OFFSET == 104);
|
||||
// sysdeps/linux/aarch64/cp_syscall.S uses the offset of cancelBits.
|
||||
static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) - TP_TCB_OFFSET == 80);
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
// The thread pointer on RISC-V points to *after* the TCB, and since
|
||||
// we need to access specific fields that means that the value in
|
||||
// sysdeps/linux/riscv64/cp_syscall.S needs to be updated whenever
|
||||
// the struct is expanded.
|
||||
static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 96);
|
||||
#elif defined (__m68k__)
|
||||
// The thread pointer on m68k points to 0x7000 bytes *after* the end of the
|
||||
// TCB, so similarly to as on RISC-V, we need to keep the value in
|
||||
// sysdeps/linux/m68k/cp_syscall.S up-to-date.
|
||||
static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 0x30);
|
||||
#elif defined(__loongarch64)
|
||||
static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 96);
|
||||
#else
|
||||
#error "Missing architecture specific code."
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <bits/ansi/timespec.h>
|
||||
#include <bits/threads.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int thread_create(struct __mlibc_thread_data **__restrict thread, const struct __mlibc_threadattr *__restrict attrp, void *entry, void *__restrict user_arg, bool returns_int);
|
||||
int thread_attr_init(struct __mlibc_threadattr *attr);
|
||||
int thread_join(struct __mlibc_thread_data *thread, void *res);
|
||||
|
||||
int thread_mutex_init(struct __mlibc_mutex *__restrict mutex, const struct __mlibc_mutexattr *__restrict attr);
|
||||
int thread_mutex_destroy(struct __mlibc_mutex *mutex);
|
||||
int thread_mutex_lock(struct __mlibc_mutex *mutex);
|
||||
int thread_mutex_unlock(struct __mlibc_mutex *mutex);
|
||||
|
||||
int thread_mutexattr_init(struct __mlibc_mutexattr *attr);
|
||||
int thread_mutexattr_destroy(struct __mlibc_mutexattr *attr);
|
||||
int thread_mutexattr_gettype(const struct __mlibc_mutexattr *__restrict attr, int *__restrict type);
|
||||
int thread_mutexattr_settype(struct __mlibc_mutexattr *attr, int type);
|
||||
|
||||
int thread_cond_init(struct __mlibc_cond *__restrict cond, const struct __mlibc_condattr *__restrict attr);
|
||||
int thread_cond_destroy(struct __mlibc_cond *cond);
|
||||
int thread_cond_broadcast(struct __mlibc_cond *cond);
|
||||
int thread_cond_timedwait(struct __mlibc_cond *__restrict cond, __mlibc_mutex *__restrict mutex, const struct timespec *__restrict abstime);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <mlibc/thread.hpp>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
inline unsigned int this_tid() {
|
||||
// During RTLD initialization, we don't have a TCB.
|
||||
if (mlibc::tcb_available_flag) {
|
||||
auto tcb = get_current_tcb();
|
||||
return tcb->tid;
|
||||
} else if (mlibc::sys_futex_tid) {
|
||||
return mlibc::sys_futex_tid();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <abi-bits/errno.h>
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/utmp-defines.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <bits/posix/timeval.h>
|
||||
#include <bits/size_t.h>
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
#include <string.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
template <class S>
|
||||
concept UtmpStruct = requires(S s) {
|
||||
std::is_same_v<decltype(s.ut_user), char[]>;
|
||||
std::is_same_v<decltype(s.ut_id), char[]>;
|
||||
std::is_same_v<decltype(s.ut_line), char[]>;
|
||||
std::is_same_v<decltype(s.ut_pid), pid_t>;
|
||||
std::is_same_v<decltype(s.ut_type), short int>;
|
||||
std::is_same_v<decltype(s.ut_tv), struct timeval>;
|
||||
};
|
||||
|
||||
template <UtmpStruct U>
|
||||
int getUtmpEntry(int fd, U *res) {
|
||||
ssize_t progress = 0;
|
||||
ssize_t read = 0;
|
||||
char *ptr = reinterpret_cast<char *>(res);
|
||||
|
||||
int err = mlibc::sys_read(fd, ptr, sizeof(U), &read);
|
||||
if(err)
|
||||
return err;
|
||||
|
||||
if(read == sizeof(U))
|
||||
return 0;
|
||||
else if(read == 0)
|
||||
return ESRCH;
|
||||
|
||||
progress = read;
|
||||
|
||||
while(read) {
|
||||
err = mlibc::sys_read(fd, ptr + progress, sizeof(U) - progress, &read);
|
||||
if(err)
|
||||
return err;
|
||||
|
||||
progress += read;
|
||||
|
||||
if(progress == sizeof(U))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
template <UtmpStruct U>
|
||||
int getUtmpEntryById(int fd, const U *id, U *res) {
|
||||
while(true) {
|
||||
U tmp;
|
||||
if(int e = getUtmpEntry(fd, &tmp); e)
|
||||
return e;
|
||||
|
||||
if(id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
|
||||
|| id->ut_type == NEW_TIME || id->ut_type == OLD_TIME) {
|
||||
if(tmp.ut_type == id->ut_type) {
|
||||
memcpy(res, &tmp, sizeof(U));
|
||||
return 0;
|
||||
}
|
||||
} else if(id->ut_type == INIT_PROCESS || id->ut_type == LOGIN_PROCESS
|
||||
|| id->ut_type == USER_PROCESS || id->ut_type == DEAD_PROCESS) {
|
||||
if(!memcmp(tmp.ut_id, id->ut_id, sizeof(U::ut_id))) {
|
||||
memcpy(res, &tmp, sizeof(U));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <UtmpStruct U>
|
||||
int getUtmpEntryByType(int fd, const U *id, U *res) {
|
||||
while(true) {
|
||||
U tmp;
|
||||
if(int e = getUtmpEntry(fd, &tmp); e)
|
||||
return e;
|
||||
|
||||
if(id->ut_type == USER_PROCESS || id->ut_type == LOGIN_PROCESS) {
|
||||
if(!strncmp(tmp.ut_line, id->ut_line, sizeof(U::ut_line))) {
|
||||
memcpy(res, &tmp, sizeof(U));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <UtmpStruct U>
|
||||
int putUtmpEntry(int fd, const U *ut) {
|
||||
size_t progress = 0;
|
||||
char *ptr = (char *) ut;
|
||||
|
||||
off_t discard;
|
||||
if(int e = mlibc::sys_seek(fd, 0, SEEK_END, &discard); e)
|
||||
return e;
|
||||
|
||||
while(progress < sizeof(U)) {
|
||||
ssize_t written = 0;
|
||||
if(int e = mlibc::sys_write(fd, ptr + progress, sizeof(U) - progress, &written); e)
|
||||
return e;
|
||||
progress += written;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,150 @@
|
||||
#ifndef _MLIBC_STDINT_H
|
||||
#define _MLIBC_STDINT_H
|
||||
|
||||
#include <bits/types.h>
|
||||
#include <bits/wchar.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Type definitions. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
/* Fixed-width (signed). */
|
||||
typedef __mlibc_int8 int8_t;
|
||||
typedef __mlibc_int16 int16_t;
|
||||
typedef __mlibc_int32 int32_t;
|
||||
typedef __mlibc_int64 int64_t;
|
||||
|
||||
/* Fixed-width (unsigned). */
|
||||
typedef __mlibc_uint8 uint8_t;
|
||||
typedef __mlibc_uint16 uint16_t;
|
||||
typedef __mlibc_uint32 uint32_t;
|
||||
typedef __mlibc_uint64 uint64_t;
|
||||
|
||||
/* Least-width (signed). */
|
||||
typedef __mlibc_int8 int_least8_t;
|
||||
typedef __mlibc_int16 int_least16_t;
|
||||
typedef __mlibc_int32 int_least32_t;
|
||||
typedef __mlibc_int64 int_least64_t;
|
||||
|
||||
/* Least-width (unsigned). */
|
||||
typedef __mlibc_uint8 uint_least8_t;
|
||||
typedef __mlibc_uint16 uint_least16_t;
|
||||
typedef __mlibc_uint32 uint_least32_t;
|
||||
typedef __mlibc_uint64 uint_least64_t;
|
||||
|
||||
/* Fast-width (signed). */
|
||||
typedef __mlibc_int_fast8 int_fast8_t;
|
||||
typedef __mlibc_int_fast16 int_fast16_t;
|
||||
typedef __mlibc_int_fast32 int_fast32_t;
|
||||
typedef __mlibc_int_fast64 int_fast64_t;
|
||||
|
||||
/* Fast-width (unsigned). */
|
||||
typedef __mlibc_uint_fast8 uint_fast8_t;
|
||||
typedef __mlibc_uint_fast16 uint_fast16_t;
|
||||
typedef __mlibc_uint_fast32 uint_fast32_t;
|
||||
typedef __mlibc_uint_fast64 uint_fast64_t;
|
||||
|
||||
/* Miscellaneous (signed). */
|
||||
typedef __mlibc_intmax intmax_t;
|
||||
typedef __mlibc_intptr intptr_t;
|
||||
|
||||
/* Miscellaneous (unsigned). */
|
||||
typedef __mlibc_uintmax uintmax_t;
|
||||
typedef __mlibc_uintptr uintptr_t;
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Constants. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
/* Fixed-width (signed). */
|
||||
#define INT8_C(x) __MLIBC_INT8_C(x)
|
||||
#define INT16_C(x) __MLIBC_INT16_C(x)
|
||||
#define INT32_C(x) __MLIBC_INT32_C(x)
|
||||
#define INT64_C(x) __MLIBC_INT64_C(x)
|
||||
#define INTMAX_C(x) __MLIBC_INTMAX_C(x)
|
||||
|
||||
/* Fixed-width (unsigned). */
|
||||
#define UINT8_C(x) __MLIBC_UINT8_C(x)
|
||||
#define UINT16_C(x) __MLIBC_UINT16_C(x)
|
||||
#define UINT32_C(x) __MLIBC_UINT32_C(x)
|
||||
#define UINT64_C(x) __MLIBC_UINT64_C(x)
|
||||
#define UINTMAX_C(x) __MLIBC_UINTMAX_C(x)
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Limits. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
/* Fixed-width (signed). */
|
||||
#define INT8_MAX __MLIBC_INT8_MAX
|
||||
#define INT16_MAX __MLIBC_INT16_MAX
|
||||
#define INT32_MAX __MLIBC_INT32_MAX
|
||||
#define INT64_MAX __MLIBC_INT64_MAX
|
||||
|
||||
#define INT8_MIN __MLIBC_INT8_MIN
|
||||
#define INT16_MIN __MLIBC_INT16_MIN
|
||||
#define INT32_MIN __MLIBC_INT32_MIN
|
||||
#define INT64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
/* Fixed-width (unsigned). */
|
||||
#define UINT8_MAX __MLIBC_UINT8_MAX
|
||||
#define UINT16_MAX __MLIBC_UINT16_MAX
|
||||
#define UINT32_MAX __MLIBC_UINT32_MAX
|
||||
#define UINT64_MAX __MLIBC_UINT64_MAX
|
||||
|
||||
/* Least-width (signed). */
|
||||
#define INT_LEAST8_MAX __MLIBC_INT8_MAX
|
||||
#define INT_LEAST16_MAX __MLIBC_INT16_MAX
|
||||
#define INT_LEAST32_MAX __MLIBC_INT32_MAX
|
||||
#define INT_LEAST64_MAX __MLIBC_INT64_MAX
|
||||
|
||||
#define INT_LEAST8_MIN __MLIBC_INT8_MIN
|
||||
#define INT_LEAST16_MIN __MLIBC_INT16_MIN
|
||||
#define INT_LEAST32_MIN __MLIBC_INT32_MIN
|
||||
#define INT_LEAST64_MIN __MLIBC_INT64_MIN
|
||||
|
||||
/* Least-width (unsigned). */
|
||||
#define UINT_LEAST8_MAX __MLIBC_UINT8_MAX
|
||||
#define UINT_LEAST16_MAX __MLIBC_UINT16_MAX
|
||||
#define UINT_LEAST32_MAX __MLIBC_UINT32_MAX
|
||||
#define UINT_LEAST64_MAX __MLIBC_UINT64_MAX
|
||||
|
||||
/* Fast-width (signed). */
|
||||
#define INT_FAST8_MAX __MLIBC_INT_FAST8_MAX
|
||||
#define INT_FAST16_MAX __MLIBC_INT_FAST16_MAX
|
||||
#define INT_FAST32_MAX __MLIBC_INT_FAST32_MAX
|
||||
#define INT_FAST64_MAX __MLIBC_INT_FAST64_MAX
|
||||
|
||||
#define INT_FAST8_MIN __MLIBC_INT_FAST8_MIN
|
||||
#define INT_FAST16_MIN __MLIBC_INT_FAST16_MIN
|
||||
#define INT_FAST32_MIN __MLIBC_INT_FAST32_MIN
|
||||
#define INT_FAST64_MIN __MLIBC_INT_FAST64_MIN
|
||||
|
||||
/* Fast-width (unsigned). */
|
||||
#define UINT_FAST8_MAX __MLIBC_UINT_FAST8_MAX
|
||||
#define UINT_FAST16_MAX __MLIBC_UINT_FAST16_MAX
|
||||
#define UINT_FAST32_MAX __MLIBC_UINT_FAST32_MAX
|
||||
#define UINT_FAST64_MAX __MLIBC_UINT_FAST64_MAX
|
||||
|
||||
/* Miscellaneous (signed). */
|
||||
#define INTMAX_MAX __MLIBC_INTMAX_MAX
|
||||
#define INTPTR_MAX __MLIBC_INTPTR_MAX
|
||||
|
||||
#define INTMAX_MIN __MLIBC_INTMAX_MIN
|
||||
#define INTPTR_MIN __MLIBC_INTPTR_MIN
|
||||
|
||||
/* Miscellaneous (unsigned). */
|
||||
#define UINTMAX_MAX __MLIBC_UINTMAX_MAX
|
||||
#define UINTPTR_MAX __MLIBC_UINTPTR_MAX
|
||||
|
||||
/* Other limits (signed). */
|
||||
#define PTRDIFF_MAX __MLIBC_PTRDIFF_MAX
|
||||
#define PTRDIFF_MIN __MLIBC_PTRDIFF_MIN
|
||||
#define SIG_ATOMIC_MAX __MLIBC_SIG_ATOMIC_MAX
|
||||
#define SIG_ATOMIC_MIN __MLIBC_SIG_ATOMIC_MIN
|
||||
#define WINT_MAX __MLIBC_WINT_MAX
|
||||
#define WINT_MIN __MLIBC_WINT_MIN
|
||||
|
||||
/* Other limits (unsigned). */
|
||||
#define SIZE_MAX __MLIBC_SIZE_MAX
|
||||
|
||||
#endif /* _MLIBC_STDINT_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_ARCH_DEFS_HPP
|
||||
#define MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline constexpr size_t page_size = 0x1000;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_ARCH_DEFS_HPP
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mlibc/tcb.hpp>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline Tcb *get_current_tcb() {
|
||||
// On LoongArch, the TCB is below the thread pointer.
|
||||
uintptr_t tp = (uintptr_t)__builtin_thread_pointer();
|
||||
auto tcb = reinterpret_cast<Tcb *>(tp - sizeof(Tcb));
|
||||
__ensure(tcb == tcb->selfPointer);
|
||||
return tcb;
|
||||
}
|
||||
|
||||
inline uintptr_t get_sp() {
|
||||
uintptr_t sp;
|
||||
asm volatile ("move %0, $sp" : "=r"(sp));
|
||||
return sp;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,67 @@
|
||||
.global feclearexcept
|
||||
.type feclearexcept, %function
|
||||
feclearexcept:
|
||||
li.w $t0, 0x1f0000
|
||||
and $a0, $a0, $t0
|
||||
movfcsr2gr $t1, $fcsr0
|
||||
andn $t1, $t1, $a0
|
||||
movgr2fcsr $fcsr0, $t1
|
||||
li.w $a0, 0
|
||||
jr $ra
|
||||
|
||||
.global feraiseexcept
|
||||
.type feraiseexcept, %function
|
||||
feraiseexcept:
|
||||
li.w $t0, 0x1f0000
|
||||
and $a0, $a0, $t0
|
||||
movfcsr2gr $t1, $fcsr0
|
||||
or $t1, $t1, $a0
|
||||
movgr2fcsr $fcsr0, $t1
|
||||
li.w $a0, 0
|
||||
jr $ra
|
||||
|
||||
.global fetestexcept
|
||||
.type fetestexcept, %function
|
||||
fetestexcept:
|
||||
li.w $t0, 0x1f0000
|
||||
and $a0, $a0, $t0
|
||||
movfcsr2gr $t1, $fcsr0
|
||||
and $a0, $t1, $a0
|
||||
jr $ra
|
||||
|
||||
.global fegetround
|
||||
.type fegetround, %function
|
||||
fegetround:
|
||||
movfcsr2gr $t0, $fcsr0
|
||||
andi $a0, $t0, 0x300
|
||||
jr $ra
|
||||
|
||||
.global __fesetround
|
||||
.type __fesetround, %function
|
||||
__fesetround:
|
||||
li.w $t0, 0x300
|
||||
and $a0, $a0, $t0
|
||||
movfcsr2gr $t1, $fcsr0
|
||||
andn $t1, $t1, $t0
|
||||
or $t1, $t1, $a0
|
||||
movgr2fcsr $fcsr0, $t1
|
||||
li.w $a0, 0
|
||||
jr $ra
|
||||
|
||||
.global fegetenv
|
||||
.type fegetenv, %function
|
||||
fegetenv:
|
||||
movfcsr2gr $t0, $fcsr0
|
||||
st.w $t0, $a0, 0
|
||||
li.w $a0, 0
|
||||
jr $ra
|
||||
|
||||
.global fesetenv
|
||||
.type fesetenv, %function
|
||||
fesetenv:
|
||||
addi.d $t0, $a0, 1
|
||||
beq $t0, $r0, 1f
|
||||
ld.w $t0, $a0, 0
|
||||
1: movgr2fcsr $fcsr0, $t0
|
||||
li.w $a0, 0
|
||||
jr $ra
|
||||
@@ -0,0 +1,68 @@
|
||||
.global setjmp
|
||||
.type setjmp, "function"
|
||||
.global _setjmp
|
||||
.type _setjmp, "function"
|
||||
setjmp:
|
||||
_setjmp:
|
||||
st.d $ra, $a0, 0
|
||||
st.d $sp, $a0, 8
|
||||
st.d $r21, $a0, 16
|
||||
st.d $fp, $a0, 24
|
||||
st.d $s0, $a0, 32
|
||||
st.d $s1, $a0, 40
|
||||
st.d $s2, $a0, 48
|
||||
st.d $s3, $a0, 56
|
||||
st.d $s4, $a0, 64
|
||||
st.d $s5, $a0, 72
|
||||
st.d $s6, $a0, 80
|
||||
st.d $s7, $a0, 88
|
||||
st.d $s8, $a0, 96
|
||||
fst.d $fs0, $a0, 104
|
||||
fst.d $fs1, $a0, 112
|
||||
fst.d $fs2, $a0, 120
|
||||
fst.d $fs3, $a0, 128
|
||||
fst.d $fs4, $a0, 136
|
||||
fst.d $fs5, $a0, 144
|
||||
fst.d $fs6, $a0, 152
|
||||
fst.d $fs7, $a0, 160
|
||||
move $a0, $r0
|
||||
ret
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, "function"
|
||||
sigsetjmp:
|
||||
break 0 // TODO
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, "function"
|
||||
.global _longjmp
|
||||
.type _longjmp, "function"
|
||||
longjmp:
|
||||
_longjmp:
|
||||
ld.d $ra, $a0, 0
|
||||
ld.d $sp, $a0, 8
|
||||
ld.d $r21, $a0, 16
|
||||
ld.d $fp, $a0, 24
|
||||
ld.d $s0, $a0, 32
|
||||
ld.d $s1, $a0, 40
|
||||
ld.d $s2, $a0, 48
|
||||
ld.d $s3, $a0, 56
|
||||
ld.d $s4, $a0, 64
|
||||
ld.d $s5, $a0, 72
|
||||
ld.d $s6, $a0, 80
|
||||
ld.d $s7, $a0, 88
|
||||
ld.d $s8, $a0, 96
|
||||
fld.d $fs0, $a0, 104
|
||||
fld.d $fs1, $a0, 112
|
||||
fld.d $fs2, $a0, 120
|
||||
fld.d $fs3, $a0, 128
|
||||
fld.d $fs4, $a0, 136
|
||||
fld.d $fs5, $a0, 144
|
||||
fld.d $fs6, $a0, 152
|
||||
fld.d $fs7, $a0, 160
|
||||
sltui $a0, $a1, 1
|
||||
add.d $a0, $a0, $a1
|
||||
jr $ra
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef MLIBC_ARCH_DEFS_HPP
|
||||
#define MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
// not strictly true, can be 4 or 8k on 68040/68060, and many more on others
|
||||
inline constexpr size_t page_size = 0x1000;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_ARCH_DEFS_HPP
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
#include <mlibc/tcb.hpp>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
extern "C" void *__m68k_read_tp();
|
||||
|
||||
inline Tcb *get_current_tcb() {
|
||||
// On m68k, the end of the TCB is 0x7000 below the thread pointer.
|
||||
void *ptr = __m68k_read_tp();
|
||||
return reinterpret_cast<Tcb *>((uintptr_t)ptr - 0x7000 - sizeof(Tcb));
|
||||
}
|
||||
|
||||
inline uintptr_t get_sp() {
|
||||
uintptr_t sp;
|
||||
asm volatile ("move.l %%sp, %0" : "=r"(sp));
|
||||
return sp;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <bits/ansi/fenv.h>
|
||||
|
||||
.global feclearexcept
|
||||
.type feclearexcept,@function
|
||||
feclearexcept:
|
||||
move.l 4(%sp), %d0
|
||||
andi.l #~FE_ALL_EXCEPT, %d0
|
||||
bne 1f
|
||||
|
||||
fmove.l %fpsr, %d1
|
||||
movel 4(%sp), %d0
|
||||
not.l %d0
|
||||
and.l %d0, %d1
|
||||
fmove.l %d1, %fpsr
|
||||
|
||||
moveq.l #0, %d0
|
||||
rts
|
||||
|
||||
1:
|
||||
moveq.l #-1, %d0
|
||||
rts
|
||||
|
||||
.global feraiseexcept
|
||||
.type feraiseexcept,@function
|
||||
feraiseexcept:
|
||||
move.l 4(%sp), %d0
|
||||
andi.l #~FE_ALL_EXCEPT, %d0
|
||||
bne 1f
|
||||
|
||||
fmove.l %fpsr, %d1
|
||||
or.l 4(%sp), %d1
|
||||
fmove.l %d1, %fpsr
|
||||
|
||||
moveq.l #0, %d0
|
||||
rts
|
||||
|
||||
1:
|
||||
moveq.l #-1, %d0
|
||||
rts
|
||||
|
||||
.global __fesetround
|
||||
.hidden __fesetround
|
||||
.type __fesetround,@function
|
||||
__fesetround:
|
||||
fmove.l %fpcr, %d1
|
||||
andi.l #~FE_UPWARD, %d1
|
||||
or.l 4(%sp), %d1
|
||||
fmove.l %d1, %fpcr
|
||||
moveq.l #0, %d0
|
||||
rts
|
||||
|
||||
.global fegetround
|
||||
.type fegetround,@function
|
||||
fegetround:
|
||||
fmove.l %fpcr, %d0
|
||||
andi.l #FE_UPWARD, %d0
|
||||
rts
|
||||
|
||||
.global fegetenv
|
||||
.type fegetenv,@function
|
||||
fegetenv:
|
||||
move.l 4(%sp), %a0
|
||||
|
||||
fmove.l %fpcr, %d0
|
||||
move.l %d0, (%a0)
|
||||
|
||||
fmove.l %fpsr, %d0
|
||||
move.l %d0, 4(%a0)
|
||||
|
||||
fmove.l %fpiar, %d0
|
||||
move.l %d0, 8(%a0)
|
||||
|
||||
moveq.l #0, %d0
|
||||
rts
|
||||
|
||||
.global fesetenv
|
||||
.type fesetenv,@function
|
||||
fesetenv:
|
||||
move.l 4(%sp), %a0
|
||||
|
||||
cmp.l #-1, %a0
|
||||
beq 1f
|
||||
|
||||
move.l (%a0), %d0
|
||||
fmove.l %d0, %fpcr
|
||||
|
||||
move.l 4(%a0), %d0
|
||||
fmove.l %d0, %fpsr
|
||||
|
||||
move.l 8(%a0), %d0
|
||||
fmove.l %d0, %fpiar
|
||||
|
||||
moveq.l #0, %d0
|
||||
rts
|
||||
|
||||
1:
|
||||
clr.l %d0
|
||||
fmove.l %d0, %fpcr
|
||||
fmove.l %d0, %fpsr
|
||||
fmove.l %d0, %fpiar
|
||||
moveq.l #0, %d0
|
||||
rts
|
||||
|
||||
.global fetestexcept
|
||||
.type fetestexcept,@function
|
||||
fetestexcept:
|
||||
fmove.l %fpsr, %d0
|
||||
and.l 4(%sp), %d0
|
||||
rts
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,52 @@
|
||||
.type __setjmp, "function"
|
||||
__setjmp:
|
||||
movea.l 4(%sp), %a0
|
||||
movem.l %d2-%d7/%a2-%a7, (%a0)
|
||||
move.l (%sp), 48(%a0)
|
||||
tst.l %d0
|
||||
bne 1f
|
||||
|
||||
clr.l %d0
|
||||
rts
|
||||
|
||||
1:
|
||||
move.l #1, -(%sp)
|
||||
move.l %a0, -(%sp)
|
||||
jbsr __sigsetjmp@PLTPC
|
||||
addq.l #8, %sp
|
||||
rts
|
||||
|
||||
|
||||
.global setjmp
|
||||
.type setjmp, "function"
|
||||
.global _setjmp
|
||||
.type _setjmp, "function"
|
||||
setjmp:
|
||||
_setjmp:
|
||||
clr.l %d0
|
||||
jmp __setjmp
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, "function"
|
||||
sigsetjmp:
|
||||
move.l #1, %d0
|
||||
jmp __setjmp
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, "function"
|
||||
.global _longjmp
|
||||
.type _longjmp, "function"
|
||||
longjmp:
|
||||
_longjmp:
|
||||
movea.l 4(%sp),%a0
|
||||
move.l 8(%sp),%d0
|
||||
bne 1f
|
||||
|
||||
move.l #1,%d0
|
||||
|
||||
1:
|
||||
movem.l (%a0), %d2-%d7/%a2-%a7
|
||||
move.l 48(%a0), (%sp)
|
||||
rts
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_ARCH_DEFS_HPP
|
||||
#define MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline constexpr size_t page_size = 0x1000;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_ARCH_DEFS_HPP
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mlibc/tcb.hpp>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline Tcb *get_current_tcb() {
|
||||
// On RISC-V, the TCB is below the thread pointer.
|
||||
uintptr_t tp = (uintptr_t)__builtin_thread_pointer();
|
||||
auto tcb = reinterpret_cast<Tcb *>(tp - sizeof(Tcb));
|
||||
__ensure(tcb == tcb->selfPointer);
|
||||
return tcb;
|
||||
}
|
||||
|
||||
inline uintptr_t get_sp() {
|
||||
uintptr_t sp;
|
||||
asm volatile ("mv %0, sp" : "=r"(sp));
|
||||
return sp;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef _MLIBC_SYS_HWPROBE_H
|
||||
#define _MLIBC_SYS_HWPROBE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <abi-bits/riscv-hwprobe.h>
|
||||
#include <bits/cpu_set.h>
|
||||
#include <bits/size_t.h>
|
||||
|
||||
int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus,
|
||||
unsigned int flags);
|
||||
|
||||
typedef int (*__riscv_hwprobe_t)(struct riscv_hwprobe *pairs, size_t pair_count,
|
||||
size_t cpusetsize, cpu_set_t *cpus, unsigned int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MLIBC_SYS_HWPROBE_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
#ifdef __riscv_flen
|
||||
|
||||
.global feclearexcept
|
||||
.type feclearexcept, %function
|
||||
feclearexcept:
|
||||
csrc fflags, a0
|
||||
li a0, 0
|
||||
ret
|
||||
|
||||
.global feraiseexcept
|
||||
.type feraiseexcept, %function
|
||||
feraiseexcept:
|
||||
csrs fflags, a0
|
||||
li a0, 0
|
||||
ret
|
||||
|
||||
.global fetestexcept
|
||||
.type fetestexcept, %function
|
||||
fetestexcept:
|
||||
frflags t0
|
||||
and a0, t0, a0
|
||||
ret
|
||||
|
||||
.global fegetround
|
||||
.type fegetround, %function
|
||||
fegetround:
|
||||
frrm a0
|
||||
ret
|
||||
|
||||
.global __fesetround
|
||||
.type __fesetround, %function
|
||||
__fesetround:
|
||||
fsrm t0, a0
|
||||
li a0, 0
|
||||
ret
|
||||
|
||||
.global fegetenv
|
||||
.type fegetenv, %function
|
||||
fegetenv:
|
||||
frcsr t0
|
||||
sw t0, 0(a0)
|
||||
li a0, 0
|
||||
ret
|
||||
|
||||
.global fesetenv
|
||||
.type fesetenv, %function
|
||||
fesetenv:
|
||||
li t2, -1
|
||||
li t1, 0
|
||||
beq a0, t2, 1f
|
||||
lw t1, 0(a0)
|
||||
1: fscsr t1
|
||||
li a0, 0
|
||||
ret
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <abi-bits/errno.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/internal-sysdeps.hpp>
|
||||
#include <sys/hwprobe.h>
|
||||
|
||||
int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags) {
|
||||
if (!mlibc::sys_riscv_hwprobe) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int ret = mlibc::sys_riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
|
||||
|
||||
if (ret)
|
||||
return -ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
.global setjmp
|
||||
.type setjmp, "function"
|
||||
.global _setjmp
|
||||
.type _setjmp, "function"
|
||||
setjmp:
|
||||
_setjmp:
|
||||
sd ra, 0(a0)
|
||||
sd s0, 8(a0)
|
||||
sd s1, 16(a0)
|
||||
sd s2, 24(a0)
|
||||
sd s3, 32(a0)
|
||||
sd s4, 40(a0)
|
||||
sd s5, 48(a0)
|
||||
sd s6, 56(a0)
|
||||
sd s7, 64(a0)
|
||||
sd s8, 72(a0)
|
||||
sd s9, 80(a0)
|
||||
sd s10, 88(a0)
|
||||
sd s11, 96(a0)
|
||||
sd sp, 104(a0)
|
||||
fsd fs0, 112(a0)
|
||||
fsd fs1, 120(a0)
|
||||
fsd fs2, 128(a0)
|
||||
fsd fs3, 136(a0)
|
||||
fsd fs4, 144(a0)
|
||||
fsd fs5, 152(a0)
|
||||
fsd fs6, 160(a0)
|
||||
fsd fs7, 168(a0)
|
||||
fsd fs8, 176(a0)
|
||||
fsd fs9, 184(a0)
|
||||
fsd fs10, 192(a0)
|
||||
fsd fs11, 200(a0)
|
||||
li a0, 0
|
||||
ret
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, "function"
|
||||
sigsetjmp:
|
||||
unimp // TODO
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, "function"
|
||||
.global _longjmp
|
||||
.type _longjmp, "function"
|
||||
longjmp:
|
||||
_longjmp:
|
||||
ld ra,0(a0)
|
||||
ld s0,8(a0)
|
||||
ld s1,16(a0)
|
||||
ld s2,24(a0)
|
||||
ld s3,32(a0)
|
||||
ld s4,40(a0)
|
||||
ld s5,48(a0)
|
||||
ld s6,56(a0)
|
||||
ld s7,64(a0)
|
||||
ld s8,72(a0)
|
||||
ld s9,80(a0)
|
||||
ld s10,88(a0)
|
||||
ld s11,96(a0)
|
||||
ld sp,104(a0)
|
||||
fld fs0,112(a0)
|
||||
fld fs1,120(a0)
|
||||
fld fs2,128(a0)
|
||||
fld fs3,136(a0)
|
||||
fld fs4,144(a0)
|
||||
fld fs5,152(a0)
|
||||
fld fs6,160(a0)
|
||||
fld fs7,168(a0)
|
||||
fld fs8,176(a0)
|
||||
fld fs9,184(a0)
|
||||
fld fs10,192(a0)
|
||||
fld fs11,200(a0)
|
||||
seqz a0,a1
|
||||
add a0,a0,a1
|
||||
ret
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef MLIBC_ARCH_DEFS_HPP
|
||||
#define MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline constexpr size_t page_size = 0x1000;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline Tcb *get_current_tcb() {
|
||||
uintptr_t ptr;
|
||||
asm volatile ("movl %%gs:0, %0" : "=r"(ptr));
|
||||
return reinterpret_cast<Tcb *>(ptr);
|
||||
}
|
||||
|
||||
inline uintptr_t get_sp() {
|
||||
uintptr_t esp;
|
||||
asm volatile ("mov %%esp, %0" : "=r"(esp));
|
||||
return esp;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
# The functions below are taken from musl.
|
||||
|
||||
.hidden __hwcap
|
||||
|
||||
.global feclearexcept
|
||||
.type feclearexcept,@function
|
||||
feclearexcept:
|
||||
mov 4(%esp),%ecx
|
||||
and $0x3f,%ecx
|
||||
fnstsw %ax
|
||||
# consider sse fenv as well if the cpu has XMM capability
|
||||
call 1f
|
||||
1: addl $__hwcap-1b,(%esp)
|
||||
pop %edx
|
||||
testl $0x02000000,(%edx)
|
||||
jz 2f
|
||||
# maintain exceptions in the sse mxcsr, clear x87 exceptions
|
||||
test %eax,%ecx
|
||||
jz 1f
|
||||
fnclex
|
||||
1: push %edx
|
||||
stmxcsr (%esp)
|
||||
pop %edx
|
||||
and $0x3f,%eax
|
||||
or %eax,%edx
|
||||
test %edx,%ecx
|
||||
jz 1f
|
||||
not %ecx
|
||||
and %ecx,%edx
|
||||
push %edx
|
||||
ldmxcsr (%esp)
|
||||
pop %edx
|
||||
1: xor %eax,%eax
|
||||
ret
|
||||
# only do the expensive x87 fenv load/store when needed
|
||||
2: test %eax,%ecx
|
||||
jz 1b
|
||||
not %ecx
|
||||
and %ecx,%eax
|
||||
test $0x3f,%eax
|
||||
jz 1f
|
||||
fnclex
|
||||
jmp 1b
|
||||
1: sub $32,%esp
|
||||
fnstenv (%esp)
|
||||
mov %al,4(%esp)
|
||||
fldenv (%esp)
|
||||
add $32,%esp
|
||||
xor %eax,%eax
|
||||
ret
|
||||
|
||||
.global feraiseexcept
|
||||
.type feraiseexcept,@function
|
||||
feraiseexcept:
|
||||
mov 4(%esp),%eax
|
||||
and $0x3f,%eax
|
||||
sub $32,%esp
|
||||
fnstenv (%esp)
|
||||
or %al,4(%esp)
|
||||
fldenv (%esp)
|
||||
add $32,%esp
|
||||
xor %eax,%eax
|
||||
ret
|
||||
|
||||
.global __fesetround
|
||||
.hidden __fesetround
|
||||
.type __fesetround,@function
|
||||
__fesetround:
|
||||
mov 4(%esp),%ecx
|
||||
push %eax
|
||||
xor %eax,%eax
|
||||
fnstcw (%esp)
|
||||
andb $0xf3,1(%esp)
|
||||
or %ch,1(%esp)
|
||||
fldcw (%esp)
|
||||
# consider sse fenv as well if the cpu has XMM capability
|
||||
call 1f
|
||||
1: addl $__hwcap-1b,(%esp)
|
||||
pop %edx
|
||||
testl $0x02000000,(%edx)
|
||||
jz 1f
|
||||
stmxcsr (%esp)
|
||||
shl $3,%ch
|
||||
andb $0x9f,1(%esp)
|
||||
or %ch,1(%esp)
|
||||
ldmxcsr (%esp)
|
||||
1: pop %ecx
|
||||
ret
|
||||
|
||||
.global fegetround
|
||||
.type fegetround,@function
|
||||
fegetround:
|
||||
push %eax
|
||||
fnstcw (%esp)
|
||||
pop %eax
|
||||
and $0xc00,%eax
|
||||
ret
|
||||
|
||||
.global fegetenv
|
||||
.type fegetenv,@function
|
||||
fegetenv:
|
||||
mov 4(%esp),%ecx
|
||||
xor %eax,%eax
|
||||
fnstenv (%ecx)
|
||||
# consider sse fenv as well if the cpu has XMM capability
|
||||
call 1f
|
||||
1: addl $__hwcap-1b,(%esp)
|
||||
pop %edx
|
||||
testl $0x02000000,(%edx)
|
||||
jz 1f
|
||||
push %eax
|
||||
stmxcsr (%esp)
|
||||
pop %edx
|
||||
and $0x3f,%edx
|
||||
or %edx,4(%ecx)
|
||||
1: ret
|
||||
|
||||
.global fesetenv
|
||||
.type fesetenv,@function
|
||||
fesetenv:
|
||||
mov 4(%esp),%ecx
|
||||
xor %eax,%eax
|
||||
inc %ecx
|
||||
jz 1f
|
||||
fldenv -1(%ecx)
|
||||
movl -1(%ecx),%ecx
|
||||
jmp 2f
|
||||
1: push %eax
|
||||
push %eax
|
||||
push %eax
|
||||
push %eax
|
||||
pushl $0xffff
|
||||
push %eax
|
||||
pushl $0x37f
|
||||
fldenv (%esp)
|
||||
add $28,%esp
|
||||
# consider sse fenv as well if the cpu has XMM capability
|
||||
2: call 1f
|
||||
1: addl $__hwcap-1b,(%esp)
|
||||
pop %edx
|
||||
testl $0x02000000,(%edx)
|
||||
jz 1f
|
||||
# mxcsr := same rounding mode, cleared exceptions, default mask
|
||||
and $0xc00,%ecx
|
||||
shl $3,%ecx
|
||||
or $0x1f80,%ecx
|
||||
mov %ecx,4(%esp)
|
||||
ldmxcsr 4(%esp)
|
||||
1: ret
|
||||
|
||||
.global fetestexcept
|
||||
.type fetestexcept,@function
|
||||
fetestexcept:
|
||||
mov 4(%esp),%ecx
|
||||
and $0x3f,%ecx
|
||||
fnstsw %ax
|
||||
# consider sse fenv as well if the cpu has XMM capability
|
||||
call 1f
|
||||
1: addl $__hwcap-1b,(%esp)
|
||||
pop %edx
|
||||
testl $0x02000000,(%edx)
|
||||
jz 1f
|
||||
stmxcsr 4(%esp)
|
||||
or 4(%esp),%eax
|
||||
1: and %ecx,%eax
|
||||
ret
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
.type __setjmp, "function"
|
||||
__setjmp:
|
||||
mov 4(%esp), %eax # Save argument (buffer) in edi
|
||||
mov %ebx, 0x00(%eax)
|
||||
mov %ebp, 0x04(%eax)
|
||||
mov %esi, 0x08(%eax)
|
||||
mov %edi, 0x0c(%eax)
|
||||
|
||||
lea 4(%esp), %ecx # esp before return eip is pushed
|
||||
mov %ecx, 0x10(%eax)
|
||||
mov (%esp), %ecx # Return eip
|
||||
mov %ecx, 0x14(%eax)
|
||||
|
||||
test %edx, %edx
|
||||
jnz 1f
|
||||
xor %eax, %eax
|
||||
ret
|
||||
|
||||
1:
|
||||
jmp __sigsetjmp@PLT
|
||||
|
||||
.global setjmp
|
||||
.type setjmp, "function"
|
||||
.global _setjmp
|
||||
.type _setjmp, "function"
|
||||
setjmp:
|
||||
_setjmp:
|
||||
xor %edx, %edx
|
||||
jmp __setjmp
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, "function"
|
||||
sigsetjmp:
|
||||
mov $1, %edx
|
||||
jmp __setjmp
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, "function"
|
||||
.global _longjmp
|
||||
.type _longjmp, "function"
|
||||
longjmp:
|
||||
_longjmp:
|
||||
mov 4(%esp), %ecx
|
||||
mov 0x00(%ecx), %ebx
|
||||
mov 0x04(%ecx), %ebp
|
||||
mov 0x08(%ecx), %esi
|
||||
mov 0x0c(%ecx), %edi
|
||||
|
||||
mov 8(%esp), %eax
|
||||
test %eax, %eax
|
||||
jnz 1f
|
||||
inc %eax
|
||||
1:
|
||||
mov 0x10(%ecx), %esp
|
||||
jmp *0x14(%ecx)
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_ARCH_DEFS_HPP
|
||||
#define MLIBC_ARCH_DEFS_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline constexpr size_t page_size = 0x1000;
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_ARCH_DEFS_HPP
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
inline Tcb *get_current_tcb() {
|
||||
uintptr_t ptr;
|
||||
asm volatile ("movq %%fs:0, %0" : "=r"(ptr));
|
||||
return reinterpret_cast<Tcb *>(ptr);
|
||||
}
|
||||
|
||||
inline uintptr_t get_sp() {
|
||||
uintptr_t rsp;
|
||||
asm volatile ("mov %%rsp, %0" : "=r"(rsp));
|
||||
return rsp;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,102 @@
|
||||
# The functions below are taken from musl.
|
||||
.global feclearexcept
|
||||
.type feclearexcept,@function
|
||||
feclearexcept:
|
||||
# maintain exceptions in the sse mxcsr, clear x87 exceptions
|
||||
mov %edi,%ecx
|
||||
and $0x3f,%ecx
|
||||
fnstsw %ax
|
||||
test %eax,%ecx
|
||||
jz 1f
|
||||
fnclex
|
||||
1: stmxcsr -8(%rsp)
|
||||
and $0x3f,%eax
|
||||
or %eax,-8(%rsp)
|
||||
test %ecx,-8(%rsp)
|
||||
jz 1f
|
||||
not %ecx
|
||||
and %ecx,-8(%rsp)
|
||||
ldmxcsr -8(%rsp)
|
||||
1: xor %eax,%eax
|
||||
ret
|
||||
|
||||
.global feraiseexcept
|
||||
.type feraiseexcept,@function
|
||||
feraiseexcept:
|
||||
and $0x3f,%edi
|
||||
stmxcsr -8(%rsp)
|
||||
or %edi,-8(%rsp)
|
||||
ldmxcsr -8(%rsp)
|
||||
xor %eax,%eax
|
||||
ret
|
||||
|
||||
.global __fesetround
|
||||
.hidden __fesetround
|
||||
.type __fesetround,@function
|
||||
__fesetround:
|
||||
push %rax
|
||||
xor %eax,%eax
|
||||
mov %edi,%ecx
|
||||
fnstcw (%rsp)
|
||||
andb $0xf3,1(%rsp)
|
||||
or %ch,1(%rsp)
|
||||
fldcw (%rsp)
|
||||
stmxcsr (%rsp)
|
||||
shl $3,%ch
|
||||
andb $0x9f,1(%rsp)
|
||||
or %ch,1(%rsp)
|
||||
ldmxcsr (%rsp)
|
||||
pop %rcx
|
||||
ret
|
||||
|
||||
.global fegetround
|
||||
.type fegetround,@function
|
||||
fegetround:
|
||||
push %rax
|
||||
stmxcsr (%rsp)
|
||||
pop %rax
|
||||
shr $3,%eax
|
||||
and $0xc00,%eax
|
||||
ret
|
||||
|
||||
.global fegetenv
|
||||
.type fegetenv,@function
|
||||
fegetenv:
|
||||
xor %eax,%eax
|
||||
fnstenv (%rdi)
|
||||
stmxcsr 28(%rdi)
|
||||
ret
|
||||
|
||||
.global fesetenv
|
||||
.type fesetenv,@function
|
||||
fesetenv:
|
||||
xor %eax,%eax
|
||||
inc %rdi
|
||||
jz 1f
|
||||
fldenv -1(%rdi)
|
||||
ldmxcsr 27(%rdi)
|
||||
ret
|
||||
1: push %rax
|
||||
push %rax
|
||||
pushq $0xffff
|
||||
pushq $0x37f
|
||||
fldenv (%rsp)
|
||||
pushq $0x1f80
|
||||
ldmxcsr (%rsp)
|
||||
add $40,%rsp
|
||||
ret
|
||||
|
||||
.global fetestexcept
|
||||
.type fetestexcept,@function
|
||||
fetestexcept:
|
||||
and $0x3f,%edi
|
||||
push %rax
|
||||
stmxcsr (%rsp)
|
||||
pop %rsi
|
||||
fnstsw %ax
|
||||
or %esi,%eax
|
||||
and %edi,%eax
|
||||
ret
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
.type __setjmp, "function"
|
||||
__setjmp:
|
||||
mov %rbx, 0x00(%rdi)
|
||||
mov %rbp, 0x08(%rdi)
|
||||
mov %r12, 0x10(%rdi)
|
||||
mov %r13, 0x18(%rdi)
|
||||
mov %r14, 0x20(%rdi)
|
||||
mov %r15, 0x28(%rdi)
|
||||
|
||||
lea 8(%rsp), %rax # rsp before return rip is pushed
|
||||
mov %rax, 0x30(%rdi)
|
||||
mov (%rsp), %rax # return rip
|
||||
mov %rax, 0x38(%rdi)
|
||||
|
||||
test %rdx, %rdx
|
||||
jnz 1f
|
||||
xor %rax, %rax
|
||||
ret
|
||||
|
||||
1:
|
||||
jmp __sigsetjmp
|
||||
|
||||
.global setjmp
|
||||
.type setjmp, "function"
|
||||
.global _setjmp
|
||||
.type _setjmp, "function"
|
||||
setjmp:
|
||||
_setjmp:
|
||||
xor %rdx, %rdx
|
||||
jmp __setjmp
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, "function"
|
||||
sigsetjmp:
|
||||
mov $1, %rdx
|
||||
jmp __setjmp
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, "function"
|
||||
.global _longjmp
|
||||
.type _longjmp, "function"
|
||||
longjmp:
|
||||
_longjmp:
|
||||
mov 0x00(%rdi), %rbx
|
||||
mov 0x08(%rdi), %rbp
|
||||
mov 0x10(%rdi), %r12
|
||||
mov 0x18(%rdi), %r13
|
||||
mov 0x20(%rdi), %r14
|
||||
mov 0x28(%rdi), %r15
|
||||
|
||||
mov %rsi, %rax
|
||||
test %rax, %rax
|
||||
jnz 1f
|
||||
inc %rax
|
||||
1:
|
||||
mov 0x30(%rdi), %rsp
|
||||
jmp *0x38(%rdi)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
Reference in New Issue
Block a user