diff options
| author | John "Lameguy" Wilbert Villamor <lameguy64@gmail.com> | 2021-08-31 13:23:20 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-31 13:23:20 +0800 |
| commit | ffa679d4d24b891cb59aba10946368f2ec00c391 (patch) | |
| tree | 0cf6061915ebf48acdedf6d77b0c1b76eec5b8c3 /libpsn00b/libc | |
| parent | 317dc2b91d3afcdbaddb035f38611d12af161970 (diff) | |
| parent | f2fc18f82dd7900465d6ab3ae2080726d5589d39 (diff) | |
| download | psn00bsdk-ffa679d4d24b891cb59aba10946368f2ec00c391.tar.gz | |
Merge pull request #36 from spicyjpeg/dynlink
Dynamic linker, gp-relative addressing, ldscripts and more
Diffstat (limited to 'libpsn00b/libc')
| -rw-r--r-- | libpsn00b/libc/_mem_init.s | 20 | ||||
| -rw-r--r-- | libpsn00b/libc/makefile | 59 | ||||
| -rw-r--r-- | libpsn00b/libc/malloc.s | 11 | ||||
| -rw-r--r-- | libpsn00b/libc/start.c | 181 |
4 files changed, 136 insertions, 135 deletions
diff --git a/libpsn00b/libc/_mem_init.s b/libpsn00b/libc/_mem_init.s deleted file mode 100644 index 672ac2f..0000000 --- a/libpsn00b/libc/_mem_init.s +++ /dev/null @@ -1,20 +0,0 @@ -.set noreorder - -.global _mem_init -.type _mem_init, @function -_mem_init: - -.section .text - -_mem_init: - la $a0, __bss_start - la $a1, _end -.Lclear_bss: - sb $0 , 0($a0) - blt $a0, $a1, .Lclear_bss - addiu $a0, 1 - la $a0, _end+4 # Initialize heap for malloc (does not use BIOS maalloc) - li $a1, 1572864 # Allocate 1.5MB at end of bss - j InitHeap - nop -
\ No newline at end of file diff --git a/libpsn00b/libc/makefile b/libpsn00b/libc/makefile index a515ad5..bb3a687 100644 --- a/libpsn00b/libc/makefile +++ b/libpsn00b/libc/makefile @@ -1,54 +1,61 @@ -# Run using make (Linux) or gmake (BSD) +# PSn00bSDK library makefile # Part of the PSn00bSDK Project -# 2019 - 2020 Lameguy64 / Meido-Tek Productions +# 2019 - 2021 Lameguy64 / Meido-Tek Productions -include ../../template/psn00bsdk-setup.mk +## Settings -TARGET = libc.a +PSN00BSDK_LIBS ?= .. -INCLUDE = -I../include +include ../../psn00bsdk-setup.mk -CFLAGS = -g -O2 -msoft-float -fno-builtin -fdata-sections \ - -ffunction-sections -Wa,--strip-local-absolute -AFLAGS = -g -msoft-float -Wa,-strip-local-absolute +# Project target name +TARGET = libc.a -CFILES = $(notdir $(wildcard ./*.c)) -CXXFILES = $(notdir $(wildcard ./*.cxx)) -AFILES = $(notdir $(wildcard ./*.s)) +## Files -OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CXXFILES:.cxx=.o) \ - $(AFILES:.s=.o)) +# Searches for C, C++ and S (assembler) files in local directory +CFILES = $(notdir $(wildcard *.c)) +CXXFILES= $(notdir $(wildcard *.cxx)) +AFILES = $(notdir $(wildcard *.s)) -ifndef PSN00BSDK_LIBS +# Create names for object files +OFILES = $(addprefix build/,$(CFILES:.c=.o)) \ + $(addprefix build/,$(CXXFILES:.cxx=.o)) \ + $(addprefix build/,$(AFILES:.s=.o)) -PSN00BSDK_LIBS = .. +# Project specific includes and libraries +# (use -I for include dirs, -L for library dirs, -l for static libraries) +INCLUDE += +LIBDIRS += +LIBS += -endif +## Build rules -all: $(TARGET) +all: build/$(TARGET) -$(TARGET): $(OFILES) - cp $(GCC_BASE)/lib/gcc/$(PREFIX)/$(GCC_VERSION)/libgcc.a ./$(TARGET) - $(AR) r $(TARGET) $(OFILES) - $(RANLIB) $(TARGET) +build/$(TARGET): $(OFILES) + @mkdir -p $(dir $@) + # "Import" libgcc's contents + cp $(GCC_BASE)/lib/gcc/$(PREFIX)/$(GCC_VERSION)/libgcc.a ./$@ + $(AR) rs $@ $(OFILES) build/%.o: %.c @mkdir -p $(dir $@) - $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + $(CC) $(CFLAGS_LIB) $(INCLUDE) -c $< -o $@ build/%.o: %.cxx @mkdir -p $(dir $@) - $(CXX) $(CFLAGS) $(INCLUDE) -c $< -o $@ + $(CXX) $(CPPFLAGS_LIB) $(INCLUDE) -c $< -o $@ build/%.o: %.s @mkdir -p $(dir $@) - $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + $(CC) $(AFLAGS_LIB) $(INCLUDE) -c $< -o $@ install: ifneq ($(PSN00BSDK_LIBS), "..") @mkdir -p $(PSN00BSDK_LIBS) endif - cp $(TARGET) $(PSN00BSDK_LIBS)/$(TARGET) + cp build/$(TARGET) $(PSN00BSDK_LIBS)/$(TARGET) clean: - rm -Rf build $(TARGET) + rm -rf build diff --git a/libpsn00b/libc/malloc.s b/libpsn00b/libc/malloc.s index 90f9bd4..e441bbe 100644 --- a/libpsn00b/libc/malloc.s +++ b/libpsn00b/libc/malloc.s @@ -1,5 +1,10 @@ # Custom first-fit malloc routines by Lameguy64 # Part of the PSn00bSDK Project +# +# NOTE: there reportedly is a GCC bug which messes up .weak functions written +# in assembly if LTO is enabled. I haven't tested but, according to the +# internet, this bug has never been fixed. +# https://gcc.gnu.org/legacy-ml/gcc-help/2019-10/msg00092.html .set noreorder @@ -10,7 +15,6 @@ .section .text - # Stupid small function just to get bss end # due to GCC insisting externs to be gp relative .global GetBSSend @@ -27,6 +31,7 @@ GetBSSend: # .global InitHeap .type InitHeap, @function +.weak InitHeap InitHeap: la $v0, _malloc_addr sw $a0, 0($v0) @@ -43,6 +48,7 @@ InitHeap: # a0 - Size of memory heap in bytes .global SetHeapSize .type SetHeapSize, @function +.weak SetHeapSize SetHeapSize: la $v1, _malloc_size lw $v0, 0($v1) @@ -55,6 +61,7 @@ SetHeapSize: # .global malloc .type malloc, @function +.weak malloc malloc: addiu $a0, 3 # Round size to a multiple of 4 srl $a0, 2 @@ -170,6 +177,7 @@ malloc: # .global calloc .type calloc, @function +.weak calloc calloc: mult $a0, $a1 addiu $sp, -4 @@ -199,6 +207,7 @@ calloc: # .global free .type free, @function +.weak free free: addiu $a0, -ND_HSIZ diff --git a/libpsn00b/libc/start.c b/libpsn00b/libc/start.c index 354ebb9..c5872df 100644 --- a/libpsn00b/libc/start.c +++ b/libpsn00b/libc/start.c @@ -1,110 +1,115 @@ -#include <stdio.h> +/* + * PSn00bSDK startup code + * (C) 2021 Lameguy64, spicyjpeg - MPL licensed + */ + +#include <sys/types.h> #include <string.h> #include <malloc.h> -#define load_gp() __asm__ volatile ( \ - "la $gp, _gp;" ) - -extern int _end; -extern int main(int argc, const char* argv[]); +#define KERNEL_ARG_STRING ((const char *) 0x80000180) +#define KERNEL_RETURN_VALUE ((volatile int *) 0x8000dffc) -void _mem_init(void); +/* Argument parsing */ -int __argc; +int32_t __argc; const char **__argv; -static const char *_arg_ptrs_int[8]; -static char _arg_buff[132]; +#define ARGC_MAX 16 -static void _call_global_ctors(void) -{ - extern void (*__CTOR_LIST__[])(void); +static const char *_argv_buffer[ARGC_MAX]; +static char _arg_string_buffer[132]; - // Constructors are called in reverse order of the list - int i; - for (i = (int)__CTOR_LIST__[0]; i >= 1; i--) { - // Each function handles one or more destructor (within - // file scope) - __CTOR_LIST__[i](); +static void _parse_kernel_args() { + // Copy the argument string from kernel memory into a private buffer (which + // won't be cleared or deallocated) and trim it at the first newline. + memset(_arg_string_buffer, 0, 132); + strncpy(_arg_string_buffer, KERNEL_ARG_STRING, 128); + + for (char *ptr = _arg_string_buffer; *ptr; ptr++) { + if ((*ptr == '\r') || (*ptr == '\n')) { + *ptr = 0; + break; + } } -} -static void _call_global_dtors(void) -{ - extern void (*__DTOR_LIST__[])(void); + __argv = _argv_buffer; + for (__argc = 0; __argc < ARGC_MAX; __argc++) { + const char *ptr; + if (!__argc) + ptr = strtok(_arg_string_buffer, " "); + else + ptr = strtok(0, " "); - /* Destructors in forward order */ - int i; - for (i = 0; i < (int)__DTOR_LIST__[0]; i++) { - /* Each function handles one or more destructor (within - * file scope) */ - __DTOR_LIST__[i + 1](); + _argv_buffer[__argc] = ptr; + if (!ptr) + break; } } -void _parse_args( int argc, const char *args[] ) -{ - int i; - char *c,*s; - - memset( _arg_buff, 0, 132 ); - - if( !args ) - { - // Use arguments from kernel if args is NULL - strncpy( _arg_buff, (char*)0x180, 128 ); - - // Clean-up args froom stray line-ends - while( ( c = strrchr( _arg_buff, '\r' ) ) || - ( c = strrchr( _arg_buff, '\n' ) ) ) - *c = 0; - } - else - { - __argc = argc; - __argv = args; - return; - } - - __argc = 0; - for( i=0; i<8; i++ ) - _arg_ptrs_int[i] = 0; - - s = _arg_buff; - while( c = strtok( s, " " ) ) - { - _arg_ptrs_int[__argc] = c; - __argc++; - s = NULL; - if( __argc >= 8 ) - break; - } - - __argv = _arg_ptrs_int; - -} /* parse_args */ +/* Main */ + +// How much space at the end of RAM to leave for the stack (instead of using it +// as heap). By default 128 KB are reserved for the stack, but this constant +// can be overridden in main.c (or anywhere else) simply by redeclaring it +// without the weak attribute. +const int32_t __attribute__((weak)) STACK_MAX_SIZE = 0x20000; -void _start( int argc, const char *args[] ) -{ - // Load GP address - load_gp(); +// These are defined by the linker script. Note that these are *NOT* pointers, +// they are virtual symbols whose location matches their value. The simplest +// way to turn them into pointers is to declare them as arrays, so here we go. +extern uint8_t __text_start[]; +extern uint8_t __bss_start[]; +extern uint8_t _end[]; +//extern uint8_t _gp[]; + +extern void (*__CTOR_LIST__[])(void); +extern void (*__DTOR_LIST__[])(void); + +extern int32_t main(int32_t argc, const char* argv[]); + +// Even though _start() usually takes no arguments, this implementation allows +// parent executables to pass args directly to child executables without having +// to overwrite the arg strings in kernel RAM. +void _start(int32_t override_argc, const char **override_argv) { + __asm__ volatile("la $gp, _gp;"); // Mem init assembly function (clears BSS and InitHeap to _end which is // not possible to do purely in C because the linker complains about // relocation truncated to fit: R_MIPS_GPREL16 against `_end' // Workaround is to do it in assembly because la pseudo-op doesn't use // stupid gp relative addressing - _mem_init(); - - // process command line arguments - _parse_args( argc, args ); - - _call_global_ctors(); - - *((int*)0x8000DFFC) = main( __argc, __argv ); - - _call_global_dtors(); - - // Set return value to kernel return value area - -} /* _start */
\ No newline at end of file + //_mem_init(); + + // Clear BSS 4 bytes at a time. BSS is always aligned to 4 bytes by the + // linker script. + for (uint32_t *i = (uint32_t *) __bss_start; i < (uint32_t *) _end; i++) + *i = 0; + + // Calculate how much RAM is available after the loaded executable and + // initialize heap accordingly. + void *exe_end = _end + 4; + unsigned int exe_size = (unsigned int) exe_end - (unsigned int) __text_start; + InitHeap(exe_end, 0x200000 - (exe_size + STACK_MAX_SIZE)); + + if (override_argv) { + __argc = override_argc; + __argv = override_argv; + } else { + _parse_kernel_args(); + } + + // Call the global constructors (if any) to initialize global objects + // before calling main(). Constructors are put by the linker script in a + // length-prefixed array in reverse order. + for (uint32_t i = (uint32_t) __CTOR_LIST__[0]; i >= 1; i--) + __CTOR_LIST__[i](); + + // Store main()'s return value into the kernel return value area (for child + // executables). + *KERNEL_RETURN_VALUE = main(__argc, __argv); + + // Call global destructors (in forward order). + for (uint32_t i = 0; i < (uint32_t) __DTOR_LIST__[0]; i++) + __DTOR_LIST__[i + 1](); +} |
