diff --git a/CMakeLists.txt b/CMakeLists.txt index a959d8c..d4b8ff2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,7 +230,8 @@ add_executable(StrToHash src/StrToHash.cpp) target_include_directories(EHS PUBLIC ${PROJECT_SOURCE_DIR}/include) if (IS_OS_LINUX) - target_link_options(EHS PUBLIC -nostdlib -nostartfiles -e _start) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions") + target_link_options(EHS PUBLIC -nostdlib -nostartfiles -e start -T ${PROJECT_SOURCE_DIR}/custom.ld) set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/.local") elseif (IS_OS_WINDOWS) set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/EHS") diff --git a/custom.ld b/custom.ld new file mode 100644 index 0000000..d2798bd --- /dev/null +++ b/custom.ld @@ -0,0 +1,48 @@ +/* Define memory regions */ +MEMORY +{ + RAM (wxa) : ORIGIN = 0x20000000, LENGTH = 1M /* Adjust these values for your target */ + ROM (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* Adjust these values for your target */ +} + +/* Define the entry point of the program */ +ENTRY(_start) + +SECTIONS +{ + /* Place the program code at the beginning of ROM */ + .text : { + *(.text) + *(.text*) + } > ROM + + /* Initialize data section in ROM, copy to RAM at startup */ + .data : { + *(.data) + *(.data*) + } > RAM AT > ROM + + /* Uninitialized data section in RAM */ + .bss : { + *(.bss) + *(.bss*) + *(COMMON) + } > RAM + + /* Constructor array section */ + .init_array : { + __start_init_array = .; /* Define the start symbol */ + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + __stop_init_array = .; /* Define the end symbol */ + } > ROM + + .fini_array : { + __start_fini_array = .; /* Define the start symbol for destructors */ + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + __stop_fini_array = .; /* Define the end symbol for destructors */ + } > ROM + + /* Add other sections as needed */ +} diff --git a/src/CRT_LNX.cpp b/src/CRT_LNX.cpp index 85c18a5..1f6f209 100644 --- a/src/CRT_LNX.cpp +++ b/src/CRT_LNX.cpp @@ -49,12 +49,19 @@ extern "C" return &tls_errno; } + extern void (*__start_init_array[])(); + extern void (*__stop_init_array[])(); + extern void (*__start_fini_array[])(); + extern void (*__stop_fini_array[])(); + #ifdef EHS_DEBUG unsigned long __stack_chk_guard = 0x0000DEAD; #else unsigned long __stack_chk_guard = ehs::HRNG::GenerateSeed_u64(); #endif + void* __dso_handle = (void*)&__dso_handle; + void __stack_chk_fail(void) { EHS_LOG("Error", 0, "Found corrupted stack."); @@ -67,6 +74,22 @@ extern "C" return 0; } + void construct() __attribute__((constructor)); + + void construct() + { + for (void (**p)() = __start_init_array; p < __stop_init_array; ++p) + (*p)(); + } + + void destruct() __attribute__((destructor)); + + void destruct() + { + for (void (**p)() = __start_fini_array; p < __stop_fini_array; ++p) + (*p)(); + } + size_t strlen(const char *s) { size_t count = 0; @@ -77,20 +100,176 @@ extern "C" } } -void* operator new[](unsigned long size) noexcept(false) +struct Block { - syscall(SYS_brk,) - void* ptr = (void*)syscall(SYS_mmap, nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (ptr == MAP_FAILED) - { - EHS_LOG("Error", 0, "Failed to allocate memory on the heap."); + size_t size; + Block* prev; + Block* next; + int free; +}; + +Block* first = nullptr; +Block* last = nullptr; + +/// Extends heap memory upwards, towards zero. +/// @param [in] s The size of the memory needed aligned by 4 bytes. +/// @returns The new memory block. +Block* extend_heap(ehs::UInt_64 s) +{ + Block* b = (Block*)syscall(SYS_brk, nullptr); + + if ((void*)syscall(SYS_brk, (char*)(b + 1) + s) == (void*)-1) return nullptr; + + b->size = s; + b->prev = last; + b->next = nullptr; + b->free = 0; + + if (last) + last->next = b; + + last = b; + + return b; +} + +/// Finds the first block that will fit the given size. +/// @param [in] s The 4 byte aligned size to look for. +/// @returns The matching available memory block. +Block* find_first(ehs::UInt_64 s) +{ + Block* current = first; + while (current && (!current->free || current->size < s)) + current = current->next; + + return current; +} + +/// Fragments an existing free memory block into the given size. +/// @param [in] in The memory block to fragment. +/// @param [in] s The size of the new memory block. +/// @returns The new memory block. +Block* fragment_block(Block* in, ehs::UInt_64 s) +{ + ehs::UInt_64 totalSize = sizeof(Block) + s; + Block* b = (Block*)((char*)(in + 1) + (in->size - totalSize)); + b->size = s; + b->prev = in; + b->next = in->next; + b->free = 0; + + in->size -= totalSize; + in->next = b; + + return b; +} + +/// Will find or allocate a memory block. +/// @param [in] size The size of the memory block to request. +/// @returns The requested memory on the heap. +void* malloc(ehs::UInt_64 size) +{ + Block* b; + + size = ((size - 1) >> 2 << 2) + 4; + + if (first) + { + b = find_first(size); + if (!b) + b = extend_heap(size); + else if (b->size > sizeof(Block) + size) + b = fragment_block(b, size); + } + else + { + b = extend_heap(size); + if (!b) + return nullptr; + + first = b; } - return ptr; + return b + 1; +} + +void* realloc(void* ptr, ehs::UInt_64 new_size) +{ + if (!ptr) + return malloc(new_size); + + if (!new_size) + return nullptr; + + Block* b = (Block*)ptr - 1; + if (b->free) + return nullptr; + + if (b->size == new_size) + return ptr; + else if (b->size > sizeof(Block) + new_size) + return fragment_block(b, new_size) + 1; + + return nullptr; +} + +/// Will flag the provided memory as free and will defragment other blocks adjacent to it. +/// @param [in] ptr The memory to flag as free. +/// @note If all data after the provided memory is free, it will reduce the heap size. +void free(void* ptr) +{ + if (!ptr) + return; + + Block* b = (Block*)ptr - 1; + if (b->free) + return; + + b->free = 1; + + while (b->prev && b->prev->free) + b = b->prev; + + while (b->next && b->next->free) + { + b->size += sizeof(Block) + b->next->size; + b->next = b->next->next; + } + + if (!b->next) + syscall(SYS_brk, b); +} + +ehs::UInt_64 get_heap_size() +{ + if (!first || !last) + return 0; + + return ((char*)last + last->size) - (char*)first; +} + +void* operator new(unsigned long size) noexcept +{ + return malloc(size); +} + +void operator delete(void* ptr, unsigned long size) noexcept +{ + free(ptr); +} + +void* operator new[](unsigned long size) noexcept(false) +{ + return malloc(size); +} + +void operator delete[](void* ptr, unsigned long size) noexcept +{ + free(ptr); } void operator delete[](void* ptr) noexcept { - syscall(SYS_munmap, ptr, GetStackSize()) + free(ptr); } \ No newline at end of file diff --git a/src/EHS.cpp b/src/EHS.cpp index 449578a..6a86b5f 100644 --- a/src/EHS.cpp +++ b/src/EHS.cpp @@ -635,7 +635,7 @@ void LogRaised(const ehs::Log& log) ehs::BaseConsole::Write_8(result); } -int main() +void start() { ehs::Console::Attach(); @@ -682,6 +682,4 @@ int main() ehs::GarbageCollector::Stop(); ehs::Console::Free(); - - return code; } \ No newline at end of file diff --git a/src/StrToHash.cpp b/src/StrToHash.cpp index 3c7c6a8..adc9fee 100644 --- a/src/StrToHash.cpp +++ b/src/StrToHash.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include ehs::Int_32 Main(ehs::Str_8* appName, ehs::Str_8* appVerId, ehs::Version* appVer) { @@ -8,23 +8,23 @@ ehs::Int_32 Main(ehs::Str_8* appName, ehs::Str_8* appVerId, ehs::Version* appVer *appVerId = "Release"; *appVer = {1, 0, 0}; - ehs::Vector args = ehs::BaseConsole::GetArgs_8(); + ehs::Vector args = ehs::Console::GetArgs_8(); if (args.Size() > 1) { for (ehs::UInt_64 i = 1; i < args.Size(); ++i) - ehs::BaseConsole::Write_8("Result " + ehs::Str_8::FromNum(i) + ": " + ehs::Str_8::FromNum(args[i].Hash_64())); + ehs::Console::Write_8("Result " + ehs::Str_8::FromNum(i) + ": " + ehs::Str_8::FromNum(args[i].Hash_64())); } else { - ehs::BaseConsole::Write_8("String: ", false); - ehs::Str_8 in = ehs::BaseConsole::Read_8(); - ehs::BaseConsole::Write_8("Result: " + ehs::Str_8::FromNum(in.Hash_64())); + ehs::Console::Write_8("String: ", false); + ehs::Str_8 in = ehs::Console::Read_8(); + ehs::Console::Write_8("Result: " + ehs::Str_8::FromNum(in.Hash_64())); - ehs::BaseConsole::Read_8(); + ehs::Console::Read_8(); } - ehs::BaseConsole::Free(); + ehs::Console::Free(); return 0; }