diff --git a/cleonos/c/apps/dltest_main.c b/cleonos/c/apps/dltest_main.c new file mode 100644 index 0000000..92a97fb --- /dev/null +++ b/cleonos/c/apps/dltest_main.c @@ -0,0 +1,48 @@ +#include +#include + +typedef unsigned long long u64; +typedef u64 (*dl_math2_fn)(u64, u64); +typedef u64 (*dl_void_fn)(void); + +int cleonos_app_main(int argc, char **argv, char **envp) { + const char *lib_path = "/shell/libdemo.elf"; + void *handle; + dl_math2_fn add_fn; + dl_math2_fn mul_fn; + dl_void_fn hello_fn; + + (void)envp; + + if (argc > 1 && argv != (char **)0 && argv[1] != (char *)0 && argv[1][0] != '\0') { + lib_path = argv[1]; + } + + handle = dlopen(lib_path, 0); + if (handle == (void *)0) { + (void)printf("[dltest] dlopen failed: %s\n", lib_path); + return 1; + } + + add_fn = (dl_math2_fn)dlsym(handle, "cleonos_libdemo_add"); + mul_fn = (dl_math2_fn)dlsym(handle, "cleonos_libdemo_mul"); + hello_fn = (dl_void_fn)dlsym(handle, "cleonos_libdemo_hello"); + + if (add_fn == (dl_math2_fn)0 || mul_fn == (dl_math2_fn)0 || hello_fn == (dl_void_fn)0) { + (void)puts("[dltest] dlsym failed"); + (void)dlclose(handle); + return 2; + } + + (void)hello_fn(); + (void)printf("[dltest] add(7, 35) = %llu\n", add_fn(7ULL, 35ULL)); + (void)printf("[dltest] mul(6, 9) = %llu\n", mul_fn(6ULL, 9ULL)); + + if (dlclose(handle) != 0) { + (void)puts("[dltest] dlclose failed"); + return 3; + } + + (void)puts("[dltest] PASS"); + return 0; +} diff --git a/cleonos/c/apps/libdemo_main.c b/cleonos/c/apps/libdemo_main.c new file mode 100644 index 0000000..44c01c4 --- /dev/null +++ b/cleonos/c/apps/libdemo_main.c @@ -0,0 +1,24 @@ +#include + +typedef unsigned long long u64; + +u64 cleonos_libdemo_add(u64 left, u64 right) { + return left + right; +} + +u64 cleonos_libdemo_mul(u64 left, u64 right) { + return left * right; +} + +u64 cleonos_libdemo_hello(void) { + (void)puts("[libdemo] hello from libdemo.elf"); + return 0ULL; +} + +int cleonos_app_main(int argc, char **argv, char **envp) { + (void)argc; + (void)argv; + (void)envp; + (void)puts("[libdemo] dynamic library image ready"); + return 0; +} diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 4eb7e74..0adbcb4 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -119,6 +119,9 @@ typedef struct cleonos_proc_snapshot { #define CLEONOS_SYSCALL_FD_WRITE 74ULL #define CLEONOS_SYSCALL_FD_CLOSE 75ULL #define CLEONOS_SYSCALL_FD_DUP 76ULL +#define CLEONOS_SYSCALL_DL_OPEN 77ULL +#define CLEONOS_SYSCALL_DL_CLOSE 78ULL +#define CLEONOS_SYSCALL_DL_SYM 79ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); @@ -197,5 +200,8 @@ u64 cleonos_sys_fd_read(u64 fd, void *out_buffer, u64 size); u64 cleonos_sys_fd_write(u64 fd, const void *buffer, u64 size); u64 cleonos_sys_fd_close(u64 fd); u64 cleonos_sys_fd_dup(u64 fd); +u64 cleonos_sys_dl_open(const char *path); +u64 cleonos_sys_dl_close(u64 handle); +u64 cleonos_sys_dl_sym(u64 handle, const char *symbol); #endif diff --git a/cleonos/c/include/dlfcn.h b/cleonos/c/include/dlfcn.h new file mode 100644 index 0000000..1ceb0d7 --- /dev/null +++ b/cleonos/c/include/dlfcn.h @@ -0,0 +1,8 @@ +#ifndef CLEONOS_LIBC_DLFCN_H +#define CLEONOS_LIBC_DLFCN_H + +void *dlopen(const char *path, int flags); +void *dlsym(void *handle, const char *symbol); +int dlclose(void *handle); + +#endif diff --git a/cleonos/c/src/dlfcn.c b/cleonos/c/src/dlfcn.c new file mode 100644 index 0000000..fffd616 --- /dev/null +++ b/cleonos/c/src/dlfcn.c @@ -0,0 +1,48 @@ +#include + +#include + +void *dlopen(const char *path, int flags) { + u64 handle; + + (void)flags; + + if (path == (const char *)0 || path[0] == '\0') { + return (void *)0; + } + + handle = cleonos_sys_dl_open(path); + + if (handle == 0ULL || handle == (u64)-1) { + return (void *)0; + } + + return (void *)handle; +} + +void *dlsym(void *handle, const char *symbol) { + u64 addr; + + if (handle == (void *)0 || symbol == (const char *)0 || symbol[0] == '\0') { + return (void *)0; + } + + addr = cleonos_sys_dl_sym((u64)handle, symbol); + + if (addr == 0ULL || addr == (u64)-1) { + return (void *)0; + } + + return (void *)addr; +} + +int dlclose(void *handle) { + u64 rc; + + if (handle == (void *)0) { + return -1; + } + + rc = cleonos_sys_dl_close((u64)handle); + return (rc == (u64)-1) ? -1 : 0; +} diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index 96059fa..12973e4 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -330,3 +330,15 @@ u64 cleonos_sys_fd_close(u64 fd) { u64 cleonos_sys_fd_dup(u64 fd) { return cleonos_syscall(CLEONOS_SYSCALL_FD_DUP, fd, 0ULL, 0ULL); } + +u64 cleonos_sys_dl_open(const char *path) { + return cleonos_syscall(CLEONOS_SYSCALL_DL_OPEN, (u64)path, 0ULL, 0ULL); +} + +u64 cleonos_sys_dl_close(u64 handle) { + return cleonos_syscall(CLEONOS_SYSCALL_DL_CLOSE, handle, 0ULL, 0ULL); +} + +u64 cleonos_sys_dl_sym(u64 handle, const char *symbol) { + return cleonos_syscall(CLEONOS_SYSCALL_DL_SYM, handle, (u64)symbol, 0ULL); +} diff --git a/clks/include/clks/exec.h b/clks/include/clks/exec.h index 2a98644..49973c3 100644 --- a/clks/include/clks/exec.h +++ b/clks/include/clks/exec.h @@ -45,6 +45,9 @@ u64 clks_exec_fd_read(u64 fd, void *out_buffer, u64 size); u64 clks_exec_fd_write(u64 fd, const void *buffer, u64 size); u64 clks_exec_fd_close(u64 fd); u64 clks_exec_fd_dup(u64 fd); +u64 clks_exec_dl_open(const char *path); +u64 clks_exec_dl_close(u64 handle); +u64 clks_exec_dl_sym(u64 handle, const char *symbol); u64 clks_exec_current_pid(void); u32 clks_exec_current_tty(void); u64 clks_exec_current_argc(void); diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index 219491a..73e29d6 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -80,6 +80,9 @@ #define CLKS_SYSCALL_FD_WRITE 74ULL #define CLKS_SYSCALL_FD_CLOSE 75ULL #define CLKS_SYSCALL_FD_DUP 76ULL +#define CLKS_SYSCALL_DL_OPEN 77ULL +#define CLKS_SYSCALL_DL_CLOSE 78ULL +#define CLKS_SYSCALL_DL_SYM 79ULL void clks_syscall_init(void); u64 clks_syscall_dispatch(void *frame_ptr); diff --git a/clks/include/clks/tty.h b/clks/include/clks/tty.h index 9a2a0c9..673fd1d 100644 --- a/clks/include/clks/tty.h +++ b/clks/include/clks/tty.h @@ -5,6 +5,7 @@ void clks_tty_init(void); void clks_tty_write(const char *text); +void clks_tty_write_n(const char *text, usize len); void clks_tty_write_char(char ch); void clks_tty_switch(u32 tty_index); void clks_tty_tick(u64 tick); diff --git a/clks/kernel/exec.c b/clks/kernel/exec.c index a3b7f0d..ec63d59 100644 --- a/clks/kernel/exec.c +++ b/clks/kernel/exec.c @@ -34,6 +34,21 @@ typedef u64 (*clks_exec_entry_fn)(void); #define CLKS_EXEC_O_CREAT 0x0040ULL #define CLKS_EXEC_O_TRUNC 0x0200ULL #define CLKS_EXEC_O_APPEND 0x0400ULL +#define CLKS_EXEC_DYNLIB_MAX 32U + +#define CLKS_EXEC_ELF64_MAGIC_0 0x7FU +#define CLKS_EXEC_ELF64_MAGIC_1 'E' +#define CLKS_EXEC_ELF64_MAGIC_2 'L' +#define CLKS_EXEC_ELF64_MAGIC_3 'F' +#define CLKS_EXEC_ELF64_CLASS_64 2U +#define CLKS_EXEC_ELF64_DATA_LSB 1U +#define CLKS_EXEC_ELF64_VERSION 1U + +#define CLKS_EXEC_ELF64_SHT_SYMTAB 2U +#define CLKS_EXEC_ELF64_SHT_DYNSYM 11U +#define CLKS_EXEC_ELF64_SHN_UNDEF 0U +#define CLKS_EXEC_ELF64_STT_NOTYPE 0U +#define CLKS_EXEC_ELF64_STT_FUNC 2U enum clks_exec_fd_kind { CLKS_EXEC_FD_KIND_NONE = 0, @@ -84,6 +99,56 @@ struct clks_exec_proc_record { struct clks_exec_fd_entry fds[CLKS_EXEC_FD_MAX]; }; +struct clks_exec_elf64_ehdr { + u8 e_ident[16]; + u16 e_type; + u16 e_machine; + u32 e_version; + u64 e_entry; + u64 e_phoff; + u64 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; +}; + +struct clks_exec_elf64_shdr { + u32 sh_name; + u32 sh_type; + u64 sh_flags; + u64 sh_addr; + u64 sh_offset; + u64 sh_size; + u32 sh_link; + u32 sh_info; + u64 sh_addralign; + u64 sh_entsize; +}; + +struct clks_exec_elf64_sym { + u32 st_name; + u8 st_info; + u8 st_other; + u16 st_shndx; + u64 st_value; + u64 st_size; +}; + +struct clks_exec_dynlib_slot { + clks_bool used; + u64 handle; + u64 owner_pid; + u64 ref_count; + char path[CLKS_EXEC_PATH_MAX]; + const void *file_image; + u64 file_size; + struct clks_elf64_loaded_image loaded; +}; + #if defined(CLKS_ARCH_X86_64) extern u64 clks_exec_call_on_stack_x86_64(void *entry_ptr, void *stack_top); extern void clks_exec_abort_to_caller_x86_64(void); @@ -105,6 +170,8 @@ static clks_bool clks_exec_unwind_slot_valid_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_image_begin_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_image_end_stack[CLKS_EXEC_MAX_DEPTH]; static u32 clks_exec_pid_stack_depth = 0U; +static struct clks_exec_dynlib_slot clks_exec_dynlib_table[CLKS_EXEC_DYNLIB_MAX]; +static u64 clks_exec_next_dynlib_handle = 1ULL; static struct clks_exec_proc_record *clks_exec_current_proc(void); @@ -263,6 +330,267 @@ static void clks_exec_copy_line(char *dst, usize dst_size, const char *src) { dst[i] = '\0'; } +static clks_bool clks_exec_range_ok(u64 off, u64 len, u64 total) { + if (off > total) { + return CLKS_FALSE; + } + + if (len > (total - off)) { + return CLKS_FALSE; + } + + return CLKS_TRUE; +} + +static i32 clks_exec_dynlib_alloc_slot(void) { + u32 i; + + for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { + if (clks_exec_dynlib_table[i].used == CLKS_FALSE) { + return (i32)i; + } + } + + return -1; +} + +static i32 clks_exec_dynlib_find_by_handle(u64 handle) { + u32 i; + + for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { + if (clks_exec_dynlib_table[i].used == CLKS_TRUE && clks_exec_dynlib_table[i].handle == handle) { + return (i32)i; + } + } + + return -1; +} + +static i32 clks_exec_dynlib_find_by_owner_path(u64 owner_pid, const char *path) { + u32 i; + + if (path == CLKS_NULL) { + return -1; + } + + for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { + if (clks_exec_dynlib_table[i].used != CLKS_TRUE) { + continue; + } + + if (clks_exec_dynlib_table[i].owner_pid == owner_pid && + clks_strcmp(clks_exec_dynlib_table[i].path, path) == 0) { + return (i32)i; + } + } + + return -1; +} + +static u64 clks_exec_dynlib_alloc_handle(void) { + u64 handle = clks_exec_next_dynlib_handle; + + clks_exec_next_dynlib_handle++; + if (clks_exec_next_dynlib_handle == 0ULL) { + clks_exec_next_dynlib_handle = 1ULL; + } + + if (handle == 0ULL) { + handle = clks_exec_next_dynlib_handle; + clks_exec_next_dynlib_handle++; + if (clks_exec_next_dynlib_handle == 0ULL) { + clks_exec_next_dynlib_handle = 1ULL; + } + } + + return handle; +} + +static void clks_exec_dynlib_slot_reset(struct clks_exec_dynlib_slot *slot) { + if (slot == CLKS_NULL) { + return; + } + + if (slot->used == CLKS_TRUE && slot->loaded.image_base != CLKS_NULL) { + clks_elf64_unload(&slot->loaded); + } + + clks_memset(slot, 0, sizeof(*slot)); +} + +static void clks_exec_dynlib_release_owner(u64 owner_pid) { + u32 i; + + if (owner_pid == 0ULL) { + return; + } + + for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { + if (clks_exec_dynlib_table[i].used == CLKS_TRUE && + clks_exec_dynlib_table[i].owner_pid == owner_pid) { + clks_exec_dynlib_slot_reset(&clks_exec_dynlib_table[i]); + } + } +} + +static clks_bool clks_exec_dynlib_elf_header_ok(const struct clks_exec_elf64_ehdr *eh) { + if (eh == CLKS_NULL) { + return CLKS_FALSE; + } + + if (eh->e_ident[0] != CLKS_EXEC_ELF64_MAGIC_0 || + eh->e_ident[1] != CLKS_EXEC_ELF64_MAGIC_1 || + eh->e_ident[2] != CLKS_EXEC_ELF64_MAGIC_2 || + eh->e_ident[3] != CLKS_EXEC_ELF64_MAGIC_3) { + return CLKS_FALSE; + } + + if (eh->e_ident[4] != CLKS_EXEC_ELF64_CLASS_64 || eh->e_ident[5] != CLKS_EXEC_ELF64_DATA_LSB) { + return CLKS_FALSE; + } + + if (eh->e_ident[6] != CLKS_EXEC_ELF64_VERSION || eh->e_version != CLKS_EXEC_ELF64_VERSION) { + return CLKS_FALSE; + } + + if (eh->e_shentsize != sizeof(struct clks_exec_elf64_shdr)) { + return CLKS_FALSE; + } + + return CLKS_TRUE; +} + +static clks_bool clks_exec_dynlib_symbol_name_ptr(const char *strtab, + u64 strtab_size, + u32 st_name, + const char **out_name) { + u64 i; + + if (out_name != CLKS_NULL) { + *out_name = CLKS_NULL; + } + + if (strtab == CLKS_NULL || out_name == CLKS_NULL || st_name >= strtab_size) { + return CLKS_FALSE; + } + + for (i = (u64)st_name; i < strtab_size; i++) { + if (strtab[i] == '\0') { + *out_name = &strtab[st_name]; + return CLKS_TRUE; + } + } + + return CLKS_FALSE; +} + +static clks_bool clks_exec_dynlib_resolve_symbol(const struct clks_exec_dynlib_slot *slot, + const char *symbol, + u64 *out_addr) { + const struct clks_exec_elf64_ehdr *eh; + const struct clks_exec_elf64_shdr *shdrs; + const u8 *image; + u64 i; + u64 sh_table_size; + + if (out_addr != CLKS_NULL) { + *out_addr = 0ULL; + } + + if (slot == CLKS_NULL || slot->used != CLKS_TRUE || symbol == CLKS_NULL || symbol[0] == '\0' || + out_addr == CLKS_NULL) { + return CLKS_FALSE; + } + + image = (const u8 *)slot->file_image; + + if (image == CLKS_NULL || slot->file_size < sizeof(struct clks_exec_elf64_ehdr)) { + return CLKS_FALSE; + } + + eh = (const struct clks_exec_elf64_ehdr *)image; + + if (clks_exec_dynlib_elf_header_ok(eh) == CLKS_FALSE || eh->e_shnum == 0U || eh->e_shoff == 0ULL) { + return CLKS_FALSE; + } + + sh_table_size = (u64)eh->e_shnum * (u64)eh->e_shentsize; + if (clks_exec_range_ok(eh->e_shoff, sh_table_size, slot->file_size) == CLKS_FALSE) { + return CLKS_FALSE; + } + + shdrs = (const struct clks_exec_elf64_shdr *)(image + (usize)eh->e_shoff); + + for (i = 0ULL; i < (u64)eh->e_shnum; i++) { + const struct clks_exec_elf64_shdr *symtab = &shdrs[i]; + const struct clks_exec_elf64_shdr *strtab; + const struct clks_exec_elf64_sym *symbols; + const char *strings; + u64 sym_count; + u64 j; + + if (symtab->sh_type != CLKS_EXEC_ELF64_SHT_SYMTAB && symtab->sh_type != CLKS_EXEC_ELF64_SHT_DYNSYM) { + continue; + } + + if (symtab->sh_entsize != sizeof(struct clks_exec_elf64_sym) || symtab->sh_link >= eh->e_shnum || + symtab->sh_size < symtab->sh_entsize) { + continue; + } + + if (clks_exec_range_ok(symtab->sh_offset, symtab->sh_size, slot->file_size) == CLKS_FALSE) { + continue; + } + + strtab = &shdrs[symtab->sh_link]; + if (clks_exec_range_ok(strtab->sh_offset, strtab->sh_size, slot->file_size) == CLKS_FALSE) { + continue; + } + + symbols = (const struct clks_exec_elf64_sym *)(image + (usize)symtab->sh_offset); + strings = (const char *)(image + (usize)strtab->sh_offset); + sym_count = symtab->sh_size / symtab->sh_entsize; + + for (j = 0ULL; j < sym_count; j++) { + const struct clks_exec_elf64_sym *sym = &symbols[j]; + const char *name_ptr; + u8 symbol_type; + u64 offset; + + if (sym->st_name == 0U || sym->st_shndx == CLKS_EXEC_ELF64_SHN_UNDEF || sym->st_value == 0ULL) { + continue; + } + + symbol_type = (u8)(sym->st_info & 0x0FU); + if (symbol_type != CLKS_EXEC_ELF64_STT_FUNC && symbol_type != CLKS_EXEC_ELF64_STT_NOTYPE) { + continue; + } + + if (clks_exec_dynlib_symbol_name_ptr(strings, strtab->sh_size, sym->st_name, &name_ptr) == CLKS_FALSE) { + continue; + } + + if (clks_strcmp(name_ptr, symbol) != 0) { + continue; + } + + if (sym->st_value < slot->loaded.image_vaddr_base) { + continue; + } + + offset = sym->st_value - slot->loaded.image_vaddr_base; + if (offset >= slot->loaded.image_size) { + continue; + } + + *out_addr = (u64)((u8 *)slot->loaded.image_base + (usize)offset); + return CLKS_TRUE; + } + } + + return CLKS_FALSE; +} + static void clks_exec_clear_items(char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { u32 i; @@ -931,6 +1259,8 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) { clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), run_ret); } + clks_exec_dynlib_release_owner(proc->pid); + if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; @@ -955,6 +1285,7 @@ fail: } clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); + clks_exec_dynlib_release_owner(proc->pid); if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; @@ -1066,6 +1397,8 @@ void clks_exec_init(void) { clks_memset(clks_exec_image_begin_stack, 0, sizeof(clks_exec_image_begin_stack)); clks_memset(clks_exec_image_end_stack, 0, sizeof(clks_exec_image_end_stack)); clks_memset(clks_exec_proc_table, 0, sizeof(clks_exec_proc_table)); + clks_memset(clks_exec_dynlib_table, 0, sizeof(clks_exec_dynlib_table)); + clks_exec_next_dynlib_handle = 1ULL; clks_exec_log_info_serial("PATH EXEC FRAMEWORK ONLINE"); } @@ -1324,13 +1657,7 @@ u64 clks_exec_fd_write(u64 fd, const void *buffer, u64 size) { } if (entry->kind == CLKS_EXEC_FD_KIND_TTY) { - u64 i; - const char *src = (const char *)buffer; - - for (i = 0ULL; i < size; i++) { - clks_tty_write_char(src[i]); - } - + clks_tty_write_n((const char *)buffer, (usize)size); return size; } @@ -1384,6 +1711,119 @@ u64 clks_exec_fd_dup(u64 fd) { return (u64)fd_slot; } +u64 clks_exec_dl_open(const char *path) { + struct clks_exec_proc_record *proc = clks_exec_current_proc(); + const void *image; + u64 image_size = 0ULL; + i32 existing_slot; + i32 slot; + u64 owner_pid; + struct clks_exec_dynlib_slot *dyn; + + if (proc == CLKS_NULL || path == CLKS_NULL || path[0] != '/') { + return (u64)-1; + } + + if (clks_strlen(path) >= CLKS_EXEC_PATH_MAX) { + return (u64)-1; + } + + owner_pid = proc->pid; + existing_slot = clks_exec_dynlib_find_by_owner_path(owner_pid, path); + + if (existing_slot >= 0) { + dyn = &clks_exec_dynlib_table[(u32)existing_slot]; + dyn->ref_count++; + return dyn->handle; + } + + slot = clks_exec_dynlib_alloc_slot(); + if (slot < 0) { + return (u64)-1; + } + + image = clks_fs_read_all(path, &image_size); + if (image == CLKS_NULL || image_size == 0ULL) { + return (u64)-1; + } + + dyn = &clks_exec_dynlib_table[(u32)slot]; + clks_memset(dyn, 0, sizeof(*dyn)); + + if (clks_elf64_load(image, image_size, &dyn->loaded) == CLKS_FALSE) { + clks_memset(dyn, 0, sizeof(*dyn)); + return (u64)-1; + } + + dyn->used = CLKS_TRUE; + dyn->handle = clks_exec_dynlib_alloc_handle(); + dyn->owner_pid = owner_pid; + dyn->ref_count = 1ULL; + dyn->file_image = image; + dyn->file_size = image_size; + clks_exec_copy_path(dyn->path, sizeof(dyn->path), path); + + clks_exec_log_info_serial("DLOPEN OK"); + clks_exec_log_info_serial(path); + clks_exec_log_hex_serial("DL_HANDLE", dyn->handle); + return dyn->handle; +} + +u64 clks_exec_dl_close(u64 handle) { + struct clks_exec_proc_record *proc = clks_exec_current_proc(); + i32 slot; + struct clks_exec_dynlib_slot *dyn; + + if (proc == CLKS_NULL || handle == 0ULL) { + return (u64)-1; + } + + slot = clks_exec_dynlib_find_by_handle(handle); + if (slot < 0) { + return (u64)-1; + } + + dyn = &clks_exec_dynlib_table[(u32)slot]; + if (dyn->owner_pid != proc->pid) { + return (u64)-1; + } + + if (dyn->ref_count > 1ULL) { + dyn->ref_count--; + return 0ULL; + } + + clks_exec_dynlib_slot_reset(dyn); + return 0ULL; +} + +u64 clks_exec_dl_sym(u64 handle, const char *symbol) { + struct clks_exec_proc_record *proc = clks_exec_current_proc(); + i32 slot; + struct clks_exec_dynlib_slot *dyn; + u64 addr = 0ULL; + + if (proc == CLKS_NULL || handle == 0ULL || symbol == CLKS_NULL || symbol[0] == '\0') { + return 0ULL; + } + + slot = clks_exec_dynlib_find_by_handle(handle); + if (slot < 0) { + return 0ULL; + } + + dyn = &clks_exec_dynlib_table[(u32)slot]; + if (dyn->owner_pid != proc->pid) { + return 0ULL; + } + + if (clks_exec_dynlib_resolve_symbol(dyn, symbol, &addr) == CLKS_FALSE) { + return 0ULL; + } + + return addr; +} + u64 clks_exec_current_pid(void) { i32 depth_index = clks_exec_current_depth_index(); diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index c0cc5fb..c38e1d8 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -32,7 +32,7 @@ #define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL) #define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym" #define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL -#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_FD_DUP +#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_DL_SYM #define CLKS_SYSCALL_STATS_RING_SIZE 256U struct clks_syscall_frame { @@ -244,6 +244,30 @@ static u64 clks_syscall_fd_dup(u64 arg0) { return clks_exec_fd_dup(arg0); } +static u64 clks_syscall_dl_open(u64 arg0) { + char path[CLKS_SYSCALL_PATH_MAX]; + + if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { + return (u64)-1; + } + + return clks_exec_dl_open(path); +} + +static u64 clks_syscall_dl_close(u64 arg0) { + return clks_exec_dl_close(arg0); +} + +static u64 clks_syscall_dl_sym(u64 arg0, u64 arg1) { + char symbol[CLKS_SYSCALL_NAME_MAX]; + + if (clks_syscall_copy_user_string(arg1, symbol, sizeof(symbol)) == CLKS_FALSE) { + return 0ULL; + } + + return clks_exec_dl_sym(arg0, symbol); +} + static clks_bool clks_syscall_procfs_is_root(const char *path) { return (path != CLKS_NULL && clks_strcmp(path, "/proc") == 0) ? CLKS_TRUE : CLKS_FALSE; } @@ -1830,6 +1854,12 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_syscall_fd_close(frame->rbx); case CLKS_SYSCALL_FD_DUP: return clks_syscall_fd_dup(frame->rbx); + case CLKS_SYSCALL_DL_OPEN: + return clks_syscall_dl_open(frame->rbx); + case CLKS_SYSCALL_DL_CLOSE: + return clks_syscall_dl_close(frame->rbx); + case CLKS_SYSCALL_DL_SYM: + return clks_syscall_dl_sym(frame->rbx, frame->rcx); default: return (u64)-1; } diff --git a/clks/kernel/tty.c b/clks/kernel/tty.c index 14ed77f..40cfe80 100644 --- a/clks/kernel/tty.c +++ b/clks/kernel/tty.c @@ -1215,11 +1215,11 @@ void clks_tty_write_char(char ch) { clks_tty_reset_blink_timer(); } -void clks_tty_write(const char *text) { +void clks_tty_write_n(const char *text, usize len) { usize i = 0U; u32 tty_index; - if (clks_tty_is_ready == CLKS_FALSE || text == CLKS_NULL) { + if (clks_tty_is_ready == CLKS_FALSE || text == CLKS_NULL || len == 0U) { return; } @@ -1231,7 +1231,7 @@ void clks_tty_write(const char *text) { clks_tty_redraw_active(); } - while (text[i] != '\0') { + while (i < len) { if (clks_tty_ansi_process_byte(tty_index, text[i]) == CLKS_FALSE) { clks_tty_put_char_raw(tty_index, text[i]); } @@ -1244,6 +1244,14 @@ void clks_tty_write(const char *text) { clks_tty_reset_blink_timer(); } +void clks_tty_write(const char *text) { + if (text == CLKS_NULL) { + return; + } + + clks_tty_write_n(text, clks_strlen(text)); +} + void clks_tty_switch(u32 tty_index) { if (clks_tty_is_ready == CLKS_FALSE) { return;