From 9a38908cea7064f344546bbc20ad79dab62631d6 Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Fri, 1 Dec 2023 18:49:42 +0100 Subject: [PATCH 01/11] libphoenix: Add option to compile as PIC JIRA: RTOS-664 --- Makefile | 3 +++ arch/arm/v7a/Makefile | 2 +- arch/arm/v7a/tls.S | 49 +++++++++++++++++++++++++++++++++++++++++++ arch/riscv64/Makefile | 2 +- arch/riscv64/tls.S | 41 ++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 arch/arm/v7a/tls.S create mode 100644 arch/riscv64/tls.S diff --git a/Makefile b/Makefile index 69467c08..30fdff7b 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,9 @@ endif CFLAGS += -Iinclude -fno-builtin-malloc +ifeq ($(LIBPHOENIX_PIC), y) +CFLAGS += $(TARGET_PIC_FLAG) +endif OBJS := # crt0.o should have all necessary initialization + call to main() diff --git a/arch/arm/v7a/Makefile b/arch/arm/v7a/Makefile index ae752782..42ae98f8 100644 --- a/arch/arm/v7a/Makefile +++ b/arch/arm/v7a/Makefile @@ -5,4 +5,4 @@ # Author: Pawel Pisarczyk # -OBJS += $(addprefix $(PREFIX_O)arch/arm/v7a/, syscalls.o reboot.o) +OBJS += $(addprefix $(PREFIX_O)arch/arm/v7a/, syscalls.o reboot.o tls.o) diff --git a/arch/arm/v7a/tls.S b/arch/arm/v7a/tls.S new file mode 100644 index 00000000..82f911d1 --- /dev/null +++ b/arch/arm/v7a/tls.S @@ -0,0 +1,49 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * tls access function + * + * Copyright 2023 Phoenix Systems + * Author: Hubert Badocha + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + + /* NOTE: + * When libphoenix is compiled as a PIC, even when linked into a static NOPIC binary, + * compiler generates accesses to TLS as calls to this function. + * This functions is simple version just for static binaries purposes, + * in dynamic binaries dynamic linker handles TLS accesses. */ + + +/* typedef struct { + * unsigned long ti_moduleid; + * unsigned long ti_tlsoffset; + * } TLS_index; + * + * void *__tls_get_addr(TLS_index *ti) */ +.thumb +.syntax unified + +.text + +.thumb_func +/* Declared as weak to be overwritten by dynamic linker */ +.weak __tls_get_addr; +.type __tls_get_addr, %function; +.align 2 +__tls_get_addr: + /* Access ti_tlsoffset. */ + ldr r0, [r0, #4] + /* Get thread pointer. */ + mrc p15, 0, r1, cr13, cr0, 3 + /* GCC expects that TLS block has 8 byte TCB pointer at the begging. */ + add r1, r1, #8 + add r0, r0, r1 + bx lr +.size __tls_get_addr, .-__tls_get_addr diff --git a/arch/riscv64/Makefile b/arch/riscv64/Makefile index 5674f637..cdd606cc 100644 --- a/arch/riscv64/Makefile +++ b/arch/riscv64/Makefile @@ -5,5 +5,5 @@ # Author: Pawel Pisarczyk # -OBJS += $(addprefix $(PREFIX_O)arch/riscv64/, syscalls.o string.o signal.o reboot.o jmp.o) +OBJS += $(addprefix $(PREFIX_O)arch/riscv64/, syscalls.o string.o signal.o reboot.o jmp.o tls.o) CRT0_OBJS += $(addprefix $(PREFIX_O)arch/riscv64/, crt0.o) diff --git a/arch/riscv64/tls.S b/arch/riscv64/tls.S new file mode 100644 index 00000000..a85b5ee5 --- /dev/null +++ b/arch/riscv64/tls.S @@ -0,0 +1,41 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * tls access function + * + * Copyright 2023 Phoenix Systems + * Author: Hubert Badocha + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +/* NOTE: + * When libphoenix is compiled as a PIC, even when linked into a static NOPIC binary, + * compiler generates accesses to TLS as calls to this function. + * This functions is simple version just for static binaries purposes, + * in dynamic binaries dynamic linker handles TLS accesses. */ + + +/* typedef struct { + * unsigned long ti_moduleid; + * unsigned long ti_tlsoffset; + * } TLS_index; + * + * void *__tls_get_addr(TLS_index *ti) */ + +/* Declared as weak to be overwritten by dynamic linker */ +.weak __tls_get_addr +.type __tls_get_addr, %function +__tls_get_addr: + /* Access ti_tlsoffset. */ + ld a0, 8(a0) + /* On RISC-V Dynamic Thread Vector pointer points at TLS block start + 0x800 */ + li t0, 0x800 + add a0, a0, t0 + add a0, a0, tp + ret +.size __tls_get_addr, .-__tls_get_addr From 7e6a31ebea7f4cee2a3f53a73987348a09c1bc2d Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Sun, 10 Dec 2023 22:41:09 +0100 Subject: [PATCH 02/11] ia32: support PIE in asm In PIE on ia32 function calls should be made using GOT. JIRA: RTOS-664 --- arch/ia32/jmp.S | 192 +++++++++++++++++++++++++-------------------- arch/ia32/signal.S | 27 +++++-- 2 files changed, 128 insertions(+), 91 deletions(-) diff --git a/arch/ia32/jmp.S b/arch/ia32/jmp.S index 13351d97..9efc42b2 100644 --- a/arch/ia32/jmp.S +++ b/arch/ia32/jmp.S @@ -5,127 +5,149 @@ * * setjmp, longjmp * - * Copyright 2018-2019 Phoenix Systems - * Author: Jan Sikorski, Andrzej Glowinski + * Copyright 2018-2019, 2023 Phoenix Systems + * Author: Jan Sikorski, Andrzej Glowinski, Hubert Badocha * * This file is part of Phoenix-RTOS. * * %LICENSE% */ + /* jmp_buf layout: + * esi + * ebx + * edi + * ebp + * esp + 4 + * return address + * signal mask indicator (0 - not saved, otherwise saved(GOT addr on PIC)) + * signal mask (if saved) + */ + #define __ASSEMBLY__ .text -.globl _setjmp -.type _setjmp, %function -_setjmp: + +.macro SETJMP_SAVE_REGS /* Store registers into jmpbuf */ - movl 4(%esp), %edx - movl %ebx, (%edx) - movl %esi, 4(%edx) - movl %edi, 8(%edx) - movl %ebp, 12(%edx) + leal 4(%esp), %ecx + movl (%ecx), %edx + movl %esi, (%edx) + movl %ebx, 4(%edx) + movl %edi, 8(%edx) + movl %ebp, 12(%edx) /* Store stack pointer pointing before return address */ - leal 4(%esp), %ecx - movl %ecx, 16(%edx) - /* Store jump address */ - leal (1f), %ecx - movl %ecx, 20(%edx) + movl %ecx, 16(%edx) /* Store return address */ - movl (%esp), %ecx - movl %ecx, 24(%edx) - /* Store result */ - movl $0, %eax - ret -1: - /* Jump point. Push return address to stack */ - pushl 24(%edx) + movl (%esp), %ecx + movl %ecx, 20(%edx) +.endm + + +.globl _setjmp +.type _setjmp, %function +.align 4 +_setjmp: + SETJMP_SAVE_REGS + /* Set no mask indicator */ + movl $0, 24(%edx) + /* Store result (0) */ + xorl %eax, %eax ret .size _setjmp, .-_setjmp .globl setjmp .type setjmp, %function +.align 4 setjmp: - /* Get signal mask */ - pushl $0 - pushl $0 - call signalMask - addl $8, %esp - /* Store registers into jmpbuf */ - movl 4(%esp), %edx - movl %ebx, (%edx) - movl %esi, 4(%edx) - movl %edi, 8(%edx) - movl %ebp, 12(%edx) - /* Store stack pointer pointing before return address */ - leal 4(%esp), %ecx - movl %ecx, 16(%edx) - /* Store jump address */ - leal (1f), %ecx - movl %ecx, 20(%edx) - /* Store return address */ - movl (%esp), %ecx - movl %ecx, 24(%edx) - /* Store signal mask */ - movl %eax, 28(%edx) - /* Store result */ - movl $0, %eax - ret -1: - /* Jump point. Push return address to stack */ - pushl 24(%edx) - /* Store longjmp return value */ - pushl %eax - /* Restore signal mask */ - movl 28(%edx), %ecx - pushl $0xffffffff - pushl %ecx + SETJMP_SAVE_REGS + /* Get signal mask */ +#if __pic__ == 0 + pushl $0 + pushl $0 call signalMask - addl $8, %esp - /* Restore longjmp return value */ - popl %eax + addl $8, %esp + /* Store signal mask indicator */ + movl $1, 24(%edx) +#else + pushl %ebx + + call .l1 +.l1: + popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+(.-.l1), %ebx + + pushl $0 + pushl $0 + call *signalMask@got(%ebx) + addl $8, %esp + /* Save GOT address as an indicator as it will not be 0 */ + movl %ebx, 24(%edx) + + popl %ebx +#endif + /* Store signal mask */ + movl %eax, 28(%edx) + /* Store result (0) */ + xorl %eax, %eax ret .size setjmp, .-setjmp .globl _longjmp .type _longjmp, %function +.align 4 _longjmp: - movl 4(%esp), %edx - movl 8(%esp), %eax - test %eax, %eax - jnz 1f - inc %eax + /* Since esi will be restored later it can be used as a scratch register */ + /* Using it allows to safely call signalMask */ + movl 4(%esp), %esi + /* Check mask indicator */ + /* Since ebx will be restored later it can be used as a scratch register */ + /* ebx as the mask indicator is a GOT address in PIC */ + movl 24(%esi), %ebx + test %ebx, %ebx + jz 1f + /* Restore signal mask */ + pushl $0xffffffff + pushl 28(%esi) + +#if __pic__ == 0 + call signalMask +#else + call *signalMask@got(%ebx) +#endif + + addl $8, %esp 1: + /* Get second argument */ + movl 8(%esp), %eax + /* _longjmp shall return 1 if 0 is provided as the second argument */ + movl $1, %ecx + test %eax, %eax + cmove %ecx, %eax /* Restore registers from jmpbuf */ - movl (%edx), %ebx - movl 4(%edx), %esi - movl 8(%edx), %edi - movl 12(%edx), %ebp - movl 16(%edx), %esp - /* Restore jump address */ - movl 20(%edx), %ecx - /* Jump */ - jmp *%ecx + movl 4(%esi), %ebx + movl 8(%esi), %edi + movl 12(%esi), %ebp + movl 16(%esi), %esp + /* Jump point. Push return address to stack */ + pushl 20(%esi) + /* At last restore esi */ + movl (%esi), %esi + ret .size _longjmp, .-_longjmp .globl sigsetjmp .type sigsetjmp, %function sigsetjmp: - /* Modify stack frame to skip this function when returning from setjmp */ - movl 8(%esp), %edx - movl 4(%esp), %ecx - movl (%esp), %eax - addl $8, %esp - pushl %ecx - pushl %eax - +.align 4 + movl 8(%esp), %edx /* Call proper setjmp */ - test %edx, %edx - jne setjmp - jmp _setjmp + test %edx, %edx + jz _setjmp + jmp setjmp .size sigsetjmp, .-sigsetjmp diff --git a/arch/ia32/signal.S b/arch/ia32/signal.S index 38131c99..7f60e0f0 100644 --- a/arch/ia32/signal.S +++ b/arch/ia32/signal.S @@ -5,8 +5,8 @@ * * Signal trampoline (ia32) * - * Copyright 2019 Phoenix Systems - * Author: Jan Sikorski + * Copyright 2019, 2023 Phoenix Systems + * Author: Jan Sikorski, Hubert Badocha * * This file is part of Phoenix-RTOS. * @@ -19,14 +19,29 @@ .globl _signal_trampoline .type _signal_trampoline, %function +.align 4 _signal_trampoline: /* Signal number on stack */ - call _signal_handler +#if __pic__ == 0 + call _signal_handler +#else + /* ebx will be restored by sigreturn */ + call .l1 +.l1: + popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+(.-.l1), %ebx - addl $4, %esp + call *_signal_handler@got(%ebx) +#endif + + addl $4, %esp /* Put old mask on stack */ - push %eax + pushl %eax /* cpu context *, eip, esp on stack */ - call sigreturn +#if __pic__ == 0 + call sigreturn +#else + call *sigreturn@got(%ebx) +#endif .size _signal_trampoline, .-_signal_trampoline From db5c6489852a7fff249e86e2e3551c802b9042e6 Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Tue, 23 Jan 2024 17:44:30 +0100 Subject: [PATCH 03/11] Makefile: generate shared library JIRA: RTOS-664 --- Makefile | 34 +++++++++++++++++------------- shared.mk | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 shared.mk diff --git a/Makefile b/Makefile index 30fdff7b..f6dc0150 100644 --- a/Makefile +++ b/Makefile @@ -15,9 +15,8 @@ include ../phoenix-rtos-build/Makefile.common SYSROOT := $(shell $(CC) $(CFLAGS) -print-sysroot) MULTILIB_DIR := $(shell $(CC) $(CFLAGS) -print-multi-directory) LIBC_INSTALL_DIR := $(SYSROOT)/lib/$(MULTILIB_DIR) -LIBC_INSTALL_NAMES := libc.a libm.a libg.a libpthread.a libubsan.a +LIBC_INSTALL_NAMES_A := libc.a libm.a libg.a libpthread.a libubsan.a HEADERS_INSTALL_DIR := $(SYSROOT)/usr/include -LIBNAME := libphoenix.a ifeq (,$(filter-out /,$(SYSROOT))) $(error SYSROOT is not supported by the toolchain. Use cross-toolchain to compile.) @@ -25,17 +24,10 @@ endif CFLAGS += -Iinclude -fno-builtin-malloc -ifeq ($(LIBPHOENIX_PIC), y) -CFLAGS += $(TARGET_PIC_FLAG) -endif - OBJS := # crt0.o should have all necessary initialization + call to main() CRT0_OBJS := $(PREFIX_O)crt0-common.o -LIB_TARGETS := $(PREFIX_A)libphoenix.a $(PREFIX_A)crt0.o - -all: $(LIB_TARGETS) ifneq (,$(findstring arm,$(TARGET_SUFF))) include arch/arm/Makefile @@ -69,7 +61,20 @@ include unistd/Makefile include wchar/Makefile include ubsan/Makefile -#include test/Makefile + +LIB_TARGETS := $(PREFIX_A)libphoenix.a $(PREFIX_A)crt0.o +INSTALL_TARGETS := install-headers install-libs + +ifeq ($(LIBPHOENIX_PIC), y) +CFLAGS += $(TARGET_PIC_FLAG) +ifeq ($(LIBPHOENIX_SHARED), y) +include shared.mk +endif +endif + + +all: $(LIB_TARGETS) + $(PREFIX_A)libphoenix.a: $(OBJS) $(ARCH) @@ -80,7 +85,8 @@ $(PREFIX_A)crt0.o: $(CRT0_OBJS) SRCHEADERS := $(shell find include -name \*.h) -install: install-headers install-libs + +install: $(INSTALL_TARGETS) install-headers: $(SRCHEADERS) @echo INSTALL "$(HEADERS_INSTALL_DIR)/*"; \ @@ -89,16 +95,16 @@ install-headers: $(SRCHEADERS) # TODO: remove `rm crt0.o` when we will be sure it's not a symlink to libphoenix.a anymore install-libs: $(LIB_TARGETS) - @echo INSTALL "$(LIBC_INSTALL_DIR)/*"; \ + $(SIL)echo INSTALL "$(LIBC_INSTALL_DIR)/*"; \ mkdir -p "$(LIBC_INSTALL_DIR)"; \ rm -rf "$(LIBC_INSTALL_DIR)/crt0.o"; \ cp -a $^ "$(LIBC_INSTALL_DIR)"; \ (cd $(LIBC_INSTALL_DIR) && \ - for lib in $(LIBC_INSTALL_NAMES); do \ + for lib in $(LIBC_INSTALL_NAMES_A); do \ if [ ! -e "$$lib" ]; then \ ln -sf "libphoenix.a" "$$lib"; \ fi \ - done) + done) .PHONY: clean install install-headers install-libs clean: diff --git a/shared.mk b/shared.mk new file mode 100644 index 00000000..3a0da63c --- /dev/null +++ b/shared.mk @@ -0,0 +1,62 @@ +# +# Makefile for compiling libphoenix as shared lib +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +# FIXME: In shared versions each library should only have needed parts of libphoenix. +LIBC_INSTALL_NAMES_SO := libc.so libm.so libpthread.so libubsan.so + +# TODO: automatically get the version +VERSION=3.2.1 +MAJOR_VERSION=$(word 1, $(subst ., ,$(VERSION))) + +LIBNAME=libphoenix.so +SONAME=$(LIBNAME).$(MAJOR_VERSION) +REALNAME=$(LIBNAME).$(VERSION) + +LIB_TARGETS += $(PREFIX_SO)$(REALNAME) +INSTALL_TARGETS += install-shared + + +SHARED_LDFLAGS := -nolibc +SHARED_LDFLAGS += -z initfirst # Tell dynamic linker to init libphoenix first. +SHARED_LDFLAGS += -static-libgcc # Use static libgcc to prevent each program from including it separately. +SHARED_LDFLAGS += $(TARGET_PIC_FLAG) -shared # Common shared lib flags +SHARED_LDFLAGS += -z text # Tell linker to abort if .text contains relocations +SHARED_LDFLAGS += $(LDFLAGS_PREFIX)-soname,$(SONAME) + + +$(PREFIX_SO)$(REALNAME): LDFLAGS:=$(LDFLAGS) $(SHARED_LDFLAGS) + +$(PREFIX_SO)$(REALNAME): $(OBJS) + $(LINK) + + +LOCAL_INSTALL_PATH := $(or $(LOCAL_INSTALL_PATH),$(DEFAULT_INSTALL_PATH_SO)) + +install-shared: $(PREFIX_SO)$(REALNAME) $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME) install-shared-libs + +$(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME): $(PREFIX_SO)$(REALNAME) + $(INSTALL_FS) + +install-shared-libs: $(PREFIX_SO)$(REALNAME) install-libs + $(SIL)(cd $(LIBC_INSTALL_DIR) && \ + for lib in $(LIBC_INSTALL_NAMES_SO); do \ + if [ ! -e "$$lib.$(VERSION)" ]; then \ + ln -sf "$(REALNAME)" "$$lib.$(VERSION)"; \ + fi \ + done && \ + for lib in $(LIBC_INSTALL_NAMES_SO) $(LIBNAME); do \ + if [ ! -e "$$lib.$(MAJOR_VERSION)" ]; then \ + ln -sf "$$lib.$(VERSION)" "$$lib.$(MAJOR_VERSION)"; \ + fi \ + done && \ + for lib in $(LIBC_INSTALL_NAMES_SO) $(LIBNAME); do \ + if [ ! -e "$$lib" ]; then \ + ln -sf "$$lib.$(MAJOR_VERSION)" "$$lib"; \ + fi \ + done \ + ) From 4c14d66a4bb198638273a199986cf95bd2d12e55 Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Fri, 16 Aug 2024 17:12:57 +0200 Subject: [PATCH 04/11] dlfcn: create header and stub definitions JIRA: RTOS-664 --- Makefile | 1 + include/dlfcn.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ rtld/Makefile | 8 ++++++++ rtld/stubs.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 include/dlfcn.h create mode 100644 rtld/Makefile create mode 100644 rtld/stubs.c diff --git a/Makefile b/Makefile index f6dc0150..dfdb032a 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ include posix/Makefile include phoenix/Makefile include pthread/Makefile include regex/Makefile +include rtld/Makefile include signal/Makefile include stdio/Makefile include stdlib/Makefile diff --git a/include/dlfcn.h b/include/dlfcn.h new file mode 100644 index 00000000..808efd31 --- /dev/null +++ b/include/dlfcn.h @@ -0,0 +1,51 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * dlfcn.h + * + * Copyright 2024 Phoenix Systems + * Author: Hubert Badocha + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _LIBPHOENIX_DLFCN_H_ +#define _LIBPHOENIX_DLFCN_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_GLOBAL 0x100 +#define RTLD_LOCAL 0x200 + + +typedef struct { + const char *dli_fname; /* Pathname of mapped object file. */ + void *dli_fbase; /* Base of mapped address range. */ + const char *dli_sname; /* Symbol name or null pointer. */ + void *dli_saddr; /* Symbol address or null pointer. */ +} Dl_info_t; + + +int dladdr(const void *restrict, Dl_info_t *restrict); +int dlclose(void *); +char *dlerror(void); +void *dlopen(const char *, int); +void *dlsym(void *restrict, const char *restrict); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/rtld/Makefile b/rtld/Makefile new file mode 100644 index 00000000..719e9c25 --- /dev/null +++ b/rtld/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for libphoenix/rtld +# +# Copyright 2024 Phoenix Systems +# Author: Hubert Badocha +# + +OBJS += $(addprefix $(PREFIX_O)rtld/, stubs.o) diff --git a/rtld/stubs.c b/rtld/stubs.c new file mode 100644 index 00000000..7d76c406 --- /dev/null +++ b/rtld/stubs.c @@ -0,0 +1,52 @@ +/* + * Phoenix-RTOS + * + * libphoenix/rtld + * + * stubs.c + * + * Copyright 2024 Phoenix Systems + * Author: Hubert Badocha + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include + + +/* As dynamic linker is not added as a NEEDED dependency in libphoenix, stub implementation are required. + * They are overridden by dynamic linkers functions in runtime. */ + +__attribute__((weak)) int dladdr(const void *restrict a, Dl_info_t *restrict b) +{ + return 0; +} + + +__attribute__((weak)) int dlclose(void *a) +{ + return -1; +} + + +__attribute__((weak)) char *dlerror(void) +{ + return "dlfcn: not supported in statically linked binaries"; +} + + +__attribute__((weak)) void *dlopen(const char *a, int b) +{ + return NULL; +} + + +__attribute__((weak)) void *dlsym(void *restrict a, const char *restrict b) +{ + return NULL; +} From 1a1ee2521a523b6893f396bae4e81ae30ebf98e1 Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Mon, 22 Jan 2024 16:47:28 +0100 Subject: [PATCH 05/11] tls: add dynamic linker TLS support JIRA: RTOS-664 --- Makefile | 1 + crt0-common.c | 5 +++++ errno/errno.c | 5 ++++- include/arch/armv7a/arch.h | 1 + include/arch/riscv64/arch.h | 1 + include/sys/threads.h | 9 ++++++-- rtld/stubs.c | 18 ++++++++++++++++ sys/threads.c | 42 +++++++++++++++++++++++++++++++++++++ 8 files changed, 79 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index dfdb032a..40738c9a 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,7 @@ INSTALL_TARGETS := install-headers install-libs ifeq ($(LIBPHOENIX_PIC), y) CFLAGS += $(TARGET_PIC_FLAG) ifeq ($(LIBPHOENIX_SHARED), y) +CPPFLAGS += -DLIBPHOENIX_SHARED include shared.mk endif endif diff --git a/crt0-common.c b/crt0-common.c index 7842f9e6..61d9af45 100644 --- a/crt0-common.c +++ b/crt0-common.c @@ -72,6 +72,8 @@ extern int main(int argc, char **argv); char **environ; const char *argv_progname; +/* TLS cannot be used before initialized by dynamic linker in dynamically linked binaries. */ +int can_use_tls; __attribute__((noreturn)) void _startc(void (*cleanup)(void), int argc, char **argv, char **env) @@ -81,6 +83,9 @@ __attribute__((noreturn)) void _startc(void (*cleanup)(void), int argc, char **a _libc_init(); + /* At this point TLS is setup, as dynamic linker calls _startc after dealing with TLS. */ + can_use_tls = 1; + /* cleanup function is not NULL when the dynamic linker is used */ if (cleanup != NULL) { atexit(cleanup); diff --git a/errno/errno.c b/errno/errno.c index fccd3468..28345540 100644 --- a/errno/errno.c +++ b/errno/errno.c @@ -23,6 +23,9 @@ static __thread int __errno_tls; +extern int can_use_tls; +static int errno_single = 0; + #else static int errno_global; @@ -58,7 +61,7 @@ int *__errno_location(void) return &errno_global; #else - return &__errno_tls; + return (can_use_tls == 0) ? &errno_single : &__errno_tls; #endif } diff --git a/include/arch/armv7a/arch.h b/include/arch/armv7a/arch.h index c35b31c0..44969c87 100644 --- a/include/arch/armv7a/arch.h +++ b/include/arch/armv7a/arch.h @@ -46,5 +46,6 @@ #define SIZE_PAGE _Pragma("GCC warning \"'SIZE_PAGE' is deprecated. Use _PAGE_SIZE from arch.h or PAGE_SIZE from limits.h (POSIX only)\"") _PAGE_SIZE #define __LIBPHOENIX_ARCH_TLS_SUPPORTED +#define __LIBPHOENIX_ARCH_HAVE__TLS_GET_ADDR #endif diff --git a/include/arch/riscv64/arch.h b/include/arch/riscv64/arch.h index 98e70814..daed33f4 100644 --- a/include/arch/riscv64/arch.h +++ b/include/arch/riscv64/arch.h @@ -52,5 +52,6 @@ static inline float __ieee754_sqrtf(float x) #define SIZE_PAGE _Pragma("GCC warning \"'SIZE_PAGE' is deprecated. Use _PAGE_SIZE from arch.h or PAGE_SIZE from limits.h (POSIX only)\"") _PAGE_SIZE #define __LIBPHOENIX_ARCH_TLS_SUPPORTED +#define __LIBPHOENIX_ARCH_HAVE__TLS_GET_ADDR #endif diff --git a/include/sys/threads.h b/include/sys/threads.h index 04d47197..49989481 100644 --- a/include/sys/threads.h +++ b/include/sys/threads.h @@ -70,11 +70,16 @@ extern int spawnSyspage(const char *imap, const char *dmap, const char *name, ch extern int threadJoin(int tid, time_t timeout); +extern int beginthreadexsvc(void (*start)(void *), unsigned int priority, void *stack, unsigned int stacksz, void *arg, handle_t *id); + + +__attribute__((noreturn)) extern void endthreadsvc(void); + + extern int beginthreadex(void (*start)(void *), unsigned int priority, void *stack, unsigned int stacksz, void *arg, handle_t *id); -__attribute__((noreturn)) -extern void endthread(void); +__attribute__((noreturn)) extern void endthread(void); static inline int beginthread(void (*start)(void *), unsigned int priority, void *stack, unsigned int stacksz, void *arg) diff --git a/rtld/stubs.c b/rtld/stubs.c index 7d76c406..96a017bb 100644 --- a/rtld/stubs.c +++ b/rtld/stubs.c @@ -50,3 +50,21 @@ __attribute__((weak)) void *dlsym(void *restrict a, const char *restrict b) { return NULL; } + + +/* Allow override on platforms requiring __tls_get_addr in PIC compiled libraries(eg. RISC-V, ARM). */ +#ifndef __LIBPHOENIX_ARCH_HAVE__TLS_GET_ADDR + +/* Stub __tls_get_addr implementations. */ +__attribute__((weak)) void *__tls_get_addr(void *d) +{ + abort(); +} + + +__attribute__((weak)) void *___tls_get_addr(void *d) +{ + abort(); +} + +#endif diff --git a/sys/threads.c b/sys/threads.c index b3545325..746d22cd 100644 --- a/sys/threads.c +++ b/sys/threads.c @@ -17,6 +17,48 @@ #include +#include +#include + +/* Provide stub definition of tls managing functions for statically linked programs. */ + +static void _libphoenix_stub(void) +{ +} + +extern void __attribute__((weak, alias("_libphoenix_stub"))) _rtld_tls_free_curr(void); +extern void __attribute__((weak, alias("_libphoenix_stub"))) _rtld_tls_allocate_curr(void); + + +/* FIXME: Hack to provide tls support in dynamically loaded binaries. */ +void beginthreadex_wrapper(void *arg) +{ + _rtld_tls_allocate_curr(); + + void *(*start)(void *) = ((void **)arg)[0]; + void *startArg = ((void **)arg)[1]; + + free(arg); + + start(startArg); +} + +int beginthreadex(void (*start)(void *), unsigned int priority, void *stack, unsigned int stacksz, void *arg, handle_t *id) +{ + void **startAndArg = (void **)malloc(sizeof(void *) * 2); + startAndArg[0] = start; + startAndArg[1] = arg; + return beginthreadexsvc(beginthreadex_wrapper, priority, stack, stacksz, startAndArg, id); +} + + +__attribute__((noreturn)) void endthread(void) +{ + _rtld_tls_free_curr(); + endthreadsvc(); +} + + int mutexCreate(handle_t *h) { static const struct lockAttr defaultAttr = { .type = PH_LOCK_NORMAL }; From e7db14ce90a1788b82507ce2bc243982cf3edc3f Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Tue, 27 Aug 2024 17:52:12 +0200 Subject: [PATCH 06/11] ld.elf_so: add support for __cxa_thread_atexit_impl JIRA: RTOS-664 --- stdlib/Makefile | 2 +- stdlib/atexit.c | 5 ++ stdlib/cxa_thread_atexit.c | 130 +++++++++++++++++++++++++++++++++++++ sys/threads.c | 4 ++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 stdlib/cxa_thread_atexit.c diff --git a/stdlib/Makefile b/stdlib/Makefile index 0d9fbf1d..d1c1e528 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -4,4 +4,4 @@ # Copyright 2018, 2019, 2020 Phoenix Systems # -OBJS += $(addprefix $(PREFIX_O)stdlib/, abort.o bsearch.o div.o exit.o mktemp.o qsort.o random.o strtoul.o atexit.o env.o malloc_dl.o pty.o rand.o strtod.o strtoull.o) +OBJS += $(addprefix $(PREFIX_O)stdlib/, abort.o bsearch.o div.o exit.o mktemp.o qsort.o random.o strtoul.o atexit.o env.o malloc_dl.o pty.o rand.o strtod.o strtoull.o cxa_thread_atexit.o) diff --git a/stdlib/atexit.c b/stdlib/atexit.c index 6e8b151a..2d16e3c2 100644 --- a/stdlib/atexit.c +++ b/stdlib/atexit.c @@ -45,6 +45,9 @@ static struct { } atexit_common = { .head = &((struct atexit_node) {}) }; +extern void __cxa_thread_atexit_init(void); + + /* Initialise atexit_common structure before main */ void _atexit_init(void) { @@ -52,6 +55,8 @@ void _atexit_init(void) memset(atexit_common.head, 0, sizeof(struct atexit_node)); atexit_common.idx = 0; atexit_common.newestNode = atexit_common.head; + + __cxa_thread_atexit_init(); } diff --git a/stdlib/cxa_thread_atexit.c b/stdlib/cxa_thread_atexit.c new file mode 100644 index 00000000..c98cf35f --- /dev/null +++ b/stdlib/cxa_thread_atexit.c @@ -0,0 +1,130 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * atexit.c + * + * Copyright 2019 2022 Phoenix Systems + * Author: Kamil Amanowicz, Dawid Szpejna + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include + + +void __cxa_thread_atexit_init(void); +void __cxa_thread_atexit_run(void); +int __cxa_thread_atexit_impl(void (*)(void *), void *, void *); + + +#ifdef __LIBPHOENIX_ARCH_TLS_SUPPORTED + + +void __libc__dl_cxa_refcount(void *addr, ssize_t delta) +{ + /* Do nothing in static lib */ + (void)addr; + (void)delta; +} + + +extern void __dl_cxa_refcount(void *, ssize_t) __attribute__((weak, alias("__libc__dl_cxa_refcount"))); + + +struct __cxa_atexit_node { + struct __cxa_atexit_node *prev; + void (*dtor)(void *); + void *obj; + void *handle; +}; + + +static __thread struct __cxa_atexit_node *__cxa_thread_atexit_head; + + +extern int can_use_tls; + + +void __cxa_thread_atexit_init(void) +{ + /* Special case for dynamic linker exit */ + if (can_use_tls != 0) { + atexit(__cxa_thread_atexit_run); + } +} + + +void __cxa_thread_atexit_run(void) +{ + while (__cxa_thread_atexit_head != NULL) { + struct __cxa_atexit_node *last = __cxa_thread_atexit_head; + + __cxa_thread_atexit_head->dtor(__cxa_thread_atexit_head->obj); + __cxa_thread_atexit_head = __cxa_thread_atexit_head->prev; + + if (last->handle != NULL) { + __dl_cxa_refcount(last->handle, -1); + } + + free(last); + } +} + + +/* C++ thread-local destructor handler */ +int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj, void *handle) +{ + struct __cxa_atexit_node *node = malloc(sizeof(struct __cxa_atexit_node)); + + if (node == NULL) { + return -1; + } + + node->dtor = dtor; + node->obj = obj; + node->handle = handle; + node->prev = __cxa_thread_atexit_head; + + if (node->handle != NULL) { + __dl_cxa_refcount(node->handle, 1); + } + + __cxa_thread_atexit_head = node; + + return 0; +} + + +#else + + +void __cxa_thread_atexit_init(void) +{ + /* Nothing to do */ +} + + +void __cxa_thread_atexit_run(void) +{ + /* Nothing to do */ +} + + +/* NOTE: no support for __cxa_thread_atexit_impl on platforms not supporting TLS. */ +int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj, void *handle) +{ + (void)dtor; + (void)obj; + (void)handle; + + abort(); +} + + +#endif diff --git a/sys/threads.c b/sys/threads.c index 746d22cd..a945f872 100644 --- a/sys/threads.c +++ b/sys/threads.c @@ -52,8 +52,12 @@ int beginthreadex(void (*start)(void *), unsigned int priority, void *stack, uns } +void __cxa_thread_atexit_run(void); + + __attribute__((noreturn)) void endthread(void) { + __cxa_thread_atexit_run(); _rtld_tls_free_curr(); endthreadsvc(); } From cd168a3201fb9b1bcdedc5a4a00572a7169ffb2d Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Tue, 27 Aug 2024 17:58:39 +0200 Subject: [PATCH 07/11] init: declare _libc_init as constructor This allows constructor handling mechanism in dynamic linker. JIRA: RTOS-664 --- misc/init.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/misc/init.c b/misc/init.c index eba32b43..4daa4255 100644 --- a/misc/init.c +++ b/misc/init.c @@ -24,8 +24,21 @@ extern void _init_array(void); extern void _pthread_init(void); -void _libc_init(void) +static int _libc_initialized; + + +/* _libc_init is called twice once explicitly in crt0 and once during constructor handling. + * If libc is linked statically first it is called explicitly and then during constructor handling. + * If libc is linked dynamically first it is called by the constructor handling mechanism in dynamic linker, + * to allow constructors from other objects to call libc functions. + */ +__attribute__((constructor)) void _libc_init(void) { + if (_libc_initialized != 0) { + return; + } + _libc_initialized = 1; + _atexit_init(); _errno_init(); _malloc_init(); From 71d156dfc93fe1d7881549e331547f88d6bf667b Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Tue, 27 Aug 2024 18:01:38 +0200 Subject: [PATCH 08/11] shared.mk: install toolchain provided dynamic libraries JIRA: RTOS-664 --- shared.mk | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/shared.mk b/shared.mk index 3a0da63c..619ca9b6 100644 --- a/shared.mk +++ b/shared.mk @@ -39,6 +39,7 @@ LOCAL_INSTALL_PATH := $(or $(LOCAL_INSTALL_PATH),$(DEFAULT_INSTALL_PATH_SO)) install-shared: $(PREFIX_SO)$(REALNAME) $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME) install-shared-libs + $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME): $(PREFIX_SO)$(REALNAME) $(INSTALL_FS) @@ -60,3 +61,33 @@ install-shared-libs: $(PREFIX_SO)$(REALNAME) install-libs fi \ done \ ) + +# During toolchain build shared toolchain libs are not yet ready. +ifneq ($(TOOLCHAIN_BUILD),y) + +install-shared: rootfs-install-shared-toolchain-libs install-shared-toolchain-libs + +TOOLCHAIN_LIBS_PATH := $(shell $(CC) --print-sysroot)/lib/$(MULTILIB_DIR) + +rootfs-install-shared-toolchain-libs install-shared-toolchain-libs: TOOLCHAIN_LIBS_PATH := $(TOOLCHAIN_LIBS_PATH) + + +# libstdc++ version differs depending on compilers version. +LIBSTDCXX=$(shell find $(TOOLCHAIN_LIBS_PATH) -regex '.*/libstdc\+\+\.so\.[0-9]+\.[0-9]+' -exec basename {} \; | head -n 1) +LIBSTDCXX_MAJOR=$(shell echo $(LIBSTDCXX) | sed "s/\.[0-9]\+$//") + + +rootfs-install-shared-toolchain-libs: $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME) + $(SIL)cp $(TOOLCHAIN_LIBS_PATH)/$(LIBSTDCXX) $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH) + $(SIL)cp $(TOOLCHAIN_LIBS_PATH)/libgcc_s.so.1 $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH) + + +install-shared-toolchain-libs: install-shared-libs + $(SIL)ln -sf $(TOOLCHAIN_LIBS_PATH)/$(LIBSTDCXX) $(LIBC_INSTALL_DIR) + $(SIL)ln -sf $(TOOLCHAIN_LIBS_PATH)/libgcc_s.so.1 $(LIBC_INSTALL_DIR) + $(SIL)(cd $(LIBC_INSTALL_DIR) && \ + ln -sf $(LIBSTDCXX) $(LIBSTDCXX_MAJOR) && ln -sf $(LIBSTDCXX) libstdc++.so && \ + ln -sf libgcc_s.so.1 libgcc_s.so \ + ) + +endif From 3edaf745581767f8e5486ca65a6878541d04bf03 Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Tue, 10 Sep 2024 13:55:43 +0200 Subject: [PATCH 09/11] shared.mk: strip shared libs in fs JIRA: RTOS-664 --- shared.mk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shared.mk b/shared.mk index 619ca9b6..3a44cb30 100644 --- a/shared.mk +++ b/shared.mk @@ -39,9 +39,10 @@ LOCAL_INSTALL_PATH := $(or $(LOCAL_INSTALL_PATH),$(DEFAULT_INSTALL_PATH_SO)) install-shared: $(PREFIX_SO)$(REALNAME) $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME) install-shared-libs - +# Install and strip binary $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME): $(PREFIX_SO)$(REALNAME) $(INSTALL_FS) + $(STRIP) $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME) install-shared-libs: $(PREFIX_SO)$(REALNAME) install-libs $(SIL)(cd $(LIBC_INSTALL_DIR) && \ @@ -78,8 +79,8 @@ LIBSTDCXX_MAJOR=$(shell echo $(LIBSTDCXX) | sed "s/\.[0-9]\+$//") rootfs-install-shared-toolchain-libs: $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(REALNAME) - $(SIL)cp $(TOOLCHAIN_LIBS_PATH)/$(LIBSTDCXX) $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH) - $(SIL)cp $(TOOLCHAIN_LIBS_PATH)/libgcc_s.so.1 $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH) + $(SIL)$(STRIP) $(TOOLCHAIN_LIBS_PATH)/$(LIBSTDCXX) -o $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/$(LIBSTDCXX) + $(SIL)$(STRIP) $(TOOLCHAIN_LIBS_PATH)/libgcc_s.so.1 -o $(PREFIX_ROOTFS)$(LOCAL_INSTALL_PATH)/libgcc_s.so.1 install-shared-toolchain-libs: install-shared-libs From 427252a0352f298625d10f9ef0b17d64a94943a8 Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Wed, 11 Sep 2024 14:15:52 +0200 Subject: [PATCH 10/11] arch/riscv64: respect PIC in asm JIRA: RTOS-664 --- arch/riscv64/jmp.S | 8 ++++++++ arch/riscv64/syscalls.S | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/arch/riscv64/jmp.S b/arch/riscv64/jmp.S index 1537a4eb..b2b96cfb 100644 --- a/arch/riscv64/jmp.S +++ b/arch/riscv64/jmp.S @@ -30,7 +30,11 @@ .type _setjmp, %function _setjmp: mv a1, zero +#if __pic__ == 0 j sigsetjmp +#else + tail sigsetjmp +#endif .size _setjmp, .-_setjmp @@ -38,7 +42,11 @@ _setjmp: .type setjmp, %function setjmp: li a1, 1 +#if __pic__ == 0 j sigsetjmp +#else + tail sigsetjmp +#endif .size setjmp, .-setjmp diff --git a/arch/riscv64/syscalls.S b/arch/riscv64/syscalls.S index c518695e..99a5c621 100644 --- a/arch/riscv64/syscalls.S +++ b/arch/riscv64/syscalls.S @@ -54,7 +54,11 @@ sym: \ .globl vfork; .type vfork, %function; vfork: +#if __pic__ == 0 j vforksvc +#else + tail vforksvc +#endif .size vfork, .-vfork From 42d20ddf20357df9c45241765ddeb94a892c145a Mon Sep 17 00:00:00 2001 From: Hubert Badocha Date: Thu, 12 Sep 2024 12:41:56 +0200 Subject: [PATCH 11/11] sparc: make asm PIC friendly JIRA: RTOS-664 --- arch/sparcv8leon/jmp.S | 13 ++++++++++++- arch/sparcv8leon/syscalls.S | 6 +----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/sparcv8leon/jmp.S b/arch/sparcv8leon/jmp.S index 80d9481c..69bcfe83 100644 --- a/arch/sparcv8leon/jmp.S +++ b/arch/sparcv8leon/jmp.S @@ -112,8 +112,19 @@ _longjmp: .type sigsetjmp, #function sigsetjmp: cmp %o1, 0 - bne setjmp + bne 1f nop +#if __pic__ == 0 ba _setjmp +#else + jmp _setjmp +#endif + nop +1: +#if __pic__ == 0 + ba setjmp +#else + jmp setjmp +#endif nop .size sigsetjmp, .-sigsetjmp diff --git a/arch/sparcv8leon/syscalls.S b/arch/sparcv8leon/syscalls.S index 136dff11..67d61c27 100644 --- a/arch/sparcv8leon/syscalls.S +++ b/arch/sparcv8leon/syscalls.S @@ -35,11 +35,7 @@ sym: \ .globl vfork -.type vfork, #function -vfork: - ba vforksvc - nop -.size vfork, .-vfork +vfork = vforksvc #define SYSCALLS_LIBC(name) \