diff --git a/Userspace/libc/interpreter/CMakeLists.txt b/Userspace/libc/interpreter/CMakeLists.txt index 51bc90ca..278e1b0c 100644 --- a/Userspace/libc/interpreter/CMakeLists.txt +++ b/Userspace/libc/interpreter/CMakeLists.txt @@ -15,6 +15,7 @@ if(GIT_COMMIT) endif() add_compile_definitions(FENNIX_DYNAMIC_LOADER="1") +add_compile_definitions(PROGRAM_VERSION="${PROJECT_VERSION}") install(TARGETS ld.so DESTINATION lib) target_compile_options(ld.so PRIVATE -fvisibility=hidden -fPIC) diff --git a/Userspace/libc/interpreter/alloc.c b/Userspace/libc/interpreter/alloc.c index a9739edd..f186820d 100644 --- a/Userspace/libc/interpreter/alloc.c +++ b/Userspace/libc/interpreter/alloc.c @@ -25,6 +25,11 @@ #include "elf.h" #include "misc.h" +#undef PAGE_SIZE +#define PAGE_SIZE 0x1000 +#undef ALIGN_UP +#define ALIGN_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + typedef struct MemoryBlock { struct MemoryBlock *next; @@ -32,14 +37,15 @@ typedef struct MemoryBlock size_t slot_size; size_t slots_per_block; uint8_t *bitmap; + size_t bitmap_size; + size_t total_size; } MemoryBlock; -MemoryBlock *memory_pool = NULL; -#define PAGE_SIZE 0x1000 +static MemoryBlock *memory_pool = NULL; void *request_page(size_t size) { - size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + size_t aligned_size = ALIGN_UP(size, PAGE_SIZE); void *addr = (void *)sysdep(MemoryMap)(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if ((intptr_t)addr < 0) return NULL; @@ -48,42 +54,60 @@ void *request_page(size_t size) void free_page(void *addr, size_t size) { - size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + size_t aligned_size = ALIGN_UP(size, PAGE_SIZE); sysdep(MemoryUnmap)(addr, aligned_size); } MemoryBlock *allocate_block(size_t slot_size) { - size_t block_size = PAGE_SIZE; - size_t slots_per_block = block_size / slot_size; - size_t bitmap_size = (slots_per_block + 7) / 8; + if (slot_size == 0 || slot_size > PAGE_SIZE / 2) + return NULL; - MemoryBlock *block = request_page(block_size); + size_t estimated_slots = (PAGE_SIZE - sizeof(MemoryBlock)) / (slot_size + 1.0 / 8.0); + if (estimated_slots == 0) + estimated_slots = 1; + + size_t bitmap_size = ALIGN_UP((estimated_slots + 7) / 8, 8); + size_t total_slots_size = estimated_slots * slot_size; + size_t total_size = sizeof(MemoryBlock) + bitmap_size + total_slots_size; + total_size = ALIGN_UP(total_size, PAGE_SIZE); + + MemoryBlock *block = (MemoryBlock *)request_page(total_size); if (!block) return NULL; - block->slots = (void *)((uintptr_t)block + sizeof(MemoryBlock) + bitmap_size); + uintptr_t base = (uintptr_t)block + sizeof(MemoryBlock); + block->bitmap = (uint8_t *)base; + block->bitmap_size = bitmap_size; + + block->slots = (void *)ALIGN_UP(base + bitmap_size, 16); block->slot_size = slot_size; - block->slots_per_block = slots_per_block; - block->bitmap = (uint8_t *)((uintptr_t)block + sizeof(MemoryBlock)); - memset(block->bitmap, 0, bitmap_size); + block->slots_per_block = (total_size - ((uintptr_t)block->slots - (uintptr_t)block)) / slot_size; + block->total_size = total_size; block->next = NULL; + memset(block->bitmap, 0, bitmap_size); return block; } void *mini_malloc(size_t size) { + if (size == 0) + return NULL; + MemoryBlock *block = memory_pool; while (block) { - for (size_t i = 0; i < block->slots_per_block; i++) + if (block->slot_size == size) { - size_t byte = i / 8, bit = i % 8; - if (!(block->bitmap[byte] & (1 << bit))) + for (size_t i = 0; i < block->slots_per_block; i++) { - block->bitmap[byte] |= (1 << bit); - return (void *)((uintptr_t)block->slots + i * size); + size_t byte = i / 8, bit = i % 8; + if (!(block->bitmap[byte] & (1 << bit))) + { + block->bitmap[byte] |= (1 << bit); + return (void *)((uintptr_t)block->slots + i * block->slot_size); + } } } block = block->next; @@ -105,10 +129,12 @@ void mini_free(void *ptr) MemoryBlock *block = memory_pool; while (block) { - if ((uintptr_t)ptr >= (uintptr_t)block->slots && - (uintptr_t)ptr < (uintptr_t)block->slots + block->slots_per_block * block->slot_size) + uintptr_t start = (uintptr_t)block->slots; + uintptr_t end = start + block->slots_per_block * block->slot_size; + + if ((uintptr_t)ptr >= start && (uintptr_t)ptr < end) { - size_t index = ((uintptr_t)ptr - (uintptr_t)block->slots) / block->slot_size; + size_t index = ((uintptr_t)ptr - start) / block->slot_size; size_t byte = index / 8, bit = index % 8; block->bitmap[byte] &= ~(1 << bit); return; diff --git a/Userspace/libc/interpreter/helper.c b/Userspace/libc/interpreter/helper.c index 9a3e1d6a..dbcda355 100644 --- a/Userspace/libc/interpreter/helper.c +++ b/Userspace/libc/interpreter/helper.c @@ -67,6 +67,19 @@ int strcmp(const char *l, const char *r) return *l - *r; } +int strncmp(const char *s1, const char *s2, size_t n) +{ + for (size_t i = 0; i < n; i++) + { + char c1 = s1[i], c2 = s2[i]; + if (c1 != c2) + return c1 - c2; + if (!c1) + return 0; + } + return 0; +} + char *strcat(char *dest, const char *src) { char *d = dest; @@ -77,6 +90,115 @@ char *strcat(char *dest, const char *src) return dest; } +char *strrchr(const char *str, int c) +{ + const char *last_occurrence = NULL; + + while (*str) + { + if (*str == (char)c) + last_occurrence = str; + str++; + } + + if (c == '\0') + return (char *)str; + + return (char *)last_occurrence; +} + +char *strncpy(char *destination, const char *source, unsigned long num) +{ + if (destination == NULL) + return NULL; + + char *ptr = destination; + while (*source && num--) + { + *destination = *source; + destination++; + source++; + } + + *destination = '\0'; + return ptr; +} + +char *strdup(const char *str) +{ + char *buf = (char *)mini_malloc(strlen((char *)str) + 1); + strncpy(buf, str, strlen(str) + 1); + return buf; +} + +unsigned int isdelim(char c, const char *delim) +{ + while (*delim != '\0') + { + if (c == *delim) + return 1; + delim++; + } + return 0; +} + +char *strtok(char *src, const char *delim) +{ + static char *src1; + if (!src) + src = src1; + + if (!src) + return NULL; + + while (1) + { + if (isdelim(*src, (char *)delim)) + { + src++; + continue; + } + if (*src == '\0') + return NULL; + + break; + } + char *ret = src; + while (1) + { + if (*src == '\0') + { + src1 = src; + return ret; + } + if (isdelim(*src, (char *)delim)) + { + *src = '\0'; + src1 = src + 1; + return ret; + } + src++; + } + return NULL; +} + +char **environ; +char *getenv(const char *name) +{ + if (name == NULL) + return NULL; + + size_t len = strlen(name); + for (char **env = environ; *env != 0; ++env) + { + char *thisEnv = *env; + char cmp = strncmp(thisEnv, name, len) == 0; + if (cmp && thisEnv[len] == '=') + return thisEnv + len + 1; + } + return NULL; +} + unsigned long elf_hash(const unsigned char *name) { unsigned long hash = 0, high; diff --git a/Userspace/libc/interpreter/load.c b/Userspace/libc/interpreter/load.c index e6d72fca..78430d11 100644 --- a/Userspace/libc/interpreter/load.c +++ b/Userspace/libc/interpreter/load.c @@ -385,7 +385,7 @@ void ProcessNeededLibraries(Elf_Dyn *elem, ElfInfo *Info) path = strtok(NULL, ":"); } - free(pathCopy); + mini_free(pathCopy); if (found) goto load_lib; } diff --git a/Userspace/libc/interpreter/main.c b/Userspace/libc/interpreter/main.c index 1f7c49ba..b1a4db55 100644 --- a/Userspace/libc/interpreter/main.c +++ b/Userspace/libc/interpreter/main.c @@ -17,24 +17,55 @@ #include #include +#include + +#ifndef PROGRAM_VERSION +#define PROGRAM_VERSION "" +#endif int printf(const char *, ...); int _dl_main(int, char *[], char *[]); +void print_license() +{ + printf("Fennix C Library Interpreter Copyright (C) %s EnderIce2\n", (__DATE__ + 7)); + printf("This program comes with ABSOLUTELY NO WARRANTY.\n"); + printf("This is free software, and you are welcome to redistribute it\n"); + printf("under certain conditions.\n"); +} + +void print_version() +{ + printf("%s\n", PROGRAM_VERSION); +} + void print_help() { printf("Usage: ld.so [options] \n"); printf("Options:\n"); printf(" --help Display this help message\n"); + printf(" --version Display version information\n"); + printf(" --license Display license information\n"); + printf("\n"); + print_license(); } +bool IsManuallyInvoked(const char *argv0) +{ + const char *lastSlash = strrchr(argv0, '/'); + const char *name = lastSlash ? lastSlash + 1 : argv0; + /* TODO: check if exe is actually "ld.so" or it has other name */ + return strcmp(name, "ld.so") == 0; +} + +extern char **environ; int main(int argc, char *argv[], char *envp[]) { - if (argc < 2) + environ = envp; + if (!IsManuallyInvoked(argv[0])) { - printf("Error: No program specified.\n"); - print_help(); - return -1; + int status = _dl_main(argc, argv, envp); + return status; } for (int i = 1; i < argc; i++) @@ -44,8 +75,19 @@ int main(int argc, char *argv[], char *envp[]) print_help(); return 0; } + if (strcmp(argv[i], "--version") == 0) + { + print_version(); + return 0; + } + if (strcmp(argv[i], "--license") == 0) + { + print_license(); + return 0; + } } - int status = _dl_main(argc, argv, envp); - return status; + printf("Error: No program specified.\n"); + printf("Try 'ld.so --help' for more information.\n"); + return -1; } diff --git a/Userspace/libc/interpreter/misc.h b/Userspace/libc/interpreter/misc.h index 5ccc8951..c45e37c6 100644 --- a/Userspace/libc/interpreter/misc.h +++ b/Userspace/libc/interpreter/misc.h @@ -34,7 +34,14 @@ void *memcpy(void *dest, const void *src, size_t n); size_t strlen(const char *s); char *strcpy(char *dest, const char *src); int strcmp(const char *l, const char *r); +int strncmp(const char *s1, const char *s2, size_t n); char *strcat(char *dest, const char *src); +char *strrchr(const char *str, int c); +char *strncpy(char *destination, const char *source, unsigned long num); +char *strdup(const char *str); +unsigned int isdelim(char c, const char *delim); +char *strtok(char *src, const char *delim); +char *getenv(const char *name); unsigned long elf_hash(const unsigned char *name); uint32_t gnu_hash(const char *name); diff --git a/Userspace/libc/sysdeps/fennix/generic/dl_start.c b/Userspace/libc/sysdeps/fennix/generic/dl_start.c index fbdf937e..7e79a86b 100644 --- a/Userspace/libc/sysdeps/fennix/generic/dl_start.c +++ b/Userspace/libc/sysdeps/fennix/generic/dl_start.c @@ -16,35 +16,35 @@ */ #ifdef FENNIX_DYNAMIC_LOADER +#define _s __asm__ __volatile__ __attribute__((naked, used, no_stack_protector)) void _dl_start() { #if defined(__amd64__) - __asm__( - "xorq %rbp, %rbp\n" /* Clear rbp */ + _s("xorq %rbp, %rbp\n"); /* Clear rbp */ - "push %rdi\n" - "push %rsi\n" - "push %rdx\n" - "push %rcx\n" - "push %r8\n" - "push %r9\n" + _s("pushq %rdi\n"); + _s("pushq %rsi\n"); + _s("pushq %rdx\n"); + _s("pushq %rcx\n"); + _s("pushq %r8\n"); + _s("pushq %r9\n"); - "call __init_print_buffer\n" /* Call __init_print_buffer */ - "call _dl_preload\n" /* Call _dl_preload */ - "movl %eax, %edi\n" /* Move return value to edi */ - "cmp $0, %edi\n" /* Check if return value is 0 */ - "jne _exit\n" /* If not, jump to _exit */ + _s("call __init_print_buffer\n"); /* Call __init_print_buffer */ + _s("call _dl_preload\n"); /* Call _dl_preload */ + _s("movl %eax, %edi\n"); /* Move return value to edi */ + _s("cmp $0, %edi\n"); /* Check if return value is 0 */ + _s("jne _exit\n"); /* If not, jump to _exit */ - "pop %r9\n" - "pop %r8\n" - "pop %rcx\n" - "pop %rdx\n" - "pop %rsi\n" - "pop %rdi\n" + _s("popq %r9\n"); + _s("popq %r8\n"); + _s("popq %rcx\n"); + _s("popq %rdx\n"); + _s("popq %rsi\n"); + _s("popq %rdi\n"); - "call main\n" /* Call _dl_main */ - "movl %eax, %edi\n" /* Move return value to edi */ - "call _exit\n"); /* Call _exit */ + _s("call main\n"); /* Call _dl_main */ + _s("movl %eax, %edi\n"); /* Move return value to edi */ + _s("call _exit\n"); /* Call _exit */ #elif defined(__i386__) #warning "i386 _start not implemented" #elif defined(__arm__) @@ -55,4 +55,5 @@ __attribute__((naked, used, no_stack_protector)) void _dl_start() #error "Unsupported architecture" #endif } +#undef _s #endif