aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/libc
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2021-08-31 13:23:20 +0800
committerGitHub <noreply@github.com>2021-08-31 13:23:20 +0800
commitffa679d4d24b891cb59aba10946368f2ec00c391 (patch)
tree0cf6061915ebf48acdedf6d77b0c1b76eec5b8c3 /libpsn00b/libc
parent317dc2b91d3afcdbaddb035f38611d12af161970 (diff)
parentf2fc18f82dd7900465d6ab3ae2080726d5589d39 (diff)
downloadpsn00bsdk-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.s20
-rw-r--r--libpsn00b/libc/makefile59
-rw-r--r--libpsn00b/libc/malloc.s11
-rw-r--r--libpsn00b/libc/start.c181
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]();
+}