aboutsummaryrefslogtreecommitdiff
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
parent317dc2b91d3afcdbaddb035f38611d12af161970 (diff)
parentf2fc18f82dd7900465d6ab3ae2080726d5589d39 (diff)
downloadpsn00bsdk-ffa679d4d24b891cb59aba10946368f2ec00c391.tar.gz
Merge pull request #36 from spicyjpeg/dynlink
Dynamic linker, gp-relative addressing, ldscripts and more
-rw-r--r--README.md35
-rw-r--r--changelog.txt29
-rw-r--r--doc/dev notes.txt44
-rw-r--r--examples/beginner/cppdemo/makefile81
-rw-r--r--examples/beginner/hello/makefile81
-rw-r--r--examples/cdrom/cdbrowse/iso.xml33
-rw-r--r--examples/cdrom/cdbrowse/makefile80
-rw-r--r--examples/cdrom/cdxa/iso.xml29
-rw-r--r--examples/cdrom/cdxa/makefile80
-rw-r--r--examples/demos/n00bdemo/data.s2
-rw-r--r--examples/demos/n00bdemo/data.xml6
-rw-r--r--examples/demos/n00bdemo/makefile82
-rw-r--r--examples/examples-setup.mk64
-rw-r--r--examples/graphics/balls/makefile81
-rw-r--r--examples/graphics/billboard/makefile76
-rw-r--r--examples/graphics/fpscam/makefile76
-rw-r--r--examples/graphics/gte/makefile76
-rw-r--r--examples/graphics/hdtv/makefile77
-rw-r--r--examples/graphics/render2tex/makefile76
-rw-r--r--examples/graphics/rgb24/makefile76
-rw-r--r--examples/makefile4
-rw-r--r--examples/system/childexec/child/child.c (renamed from examples/system/childexec/child.c)0
-rw-r--r--examples/system/childexec/child_exe.s2
-rw-r--r--examples/system/childexec/makefile105
-rw-r--r--examples/system/console/makefile81
-rw-r--r--examples/system/dynlink/display.c70
-rw-r--r--examples/system/dynlink/iso.xml30
-rw-r--r--examples/system/dynlink/library/ball16c.h16
-rw-r--r--examples/system/dynlink/library/balls.c116
-rw-r--r--examples/system/dynlink/library/cube.c154
-rw-r--r--examples/system/dynlink/library/dll_common.h30
-rw-r--r--examples/system/dynlink/main.c225
-rw-r--r--examples/system/dynlink/makefile95
-rw-r--r--examples/system/dynlink/system.cnf4
-rw-r--r--examples/system/timer/makefile76
-rw-r--r--examples/system/tty/makefile81
-rw-r--r--libpsn00b/include/dlfcn.h176
-rw-r--r--libpsn00b/include/elf.h138
-rw-r--r--libpsn00b/include/psxapi.h1
-rw-r--r--libpsn00b/include/psxgpu.h2
-rw-r--r--libpsn00b/include/stdio.h3
-rw-r--r--libpsn00b/ldscripts/dll.ld122
-rw-r--r--libpsn00b/ldscripts/exe.ld114
-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
-rw-r--r--libpsn00b/lzp/makefile61
-rw-r--r--libpsn00b/psxapi/makefile62
-rw-r--r--libpsn00b/psxapi/sys/flushcache.s10
-rw-r--r--libpsn00b/psxcd/makefile57
-rw-r--r--libpsn00b/psxetc/_dl_resolve_wrapper.s54
-rw-r--r--libpsn00b/psxetc/dl.c665
-rw-r--r--libpsn00b/psxetc/makefile59
-rw-r--r--libpsn00b/psxetc/readme.txt16
-rw-r--r--libpsn00b/psxgpu/makefile57
-rw-r--r--libpsn00b/psxgte/makefile57
-rw-r--r--libpsn00b/psxsio/makefile57
-rw-r--r--libpsn00b/psxspu/makefile61
-rw-r--r--libpsn00b/psxspu/transfer.s3
-rw-r--r--psn00bsdk-setup.mk121
-rw-r--r--template/iso.xml27
-rw-r--r--template/makefile83
-rw-r--r--template/psn00bsdk-setup.mk68
-rw-r--r--template/system.cnf4
-rw-r--r--toolchain.txt38
66 files changed, 3658 insertions, 1002 deletions
diff --git a/README.md b/README.md
index af9fc75..7b794c7 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,8 @@ and performance reasons.
## Notable features
-As of January 5, 2021
+
+As of August 16, 2021
* Extensive GPU support with polygon, line and sprite primitives, high-speed
DMA transfers for VRAM data and ordering tables. All video modes for both
@@ -62,7 +63,12 @@ As of January 5, 2021
and querying files and directories. Supports directories containing more
than 30 files (classic ISO9660 only, no Rock Ridge or Joliet extensions)
and also supports reading new sessions on a multi-session disc.
-
+
+* Experimental support for compiling separate sections of an executable into
+ shared library files (DLLs) and linking them dynamically at runtime, plus
+ support for function and variable introspection by loading a map file
+ generated at build time.
+
* Uses Sony SDK library syntax for familiarity to experienced programmers
and to make porting existing homebrew projects to PSn00bSDK easier.
@@ -91,15 +97,15 @@ You may set one of the following variables either with set/export or on the
make command line, to specify various parameters in building PSn00bSDK and
projects made with it as you see fit.
-* ``GCC_VERSION`` specifies the GCC version number. This is only required for
- building the libc library. If not defined, the default value of 7.4.0 is
- used.
* ``PSN00BSDK_TC`` specifies the base directory of the GCC toolchain to
build PSn00bSDK with, otherwise the makefile assumes you have the path to
the toolchain binaries in one of your PATH directories. Alternatively,
``GCC_BASE`` can be specified in place of ``PSN00BSDK_TC``. If not
specified psn00bsdk-setup.mk assumes the toolchain is at
C:\mipsel-unknown-elf in Win32 or /usr/local/mipsel-unknown-elf in Linux.
+* ``GCC_VERSION`` specifies the GCC version number. This is only used for
+ building the libc library. If not defined, it will be auto-detected by
+ searching ``PSN00BSDK_TC`` or ``GCC_BASE`` for a valid GCC installation.
* ``PSN00BSDK_LIBS`` specifies the target directory you wish to install
the compiled libpsn00b libraries to. If not defined, compiled
libraries are consolidated to the libpsn00b directory and
@@ -158,8 +164,6 @@ programs with PSn00bSDK within the Command Prompt.
(see toolchain.txt for details). Export a variable named `PSN00BSDK_TC`
containing a path to the installed toolchain's base directory if
you've installed the toolchain in a location other than /usr/local.
- Also export a `GCC_VERSION` variable if you're using a version of GCC
- other than 7.4.0.
3. Clone from PSn00bSDK source with
`git clone https://github.com/lameguy64/psn00bsdk`
4. Enter tools directory and run `make`, then `make install` to consolidate
@@ -188,14 +192,25 @@ for the PlayStation. The tutorials should still apply to PSn00bSDK.
* psxspu: Plenty of work to be done. Hardware timer driven sound/music
system may need to be implemented (an equivalent to the Ss* series of
functions in libspu basically). Need to figure out the correct frequency
- table for playing sounds in musical note notation.
-
+ table for playing sounds in musical note notation. Functions that make use of
+ the SPU RAM interrupt feature to play or capture streamed audio should also
+ be added.
+
* psxcd: Implement a command queue mechanism for the CD-ROM?
-* Support for MDEC.
+* libc: Improve the memory allocation framework with multiple allocators, GC
+ and maybe helpers to manage swapping between main RAM and VRAM/SPU RAM.
+
+* Support for MDEC, and tooling to transcode videos to .STR files (either
+ reimplementing the container and compression format used by the Sony SDK, or
+ a custom format with better compression).
* Pad and memory card libraries that don't use the BIOS routines.
+* Switching to, or adding support for a build system that's easier to use with
+ IDEs and/or under Windows, which would also make asset conversion pipelines
+ easier to manage. CMake might be a good option here but more discussion is
+ needed.
## Usage terms
diff --git a/changelog.txt b/changelog.txt
index 666e3c5..15bbb85 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -2,6 +2,35 @@ PSn00bSDK changelog
Items that are lower in the log are more recently implemented.
+08-16-2021 by spicyjpeg:
+
+* psxetc: Added dynamic linking APIs (dl*, DL_*), implemented in dl.c and
+ _dl_resolve_wrapper.s. The APIs can be accessed by including dlfcn.h, while
+ another header (elf.h) provides structs and enums to help with manual parsing
+ of library headers.
+
+* libc: Removed _mem_init.s, improved heap initialization code. Added support
+ for setting how much RAM to use for the stack (by defining STACK_MAX_SIZE)
+ and for overriding/replacing the default memory allocator.
+
+* psxapi: Added wrapper around BIOS function FlushCache().
+
+* psxspu: Fixed wrong bounds check in SpuSetTransferStartAddr().
+
+* examples: Added an example showing how to compile dynamically-loaded
+ libraries (DLLs) and load them at runtime using the new dynamic linker.
+
+* libpsn00b: Added libpsn00b/ldscripts directory and linker scripts for both
+ executables and DLLs. Also fixed several broken header files (psxgpu.h not
+ including sys/types.h, missing scanf() declarations, ...).
+
+* Rewritten most makefiles (both for libraries and examples) and centralized
+ all compiler flags into a single psn00bsdk-setup.mk file for consistency and
+ easier editing. Added flags to build libpsn00b without gp-relative addressing
+ for compatibility with the dynamic linker. Also added nm commands to generate
+ symbol maps required by the linker.
+
+
07-01-2021 by Lameguy64:
* Libpsn00b: Added int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t,
diff --git a/doc/dev notes.txt b/doc/dev notes.txt
index 2b280c7..47aa2df 100644
--- a/doc/dev notes.txt
+++ b/doc/dev notes.txt
@@ -49,4 +49,46 @@ DRAWENV.isbg is not effective in the official SDK.
* In the official SDK, DMA IRQs appear to be enabled only when a callback
function is set (ie. DrawSyncCallback() enables IRQ for DMA channel 2). DMA
-IRQs are only triggered on transfer completion. \ No newline at end of file
+IRQs are only triggered on transfer completion.
+
+Additional notes by spicyjpeg:
+
+* The SDK provides no support yet for replacing the BIOS exception handler with
+a custom one, however it can be done (if you are ok with losing all BIOS
+controller, memory card and file functionality). In order not to break anything
+your exception handler must do the following:
+
+ * prevent GTE opcodes from being executed twice due to a hardware glitch (the
+ nocash docs explain how to do this);
+ * define _irq_func_table[12] as an *extern* array of function pointers, call
+ the appropriate entry when an IRQ occurs and clear the respective flag in
+ register 1F801070h;
+ * handle syscalls 01h-02h, i.e. EnterCriticalSection and ExitCriticalSection
+ properly. You should also handle syscall FF00h (invalid API usage), as well
+ as breaks 1800h and 1C00h (division errors injected by GCC), by locking up
+ and maybe showing a BSOD or similar;
+ * overwrite the default BIOS API vectors with a passthrough that checks no
+ controller- or interrupt-related function is being called. This is necessary
+ (although ugly) as libpsn00b often calls such functions internally.
+
+* For some reason mipsel-unknown-elf-nm (symbol map generator) insists on
+outputting 64-bit addresses (with the top 32 bits set, e.g. FFFFFFFF80010000)
+even when feeding it a regular 32-bit MIPS executable, while the standard x86
+nm tool that ships with most GCC packages prints the proper 32-bit address.
+Unclear whether this is a bug, intended behavior or the result of some ancient
+ELF ABI flag crap. DL_ParseSymbolMap() will ignore the top 32 bits, so this
+should only bother you if you're implementing your own symbol map parser.
+
+* I haven't worked on psxspu but, for those willing to write some code, this is
+the formula to calculate SPU pitch values for playing musical notes ("^" is the
+power operator, not xor):
+
+ frequency = (ref / 32) * (2 ^ ((note - 9) / 12))
+ spu_pitch = frequency / 44100 * 4096
+
+ ref = frequency the sample should be played at to play a middle A (MIDI note 69)
+ note = MIDI note number (usually 0-127, 60 is middle C)
+
+* If you are overriding any of the memory allocation functions, DO NOT ENABLE
+LINK-TIME OPTIMIZATION. GCC has a long-standing bug with LTO and weak functions
+written in assembly, also LTO hasn't been tested at all yet.
diff --git a/examples/beginner/cppdemo/makefile b/examples/beginner/cppdemo/makefile
index 3e122ab..630a280 100644
--- a/examples/beginner/cppdemo/makefile
+++ b/examples/beginner/cppdemo/makefile
@@ -1,54 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+PSN00BSDK_LIBS ?= ../../../libpsn00b
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
# Project target name
-TARGET = cppdemo.elf
+TARGET = cppdemo
+
+## Files
# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
-# Determine object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-# Project specific include and library directories
-# (use -I for include dirs, -L for library dirs)
-INCLUDE +=
-LIBDIRS +=
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-# Libraries to link
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Build rules
-# C compiler flags
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+#all: iso
+all: build/$(TARGET)
-# C++ compiler flags
-CPPFLAGS = $(CFLAGS) -fno-builtin -fno-rtti -fno-exceptions
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
-# Assembler flags
-AFLAGS = -g -msoft-float
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
-# Linker flags
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/beginner/hello/makefile b/examples/beginner/hello/makefile
index 3fce1ae..e4bed20 100644
--- a/examples/beginner/hello/makefile
+++ b/examples/beginner/hello/makefile
@@ -1,54 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+PSN00BSDK_LIBS ?= ../../../libpsn00b
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
# Project target name
-TARGET = hello.elf
+TARGET = hello
+
+## Files
# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
-# Determine object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-# Project specific include and library directories
-# (use -I for include dirs, -L for library dirs)
-INCLUDE +=
-LIBDIRS +=
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-# Libraries to link
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Build rules
-# C compiler flags
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+#all: iso
+all: build/$(TARGET)
-# C++ compiler flags
-CPPFLAGS = $(CFLAGS) -fno-exceptions
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
-# Assembler flags
-AFLAGS = -g -msoft-float
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
-# Linker flags
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/cdrom/cdbrowse/iso.xml b/examples/cdrom/cdbrowse/iso.xml
index a828df1..5d8963d 100644
--- a/examples/cdrom/cdbrowse/iso.xml
+++ b/examples/cdrom/cdbrowse/iso.xml
@@ -1,33 +1,34 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<iso_project image_name="cdbrowse.iso">
-
+<?xml version="1.0" encoding="utf-8"?>
+<iso_project
+ image_name="build/cdbrowse.bin"
+ cue_sheet="build/cdbrowse.cue"
+>
<track type="data">
-
<identifiers
system ="PLAYSTATION"
- application ="PLAYSTATION"
- volume ="PSN00BSDK"
- volume_set ="PSN00BSDK"
+ volume ="CDBROWSE"
+ volume_set ="CDBROWSE"
publisher ="MEIDOTEK"
+ data_preparer ="PSN00BSDK BUILD SCRIPT"
+ application ="PLAYSTATION"
+ copyright ="README.TXT;1"
/>
<directory_tree>
+ <file name="SYSTEM.CNF" type="data" source="system.cnf" />
+ <file name="CDBROWSE.EXE" type="data" source="build/cdbrowse.exe" />
+ <file name="CDBROWSE.MAP" type="data" source="build/cdbrowse.map" />
- <file name="system.cnf" type="data" source="system.cnf"/>
- <file name="cdbrowse.exe" type="data" source="cdbrowse.exe"/>
-
- <dir name="dira">
- <dir name="diraa">
+ <dir name="DIRA">
+ <dir name="DIRAA">
</dir>
</dir>
- <dir name="dirb">
+ <dir name="DIRB">
</dir>
<dummy sectors="1024"/>
-
</directory_tree>
-
</track>
+ <!--<track type="audio" source="track2.wav" />-->
</iso_project>
diff --git a/examples/cdrom/cdbrowse/makefile b/examples/cdrom/cdbrowse/makefile
index ee925d2..954408b 100644
--- a/examples/cdrom/cdbrowse/makefile
+++ b/examples/cdrom/cdbrowse/makefile
@@ -1,45 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = cdbrowse.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-LIBS = -lpsxcd -lpsxgpu -lpsxgte -lpsxspu -lpsxsio -lpsxetc -lpsxapi -lc
+# Project target name
+TARGET = cdbrowse
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) \
- -fno-exceptions \
- -fno-rtti \
- -fno-unwind-tables \
- -fno-threadsafe-statics \
- -fno-use-cxa-atexit
+## Files
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+all: iso
+#all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
-iso:
- mkpsxiso -y -q iso.xml
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/cdrom/cdxa/iso.xml b/examples/cdrom/cdxa/iso.xml
index 840b414..9a6a206 100644
--- a/examples/cdrom/cdxa/iso.xml
+++ b/examples/cdrom/cdxa/iso.xml
@@ -1,29 +1,30 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<iso_project image_name="cdxa.iso">
-
+<?xml version="1.0" encoding="utf-8"?>
+<iso_project
+ image_name="build/cdxa.bin"
+ cue_sheet="build/cdxa.cue"
+>
<track type="data">
-
<identifiers
system ="PLAYSTATION"
- application ="PLAYSTATION"
- volume ="PSN00BSDK"
- volume_set ="PSN00BSDK"
+ volume ="CDXA"
+ volume_set ="CDXA"
publisher ="MEIDOTEK"
+ data_preparer ="PSN00BSDK BUILD SCRIPT"
+ application ="PLAYSTATION"
+ copyright ="README.TXT;1"
/>
<directory_tree>
+ <file name="SYSTEM.CNF" type="data" source="system.cnf" />
+ <file name="CDXA.EXE" type="data" source="build/cdxa.exe" />
+ <file name="CDXA.MAP" type="data" source="build/cdxa.map" />
- <file name="system.cnf" type="data" source="system.cnf"/>
- <file name="cdxa.exe" type="data" source="cdxa.exe"/>
-
<!-- CD-XA file, you'll have to provide your own to make this example work -->
- <file name="xasample.xa" type="xa" source="D:\str-temp\subcon.xa"/>
+ <file name="XASAMPLE.XA" type="mixed" source="xasample.xa"/>
<dummy sectors="1024"/>
-
</directory_tree>
-
</track>
+ <!--<track type="audio" source="track2.wav" />-->
</iso_project>
diff --git a/examples/cdrom/cdxa/makefile b/examples/cdrom/cdxa/makefile
index b95efa7..b1627f7 100644
--- a/examples/cdrom/cdxa/makefile
+++ b/examples/cdrom/cdxa/makefile
@@ -1,45 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = cdxa.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-LIBS = -lpsxcd -lpsxgpu -lpsxgte -lpsxspu -lpsxsio -lpsxetc -lpsxapi -lc
+# Project target name
+TARGET = cdxa
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) \
- -fno-exceptions \
- -fno-rtti \
- -fno-unwind-tables \
- -fno-threadsafe-statics \
- -fno-use-cxa-atexit
+## Files
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
-iso:
- mkpsxiso -y -q iso.xml
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/demos/n00bdemo/data.s b/examples/demos/n00bdemo/data.s
index 3ca33cb..f3b2a83 100644
--- a/examples/demos/n00bdemo/data.s
+++ b/examples/demos/n00bdemo/data.s
@@ -3,7 +3,7 @@
.global lz_resources
.type lz_resources, @object
lz_resources:
- .incbin "data.lzp"
+ .incbin "build/data.lzp"
#.global smd_mtekdisk
#.type smd_mtekdisk, @object
diff --git a/examples/demos/n00bdemo/data.xml b/examples/demos/n00bdemo/data.xml
index 292a325..6761f16 100644
--- a/examples/demos/n00bdemo/data.xml
+++ b/examples/demos/n00bdemo/data.xml
@@ -1,6 +1,6 @@
<lzp_project>
- <create packname="textures.qlp" format="qlp">
+ <create packname="build/textures.qlp" format="qlp">
<file alias="petscum">data/petscum16c.tim</file>
<file alias="bungirl">data/bungirl.tim</file>
@@ -19,7 +19,7 @@
</create>
- <create packname="data.lzp" format="lzp">
+ <create packname="build/data.lzp" format="lzp">
<!-- intro assets -->
<file alias="mtekdisk">data/mtekdisk.smd</file>
@@ -42,7 +42,7 @@
<file alias="hatkid">data/hatkid.smd</file>
<!-- Global textures -->
- <file alias="textures">textures.qlp</file>
+ <file alias="textures">build/textures.qlp</file>
</create>
diff --git a/examples/demos/n00bdemo/makefile b/examples/demos/n00bdemo/makefile
index 7e3bd8e..9206e09 100644
--- a/examples/demos/n00bdemo/makefile
+++ b/examples/demos/n00bdemo/makefile
@@ -1,39 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = demo.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE += -I../../../libpsn00b/lzp
+# Project target name
+TARGET = demo
-LIBS = -llzp -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS += -llzp
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET)
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ $(LZPACK) data.xml
+ touch data.s
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: resources $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
-build/%.o: %.s
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
-resources:
- lzpack data.xml
- touch data.s
-
-iso:
- mkpsxiso -y -q -o demo.iso iso.xml
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s resources
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build *.lzp *.qlp $(TARGET) $(TARGET:.elf=.exe) $(TARGET:.elf=.iso)
+ rm -rf build
diff --git a/examples/examples-setup.mk b/examples/examples-setup.mk
deleted file mode 100644
index 1fadd84..0000000
--- a/examples/examples-setup.mk
+++ /dev/null
@@ -1,64 +0,0 @@
-# PSn00bSDK examples setup file
-# Part of the PSn00bSDK Project
-# 2019 - 2020 Lameguy64 / Meido-Tek Productions
-#
-# This is only for the PSn00bSDK example programs, not recommended
-# for use with user projects
-
-PREFIX = mipsel-unknown-elf
-
-ifndef GCC_VERSION
-
-GCC_VERSION = 7.4.0
-
-endif # GCC_VERSION
-
-# PSn00bSDK library/include path setup
-ifndef PSN00BSDK_LIBS
-
-# Default assumes libpsn00b is just in the parent dir of the examples dir
-
-LIBDIRS = -L../../../libpsn00b
-INCLUDE = -I../../../libpsn00b/include
-
-else
-
-LIBDIRS = -L$(PSN00BSDK_LIBS)
-INCLUDE = -I$(PSN00BSDK_LIBS)/include
-
-endif # PSN00BSDK_LIBS
-
-# PSn00bSDK toolchain path setup
-ifndef GCC_BASE
-
-ifndef PSN00BSDK_TC
-
-# Default assumes GCC toolchain is in root of C drive or /usr/local
-
-ifeq "$(OS)" "Windows_NT"
-
-GCC_BASE = /c/mipsel-unknown-elf
-GCC_BIN =
-
-else
-
-GCC_BASE = /usr/local/mipsel-unknown-elf
-GCC_BIN =
-
-endif
-
-else
-
-GCC_BASE = $(PSN00BSDK_TC)
-GCC_BIN = $(PSN00BSDK_TC)/bin/
-
-endif # PSN00BSDK_TC
-
-endif # GCC_BASE
-
-CC = $(GCC_BIN)$(PREFIX)-gcc
-CXX = $(GCC_BIN)$(PREFIX)-g++
-AS = $(GCC_BIN)$(PREFIX)-as
-AR = $(GCC_BIN)$(PREFIX)-ar
-LD = $(GCC_BIN)$(PREFIX)-ld
-RANLIB = $(GCC_BIN)$(PREFIX)-ranlib \ No newline at end of file
diff --git a/examples/graphics/balls/makefile b/examples/graphics/balls/makefile
index 70f41bf..44d3d71 100644
--- a/examples/graphics/balls/makefile
+++ b/examples/graphics/balls/makefile
@@ -1,54 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+PSN00BSDK_LIBS ?= ../../../libpsn00b
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
# Project target name
-TARGET = balls.elf
+TARGET = balls
+
+## Files
# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
-# Determine object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-# Project specific include and library directories
-# (use -I for include dirs, -L for library dirs)
-INCLUDE +=
-LIBDIRS +=
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-# Libraries to link
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Build rules
-# C compiler flags
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+#all: iso
+all: build/$(TARGET)
-# C++ compiler flags
-CPPFLAGS = $(CFLAGS) -fno-exceptions
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
-# Assembler flags
-AFLAGS = -g -msoft-float
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
-# Linker flags
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/graphics/billboard/makefile b/examples/graphics/billboard/makefile
index 4f0fcf4..462e73c 100644
--- a/examples/graphics/billboard/makefile
+++ b/examples/graphics/billboard/makefile
@@ -1,35 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = billboard.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = billboard
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/graphics/fpscam/makefile b/examples/graphics/fpscam/makefile
index dac1d43..2ddb7fd 100644
--- a/examples/graphics/fpscam/makefile
+++ b/examples/graphics/fpscam/makefile
@@ -1,35 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = fpscam.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = fpscam
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/graphics/gte/makefile b/examples/graphics/gte/makefile
index 43b7c5b..f44e72b 100644
--- a/examples/graphics/gte/makefile
+++ b/examples/graphics/gte/makefile
@@ -1,35 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = gte.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = gte
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/graphics/hdtv/makefile b/examples/graphics/hdtv/makefile
index 2c7cb71..6659c98 100644
--- a/examples/graphics/hdtv/makefile
+++ b/examples/graphics/hdtv/makefile
@@ -1,36 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = hdtv.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = hdtv
-LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/graphics/render2tex/makefile b/examples/graphics/render2tex/makefile
index 52d650b..bb0ef3c 100644
--- a/examples/graphics/render2tex/makefile
+++ b/examples/graphics/render2tex/makefile
@@ -1,35 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = render2tex.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = render2tex
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/graphics/rgb24/makefile b/examples/graphics/rgb24/makefile
index 3ec9cfe..9fa35ec 100644
--- a/examples/graphics/rgb24/makefile
+++ b/examples/graphics/rgb24/makefile
@@ -1,37 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = rgb24.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = rgb24
-LIBS = -lpsxgpu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
-build/%.o: %.tim
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/makefile b/examples/makefile
index e02f7ba..bdc62ce 100644
--- a/examples/makefile
+++ b/examples/makefile
@@ -13,8 +13,8 @@ DIRS += graphics/balls graphics/billboard graphics/fpscam \
graphics/rgb24
# System related examples
-DIRS += system/childexec system/console system/timer \
- system/tty
+DIRS += system/childexec system/console system/dynlink \
+ system/timer system/tty
# Low-level examples
DIRS +=
diff --git a/examples/system/childexec/child.c b/examples/system/childexec/child/child.c
index 2ddfa73..2ddfa73 100644
--- a/examples/system/childexec/child.c
+++ b/examples/system/childexec/child/child.c
diff --git a/examples/system/childexec/child_exe.s b/examples/system/childexec/child_exe.s
index 842ac88..66bd0e2 100644
--- a/examples/system/childexec/child_exe.s
+++ b/examples/system/childexec/child_exe.s
@@ -3,4 +3,4 @@
.global child_exe # Insert spoopypasta
.type child_exe, @object
child_exe:
- .incbin "child.exe" \ No newline at end of file
+ .incbin "build/child/child.exe" \ No newline at end of file
diff --git a/examples/system/childexec/makefile b/examples/system/childexec/makefile
index 30229ae..e801739 100644
--- a/examples/system/childexec/makefile
+++ b/examples/system/childexec/makefile
@@ -1,36 +1,93 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-INCLUDE +=
-LIBDIRS +=
+## Settings
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-LDFLAGS_P = $(LDFLAGS) -Ttext=0x80010000
-LDFLAGS_C = $(LDFLAGS) -Ttext=0x80030000
+# Project target name
+#TARGET = childexec
-all: child parent
+## Files
-child: build/child.o
- $(LD) $(LDFLAGS_C) $(LIBDIRS) build/child.o $(LIBS) -o child.elf
- elf2x -q child.elf
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES_PARENT = $(notdir $(wildcard *.c))
+CPPFILES_PARENT = $(notdir $(wildcard *.cpp))
+AFILES_PARENT = $(notdir $(wildcard *.s))
+
+CFILES_CHILD = $(notdir $(wildcard child/*.c))
+CPPFILES_CHILD = $(notdir $(wildcard child/*.cpp))
+AFILES_CHILD = $(notdir $(wildcard child/*.s))
+
+# Create names for object files
+OFILES_PARENT = $(addprefix build/,$(CFILES_PARENT:.c=.o)) \
+ $(addprefix build/,$(CPPFILES_PARENT:.cpp=.o)) \
+ $(addprefix build/,$(AFILES_PARENT:.s=.o))
+OFILES_CHILD = $(addprefix build/child/,$(CFILES_CHILD:.c=.o)) \
+ $(addprefix build/child/,$(CPPFILES_CHILD:.cpp=.o)) \
+ $(addprefix build/child/,$(AFILES_CHILD:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+# Relocate the child executable to 0x30000
+LDFLAGS_CHILD = -Ttext=0x80030000
+
+## Build rules
+
+#all: iso
+all: build/child/child build/parent
+
+iso: build/child/child build/parent resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/child/child: $(OFILES_CHILD)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LDFLAGS_CHILD) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
+
+build/parent: $(OFILES_PARENT)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
+
+build/child/%.o: child/%.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/child/%.o: child/%.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/child/%.o: child/%.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
-parent: build/parent.o build/child_exe.o
- $(LD) $(LDFLAGS_P) $(LIBDIRS) build/parent.o build/child_exe.o $(LIBS) -o parent.elf
- elf2x -q parent.elf
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build parent.elf parent.exe child.elf child.exe
+ rm -rf build
diff --git a/examples/system/console/makefile b/examples/system/console/makefile
index 1ee638f..addf02a 100644
--- a/examples/system/console/makefile
+++ b/examples/system/console/makefile
@@ -1,54 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+PSN00BSDK_LIBS ?= ../../../libpsn00b
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
# Project target name
-TARGET = console.elf
+TARGET = console
+
+## Files
# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
-# Determine object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-# Project specific include and library directories
-# (use -I for include dirs, -L for library dirs)
-INCLUDE +=
-LIBDIRS +=
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-# Libraries to link
-LIBS = -lpsxsio -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Build rules
-# C compiler flags
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+#all: iso
+all: build/$(TARGET)
-# C++ compiler flags
-CPPFLAGS = $(CFLAGS) -fno-exceptions
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
-# Assembler flags
-AFLAGS = -g -msoft-float
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
-# Linker flags
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/system/dynlink/display.c b/examples/system/dynlink/display.c
new file mode 100644
index 0000000..d8ad3ed
--- /dev/null
+++ b/examples/system/dynlink/display.c
@@ -0,0 +1,70 @@
+/*
+ * PSn00bSDK dynamic linker example (utilities)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#include <psxgpu.h>
+
+#include "library/dll_common.h"
+
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+/* Display/GPU context utilities */
+
+void init_context(CONTEXT *ctx) {
+ DB *db;
+
+ ResetGraph(0);
+ ctx->xres = SCREEN_XRES;
+ ctx->yres = SCREEN_YRES;
+ ctx->db_active = 0;
+
+ db = &(ctx->db[0]);
+ SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES);
+ SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES);
+ setRGB0(&(db->draw), 63, 0, 127);
+ db->draw.isbg = 1;
+ db->draw.dtd = 1;
+
+ db = &(ctx->db[1]);
+ SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES);
+ SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES);
+ setRGB0(&(db->draw), 63, 0, 127);
+ db->draw.isbg = 1;
+ db->draw.dtd = 1;
+
+ // Set up the ordering tables and primitive buffers.
+ db = &(ctx->db[0]);
+ ctx->db_nextpri = db->p;
+ ClearOTagR((u_long *) db->ot, OT_LEN);
+
+ PutDrawEnv(&(db->draw));
+ //PutDispEnv(&(db->disp));
+
+ db = &(ctx->db[1]);
+ ClearOTagR((u_long *) db->ot, OT_LEN);
+
+ // Create a text stream at the top of the screen.
+ FntLoad(960, 0);
+ FntOpen(4, 12, 312, 32, 2, 256);
+}
+
+void display(CONTEXT *ctx) {
+ DB *db;
+
+ DrawSync(0);
+ VSync(0);
+ ctx->db_active ^= 1;
+
+ db = &(ctx->db[ctx->db_active]);
+ ctx->db_nextpri = db->p;
+ ClearOTagR((u_long *) db->ot, OT_LEN);
+
+ PutDrawEnv(&(db->draw));
+ PutDispEnv(&(db->disp));
+ SetDispMask(1);
+
+ db = &(ctx->db[!ctx->db_active]);
+ DrawOTag((u_long *) &(db->ot[OT_LEN - 1]));
+}
diff --git a/examples/system/dynlink/iso.xml b/examples/system/dynlink/iso.xml
new file mode 100644
index 0000000..76cc8fc
--- /dev/null
+++ b/examples/system/dynlink/iso.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<iso_project
+ image_name="build/dynlink.bin"
+ cue_sheet="build/dynlink.cue"
+>
+ <track type="data">
+ <identifiers
+ system ="PLAYSTATION"
+ volume ="DYNLINK"
+ volume_set ="DYNLINK"
+ publisher ="MEIDOTEK"
+ data_preparer ="PSN00BSDK BUILD SCRIPT"
+ application ="PLAYSTATION"
+ copyright ="README.TXT;1"
+ />
+
+ <directory_tree>
+ <file name="SYSTEM.CNF" type="data" source="system.cnf" />
+ <file name="MAIN.EXE" type="data" source="build/main.exe" />
+ <file name="MAIN.MAP" type="data" source="build/main.map" />
+
+ <file name="CUBE.DLL" type="data" source="build/library/cube.dll" />
+ <file name="BALLS.DLL" type="data" source="build/library/balls.dll" />
+
+ <dummy sectors="1024"/>
+ </directory_tree>
+ </track>
+
+ <!--<track type="audio" source="track2.wav" />-->
+</iso_project>
diff --git a/examples/system/dynlink/library/ball16c.h b/examples/system/dynlink/library/ball16c.h
new file mode 100644
index 0000000..c79f273
--- /dev/null
+++ b/examples/system/dynlink/library/ball16c.h
@@ -0,0 +1,16 @@
+unsigned int ball16c_size=192;
+unsigned char ball16c[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d,
+0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a,
+0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01,
+0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32,
+0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52,
+0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31,
+0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4,
+0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce,
+0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7,
+0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e,
+0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4,
+0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00
+};
diff --git a/examples/system/dynlink/library/balls.c b/examples/system/dynlink/library/balls.c
new file mode 100644
index 0000000..2a4d9f4
--- /dev/null
+++ b/examples/system/dynlink/library/balls.c
@@ -0,0 +1,116 @@
+/*
+ * PSn00bSDK dynamic linker example (DLL 2)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <psxgpu.h>
+#include <psxgte.h>
+#include <psxpad.h>
+#include <inline_c.h>
+
+#include "dll_common.h"
+#include "ball16c.h"
+
+/* Balls data */
+
+typedef struct {
+ int16_t x, y;
+ int16_t xdir, ydir;
+ uint8_t r, g, b, p;
+} BALL_TYPE;
+
+#define MAX_BALLS 512
+
+/* Functions called by the main executable */
+
+// NOTE: DLLs have no main(), _start() or other defined entry point. C++ global
+// objects are automatically constructed when loading the library, and their
+// destructors are called when unloading it via dlclose(). Other than that, the
+// main executable can freely call DLL functions in any order, however it's
+// still recommended (at least for C code) to have an init() function to e.g.
+// initialize variables or hardware.
+
+static uint32_t frame = 0;
+static BALL_TYPE balls[MAX_BALLS];
+static TIM_IMAGE ball_tim;
+
+void init(CONTEXT *ctx) {
+ GetTimInfo((u_long *) ball16c, &ball_tim);
+
+ LoadImage(ball_tim.prect, ball_tim.paddr);
+ if (ball_tim.mode & 8)
+ LoadImage(ball_tim.crect, ball_tim.caddr);
+
+ // Initialize the balls by giving them a random initial position, velocity
+ // and color.
+ for (uint32_t i = 0; i < MAX_BALLS; i++) {
+ BALL_TYPE *b = &(balls[i]);
+
+ b->x = rand() % (ctx->xres - 16);
+ b->y = rand() % (ctx->yres - 16);
+ b->xdir = ((rand() & 1) ? 1 : -1) * ((rand() % 3) + 1);
+ b->ydir = ((rand() & 1) ? 1 : -1) * ((rand() % 3) + 1);
+ b->r = rand() & 0xff;
+ b->g = rand() & 0xff;
+ b->b = rand() & 0xff;
+ }
+}
+
+void render(CONTEXT *ctx, uint16_t buttons) {
+ DB *db = &(ctx->db[ctx->db_active]);
+ SPRT_16 *sprt = (SPRT_16 *) ctx->db_nextpri;
+
+ for (uint32_t i = 0; i < MAX_BALLS; i++) {
+ BALL_TYPE *b = &(balls[i]);
+
+ setSprt16(sprt);
+
+ setXY0(sprt, b->x, b->y);
+ setRGB0(sprt, b->r, b->g, b->b);
+ setUV0(sprt, 0, 0);
+ setClut(sprt, ball_tim.crect->x, ball_tim.crect->y);
+
+ addPrim(&(db->ot[OT_LEN - 1]), sprt);
+ sprt++;
+
+ // Update the ball's velocity and acceleration, moving them slower if
+ // cross is pressed.
+ int16_t step = !(buttons & PAD_CROSS) ? 1 : 0;
+ b->x += b->xdir >> step;
+ b->y += b->ydir >> step;
+
+ if (
+ (b->x < 0) ||
+ ((b->x + 16) > ctx->xres)
+ )
+ b->xdir *= -1;
+ if (
+ (b->y < 0) ||
+ ((b->y + 16) > ctx->yres)
+ )
+ b->ydir *= -1;
+ }
+
+ ctx->db_nextpri = (uint8_t *) sprt;
+
+ // Add a TPAGE "primitive" to ensure the GPU finds the ball texture.
+ DR_TPAGE *tpri = (DR_TPAGE * ) ctx->db_nextpri;
+
+ setDrawTPage(
+ tpri,
+ 0,
+ 0,
+ getTPage(0, 0, ball_tim.prect->x, ball_tim.prect->y)
+ );
+ addPrim(&(db->ot[OT_LEN - 1]), tpri);
+ tpri++;
+
+ ctx->db_nextpri = (uint8_t *) tpri;
+
+ // Due to our custom resolver, this will actually call dll_printf() in the
+ // main executable.
+ printf("DRAWING BALLS, COUNTER=%d\n", frame++);
+}
diff --git a/examples/system/dynlink/library/cube.c b/examples/system/dynlink/library/cube.c
new file mode 100644
index 0000000..57f3e56
--- /dev/null
+++ b/examples/system/dynlink/library/cube.c
@@ -0,0 +1,154 @@
+/*
+ * PSn00bSDK dynamic linker example (DLL 1)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <psxgpu.h>
+#include <psxgte.h>
+#include <psxpad.h>
+#include <inline_c.h>
+
+#include "dll_common.h"
+
+/* Cube model */
+
+typedef struct {
+ int16_t v0, v1, v2, v3;
+} INDEX;
+
+static SVECTOR cube_verts[] = {
+ { -100, -100, -100, 0 },
+ { 100, -100, -100, 0 },
+ { -100, 100, -100, 0 },
+ { 100, 100, -100, 0 },
+ { 100, -100, 100, 0 },
+ { -100, -100, 100, 0 },
+ { 100, 100, 100, 0 },
+ { -100, 100, 100, 0 }
+};
+static SVECTOR cube_norms[] = {
+ { 0, 0, -ONE, 0 },
+ { 0, 0, ONE, 0 },
+ { 0, -ONE, 0, 0 },
+ { 0, ONE, 0, 0 },
+ { -ONE, 0, 0, 0 },
+ { ONE, 0, 0, 0 }
+};
+static INDEX cube_indices[] = {
+ { 0, 1, 2, 3 },
+ { 4, 5, 6, 7 },
+ { 5, 4, 0, 1 },
+ { 6, 7, 3, 2 },
+ { 0, 2, 5, 7 },
+ { 3, 1, 6, 4 }
+};
+
+#define CUBE_FACES 6
+
+/* Light matrices */
+
+// Each column represents the color matrix of each light source and is used as
+// material color when using gte_ncs() or multiplied by a source color when
+// using gte_nccs(). 4096 is 1.0 in this matrix. A column of zeroes disables
+// the light source.
+static MATRIX color_mtx = {
+ ONE, 0, 0, // R
+ ONE, 0, 0, // G
+ ONE, 0, 0 // B
+};
+
+// Each row represents a vector direction of each light source. An entire row
+// of zeroes disables the light source.
+static MATRIX light_mtx = {
+ -2048, -2048, -2048,
+ 0, 0, 0,
+ 0, 0, 0
+};
+
+/* Functions called by the main executable */
+
+// NOTE: DLLs have no main(), _start() or other defined entry point. C++ global
+// objects are automatically constructed when loading the library, and their
+// destructors are called when unloading it via dlclose(). Other than that, the
+// main executable can freely call DLL functions in any order, however it's
+// still recommended (at least for C code) to have an init() function to e.g.
+// initialize variables or hardware.
+
+static uint32_t frame = 0;
+static SVECTOR rot = { 0 };
+static VECTOR pos = { 0, 0, 400 };
+static MATRIX mtx, lmtx;
+
+void init(CONTEXT *ctx) {
+ InitGeom();
+
+ gte_SetGeomOffset(ctx->xres / 2, ctx->yres / 2);
+ gte_SetGeomScreen(ctx->xres / 2);
+ gte_SetBackColor(63, 63, 63);
+ gte_SetColorMatrix(&color_mtx);
+}
+
+void render(CONTEXT *ctx, uint16_t buttons) {
+ RotMatrix(&rot, &mtx);
+ TransMatrix(&mtx, &pos);
+ MulMatrix0(&light_mtx, &mtx, &lmtx);
+
+ gte_SetRotMatrix(&mtx);
+ gte_SetTransMatrix(&mtx);
+ gte_SetLightMatrix(&lmtx);
+
+ // Spin the cube faster is cross is pressed.
+ int16_t step = !(buttons & PAD_CROSS) ? 32 : 16;
+ rot.vx += step;
+ rot.vz += step;
+
+ DB *db = &(ctx->db[ctx->db_active]);
+ POLY_F4 *pol4 = (POLY_F4 *) ctx->db_nextpri;
+
+ for (uint32_t i = 0; i < CUBE_FACES; i++) {
+ int32_t p;
+
+ gte_ldv3(
+ &cube_verts[cube_indices[i].v0],
+ &cube_verts[cube_indices[i].v1],
+ &cube_verts[cube_indices[i].v2]
+ );
+
+ gte_rtpt();
+ gte_nclip();
+ gte_stopz(&p);
+ if (p < 0)
+ continue;
+
+ gte_avsz4();
+ gte_stotz(&p);
+ if ((p >> 2) > OT_LEN)
+ continue;
+
+ setPolyF4(pol4);
+
+ gte_stsxy0(&(pol4->x0));
+ gte_stsxy1(&(pol4->x1));
+ gte_stsxy2(&(pol4->x2));
+
+ gte_ldv0(&(cube_verts[cube_indices[i].v3]));
+ gte_rtps();
+ gte_stsxy(&(pol4->x3));
+
+ gte_ldrgb(&(pol4->r0));
+ gte_ldv0(&(cube_norms[i]));
+ gte_ncs();
+ gte_strgb(&(pol4->r0));
+
+ addPrim(&(db->ot[p >> 2]), pol4);
+ pol4++;
+ }
+
+ ctx->db_nextpri = (uint8_t *) pol4;
+
+ // Due to our custom resolver, this will actually call dll_printf() in the
+ // main executable.
+ printf("DRAWING CUBE, COUNTER=%d\n", frame++);
+}
diff --git a/examples/system/dynlink/library/dll_common.h b/examples/system/dynlink/library/dll_common.h
new file mode 100644
index 0000000..4f9314b
--- /dev/null
+++ b/examples/system/dynlink/library/dll_common.h
@@ -0,0 +1,30 @@
+/*
+ * PSn00bSDK dynamic linker example (shared header)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#ifndef __DLL_COMMON_H
+#define __DLL_COMMON_H
+
+#include <psxgpu.h>
+
+/* Common structures shared by the main executable and DLLs */
+
+#define OT_LEN 256
+#define PACKET_LEN 16384
+
+typedef struct {
+ DISPENV disp;
+ DRAWENV draw;
+ uint32_t ot[OT_LEN];
+ uint8_t p[PACKET_LEN];
+} DB;
+
+typedef struct {
+ uint16_t xres, yres;
+ DB db[2];
+ uint32_t db_active;
+ uint8_t *db_nextpri;
+} CONTEXT;
+
+#endif
diff --git a/examples/system/dynlink/main.c b/examples/system/dynlink/main.c
new file mode 100644
index 0000000..70314da
--- /dev/null
+++ b/examples/system/dynlink/main.c
@@ -0,0 +1,225 @@
+/*
+ * PSn00bSDK dynamic linker example (main executable)
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * This example shows how to use the psxetc DL_*() APIs to obtain information
+ * about the executable's symbols at runtime. This is accomplished by parsing a
+ * symbol map file, which is generated at compile time by GCC's nm command and
+ * included into the CD image. The symbol map lists all functions/variables in
+ * the executable and their type, address and size. Currently only searching
+ * for a symbol's address by its name (DL_GetSymbolByName()) is supported,
+ * however this may be expanded in the future.
+ *
+ * Being able to introspect local symbols at runtime, in turn, allows us to use
+ * the dl*() set of APIs to load, link and execute code from an external file
+ * (compiled with the dll.ld linker script). A dynamically-loaded library can
+ * reference and access any non-static function or variable within the main
+ * executable (and the libraries the main executable has been compiled with);
+ * the dynamic linker will automatically patch the DLL's code and resolve these
+ * references so that they point to the addresses listed in the map file. DLLs
+ * also have their own symbol tables, and any symbol in a DLL is accessible to
+ * the main executable through dlsym().
+ *
+ * This example shows how DLLs can be loaded and unloaded at any time. Pressing
+ * START will unload the current DLL and load an alternate one on-the-fly. A
+ * custom resolver is also employed to tap into the DLL patching process and
+ * override the printf() function referenced by the DLLs with a different
+ * implementation, so the debug output from the DLLs can be redirected to the
+ * on-screen overlay.
+ *
+ * Dynamic linking has plenty of practical applications. It can be e.g. used to
+ * greatly reduce RAM usage by splitting off a large executable into a "common"
+ * executable (containing SDK APIs as well as frequently-used symbols such as
+ * rendering buffers) and many smaller DLLs, which can then be swapped in and
+ * out depending on which functions are needed. It can also be useful to run
+ * code that hasn't been compiled at the same time as the main executable, such
+ * as plugins/mods/patches stored on a memory card.
+ */
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <dlfcn.h>
+#include <psxapi.h>
+#include <psxetc.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxpad.h>
+
+#include "library/dll_common.h"
+
+// List all SDK functions used by the DLLs in a dummy array to ensure GCC won't
+// strip them. By default the linker removes all functions unused in the
+// executable itself, but we (obviously) need them to be present for a DLL to
+// call them. Placing this array in the .dummy section (as defined in the
+// PSn00bSDK linker script) ensures it won't be stripped away until all
+// functions are in place.
+const void *const DO_NOT_STRIP[] __attribute__((section(".dummy"))) = {
+ &rand,
+ &InitGeom,
+ &RotMatrix,
+ &TransMatrix,
+ &MulMatrix0
+};
+
+static const char *const DLL_FILENAMES[] = {
+ "cdrom:CUBE.DLL;1",
+ "cdrom:BALLS.DLL;1"
+};
+
+#define DLL_COUNT 2
+
+void init_context(CONTEXT *ctx);
+void display(CONTEXT *ctx);
+
+/* Symbol overriding example */
+
+static volatile uint32_t resolve_counter = 0;
+
+// This function will override printf(), i.e. DLLs will use this instead of the
+// "real" printf() present in the executable, thanks to the custom resolver
+// defined below. We'll use this to redirect the DLL's output to the debug text
+// window.
+int dll_printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ char buffer[256];
+ int32_t return_value = vsprintf(buffer, format, args);
+ va_end(args);
+
+ FntPrint(-1, "DLL: %s", buffer);
+ //FntFlush(-1);
+
+ return return_value;
+}
+
+// This function will be called by the linker for each undefined symbol
+// (function or variable) in the DLL, and should return the address of the
+// symbol so the dynamic linker can patch it in. The default resolver tries to
+// find them in the currently loaded symbol map using DL_GetSymbolByName().
+void *custom_resolver(DLL *dll, const char *name) {
+ if (!strcmp(name, "printf")) {
+ printf("Resolving printf() -> dll_printf() (#%d)\n", resolve_counter++);
+ return &dll_printf;
+ }
+
+ printf("Resolving %s() (#%d)\n", name, resolve_counter++);
+
+ // Custom resolvers should always fall back to the default behavior.
+ return DL_GetSymbolByName(name);
+}
+
+/* Global variables and structs */
+
+// Define a struct to store pointers to a DLL's functions into. This is not
+// strictly required, however looking up symbols is a relatively slow operation
+// and the pointers returned by dlsym() should be saved and reused as much as
+// possible.
+typedef struct {
+ void (*init)(CONTEXT *);
+ void (*render)(CONTEXT *, uint16_t buttons);
+} DLL_API;
+
+static DLL *dll = 0;
+static DLL_API dll_api;
+static CONTEXT ctx;
+
+/* Main */
+
+#define SHOW_STATUS(...) { FntPrint(-1, __VA_ARGS__); FntFlush(-1); display(&ctx); }
+#define SHOW_ERROR(...) { SHOW_STATUS(__VA_ARGS__); while (1) __asm__("nop"); }
+
+void load_dll(const char *filename) {
+ if (dll)
+ dlclose(dll);
+
+ SHOW_STATUS("LOADING %s\n", filename);
+
+ dll = dlopen(filename, RTLD_LAZY);
+ if (!dll)
+ SHOW_ERROR("FAILED TO LOAD %s\n%s\n", filename, dlerror());
+
+ dll_api.init = dlsym(dll, "init");
+ dll_api.render = dlsym(dll, "render");
+
+ printf("DLL init() @ %08x, render() @ %08x\n", dll_api.init, dll_api.render);
+
+ // Unfortunately, due to how position-independent code works, function
+ // pointers returned by dlsym() can't be called directly. We have to use
+ // the DL_CALL() macro instead, which sets up register $t9 to ensure the
+ // function can locate and reference the DLL's relocation table.
+ DL_CALL(dll_api.init, &ctx);
+
+}
+
+int main(int argc, const char* argv[]) {
+ // As DL_LoadSymbolMap() and dlopen() rely on BIOS file APIs, the BIOS CD
+ // driver must be initialized by calling _InitCd() prior to loading the
+ // symbol map (but after setting up the GPU, for some reason).
+ init_context(&ctx);
+
+ SHOW_STATUS("INITIALIZING CD\n");
+ _InitCd();
+
+ SHOW_STATUS("LOADING SYMBOL MAP\n");
+
+ if (!DL_LoadSymbolMap("cdrom:MAIN.MAP;1"))
+ SHOW_ERROR("FAILED TO LOAD SYMBOL MAP\n%s\n", dlerror());
+
+ // Try to obtain a reference to a local function.
+ void (*_display)() = DL_GetSymbolByName("display");
+ if (!_display)
+ SHOW_ERROR("FAILED TO LOOK UP LOCAL FUNCTION\n%s\n", dlerror());
+
+ printf("Symbol map test, display() @ %08x\n", _display);
+
+ // Set up controller polling.
+ uint8_t pad_buff[2][34];
+ InitPAD(pad_buff[0], 34, pad_buff[1], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+ // Set up the custom resolver and load the first DLL.
+ DL_SetResolveCallback(&custom_resolver);
+ load_dll(DLL_FILENAMES[0]);
+
+ uint32_t dll_active = 0;
+ uint16_t last_buttons = 0xffff;
+
+ while (1) {
+ // Use the currently loaded DLL to render a frame.
+ DL_CALL(dll_api.render, &ctx, last_buttons);
+
+ FntPrint(-1, "MAIN: DLL ADDR=%08x SIZE=%d\n", dll->ptr, dll->size);
+ FntPrint(-1, "MAIN: %d FUNCTIONS RESOLVED\n", resolve_counter);
+ FntPrint(-1, "[START] LOAD NEXT DLL\n");
+ FntFlush(-1);
+ display(&ctx);
+
+ // Check if a compatible controller is connected and if START has been
+ // pressed (i.e. wasn't previously held down, but now is). If so,
+ // switch the active DLL.
+ PADTYPE *pad = (PADTYPE *) pad_buff[0];
+ if (pad->stat)
+ continue;
+ if ((pad->type != 4) && (pad->type != 5) && (pad->type != 7))
+ continue;
+
+ if ((last_buttons & PAD_START) && !(pad->btn & PAD_START)) {
+ dll_active++;
+ dll_active %= DLL_COUNT;
+
+ load_dll(DLL_FILENAMES[dll_active]);
+ }
+
+ last_buttons = pad->btn;
+ }
+
+ //dlclose(dll);
+ //DL_UnloadSymbolMap();
+ return 0;
+}
diff --git a/examples/system/dynlink/makefile b/examples/system/dynlink/makefile
new file mode 100644
index 0000000..b3fb298
--- /dev/null
+++ b/examples/system/dynlink/makefile
@@ -0,0 +1,95 @@
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+PSN00BSDK_LIBS ?= ../../../libpsn00b
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
+
+# Project target name
+#TARGET = dynlink
+
+## Files
+
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES_MAIN = $(notdir $(wildcard *.c))
+CPPFILES_MAIN = $(notdir $(wildcard *.cpp))
+AFILES_MAIN = $(notdir $(wildcard *.s))
+
+CFILES_DLL = $(notdir $(wildcard library/*.c))
+CPPFILES_DLL = $(notdir $(wildcard library/*.cpp))
+AFILES_DLL = $(notdir $(wildcard library/*.s))
+
+# Create names for object files
+OFILES_MAIN = $(addprefix build/,$(CFILES_MAIN:.c=.o)) \
+ $(addprefix build/,$(CPPFILES_MAIN:.cpp=.o)) \
+ $(addprefix build/,$(AFILES_MAIN:.s=.o))
+OFILES_CUBE = build/library/cube.o
+OFILES_BALLS = build/library/balls.o
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+all: iso
+#all: build/library/cube build/library/balls build/main
+
+iso: build/library/cube build/library/balls build/main resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/library/cube: $(OFILES_CUBE)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_DLL) $^ -o $@
+ #$(NM) -f posix -l -n $@ >$@.map
+ $(OBJCOPY) -O binary $@ $@.dll
+
+build/library/balls: $(OFILES_BALLS)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_DLL) $^ -o $@
+ #$(NM) -f posix -l -n $@ >$@.map
+ $(OBJCOPY) -O binary $@ $@.dll
+
+build/main: $(OFILES_MAIN)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXEDYN) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
+
+build/library/%.o: library/%.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS_DLL) $(INCLUDE) -c $< -o $@
+
+build/library/%.o: library/%.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_DLL) $(INCLUDE) -c $< -o $@
+
+build/library/%.o: library/%.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS_DLL) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS_EXEDYN) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXEDYN) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS_EXEDYN) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build
diff --git a/examples/system/dynlink/system.cnf b/examples/system/dynlink/system.cnf
new file mode 100644
index 0000000..a4a2146
--- /dev/null
+++ b/examples/system/dynlink/system.cnf
@@ -0,0 +1,4 @@
+BOOT=cdrom:\main.exe;1
+TCB=4
+EVENT=10
+STACK=801FFFF0
diff --git a/examples/system/timer/makefile b/examples/system/timer/makefile
index a8defe7..c418af4 100644
--- a/examples/system/timer/makefile
+++ b/examples/system/timer/makefile
@@ -1,35 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-TARGET = timer.elf
+## Settings
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+PSN00BSDK_LIBS ?= ../../../libpsn00b
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
-INCLUDE +=
-LIBDIRS +=
+# Project target name
+TARGET = timer
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Files
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
-CPPFLAGS = $(CFLAGS) -fno-exceptions
-AFLAGS = -g -msoft-float
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
+
+#all: iso
+all: build/$(TARGET)
+
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
+
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/examples/system/tty/makefile b/examples/system/tty/makefile
index 43893d5..381aa41 100644
--- a/examples/system/tty/makefile
+++ b/examples/system/tty/makefile
@@ -1,54 +1,65 @@
-include ../../examples-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+PSN00BSDK_LIBS ?= ../../../libpsn00b
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../../../psn00bsdk-setup.mk
# Project target name
-TARGET = tty.elf
+TARGET = tty
+
+## Files
# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
-# Determine object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-# Project specific include and library directories
-# (use -I for include dirs, -L for library dirs)
-INCLUDE +=
-LIBDIRS +=
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-# Libraries to link
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Build rules
-# C compiler flags
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+#all: iso
+all: build/$(TARGET)
-# C++ compiler flags
-CPPFLAGS = $(CFLAGS) -fno-exceptions
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
-# Assembler flags
-AFLAGS = -g -msoft-float
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
-# Linker flags
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/libpsn00b/include/dlfcn.h b/libpsn00b/include/dlfcn.h
new file mode 100644
index 0000000..5fdd343
--- /dev/null
+++ b/libpsn00b/include/dlfcn.h
@@ -0,0 +1,176 @@
+/*
+ * PSn00bSDK dynamic linker
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#ifndef __DLFCN_H
+#define __DLFCN_H
+
+#include <sys/types.h>
+#include <elf.h>
+
+/* Helper macro for setting $t9 before calling a function */
+
+#define DL_CALL(func, ...) { \
+ __asm__ volatile("move $t9, %0;" :: "r"(func) : "$t9"); \
+ func(__VA_ARGS__); \
+}
+
+/* Types */
+
+#define RTLD_DEFAULT ((DLL *) 0)
+
+typedef enum _DL_ResolveMode {
+ RTLD_LAZY = 1, // Resolve functions when they are first called (default)
+ RTLD_NOW = 2 // Resolve all symbols immediately on load
+} DL_ResolveMode;
+
+// Members of this struct should not be accessed directly in most cases, but
+// they are intentionally exposed for easier expandability.
+typedef struct _DLL {
+ void *ptr;
+ void *malloc_ptr;
+ size_t size;
+ const uint32_t *hash;
+ uint32_t *got;
+ Elf32_Sym *symtab;
+ const char *strtab;
+ uint16_t symbol_count;
+ uint16_t got_length;
+} DLL;
+
+/* API */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// TODO: rewrite these javadoc comments into proper documentation
+
+/**
+ * @brief Reads the symbol table from the provided string buffer (which may or
+ * may not be null-terminated), parses it and stores the parsed entries into a
+ * private hash table; the buffer won't be further referenced and can be safely
+ * deallocated after parsing. Returns the number of entries successfully parsed
+ * or -1 if an error occurred.
+ *
+ * This function expects the string buffer to contain one more lines, each of
+ * which must follow this format:
+ *
+ * <SYMBOL_NAME> <T|R|D|B> <HEX_ADDRESS> <HEX_SIZE> [DEBUG_INFO...]
+ *
+ * The "nm" tool included in the GCC toolchain can be used to generate a map
+ * file in the appropriate format after building the executable, by using this
+ * command:
+ *
+ * mipsel-unknown-elf-nm -f posix -l -n executable.elf >executable.map
+ *
+ * @param ptr
+ * @param size
+ * @return -1 or number of entries parsed
+ */
+int32_t DL_ParseSymbolMap(const char *ptr, size_t size);
+/**
+ * @brief File wrapper around DL_ParseSymbolMap(). Allocates a temporary buffer
+ * then loads the specified map file into it (using BIOS APIs) and calls
+ * DL_ParseSymbolMap() to parse it. The buffer is deallocated immediately after
+ * parsing.
+ *
+ * @param filename Must always contain device name, e.g. "cdrom:MODULE.DLL;1"
+ * @return -1 or number of entries parsed
+ */
+int32_t DL_LoadSymbolMap(const char *filename);
+/**
+ * @brief Frees internal buffers containing the currently loaded symbol map.
+ * This is automatically done before loading a new symbol map so there is no
+ * need to call this function in most cases, however it can still be useful to
+ * free up space on the heap once the symbol map is no longer needed.
+ */
+void DL_UnloadSymbolMap(void);
+/**
+ * @brief Queries the currently loaded symbol map for the symbol with the given
+ * name and returns a pointer to it, which can then be used to directly access
+ * the symbol. If the symbol can't be found, null is returned instead.
+ *
+ * @param name
+ * @return NULL or pointer to symbol (any type)
+ */
+void *DL_GetSymbolByName(const char *name);
+/**
+ * @brief Sets a custom function to be called for resolving symbols in DLLs.
+ * The function will be given a pointer to the current DLL and the unresolved
+ * symbol's name, and should return the address of the symbol in the executable
+ * (the dynamic linker will lock up if it returns null). Passing null instead
+ * of a function resets the default behavior of calling DL_GetSymbolByName() to
+ * find the symbol in the currently loaded symbol map.
+ *
+ * @param callback NULL or pointer to callback function
+ */
+void DL_SetResolveCallback(void *(*callback)(DLL *, const char *));
+
+/**
+ * @brief Initializes a buffer holding the contents of a dynamically-loaded
+ * library file (compiled with the dll.ld linker script and converted to a raw
+ * binary) *in-place*. A new DLL struct is allocated to store metadata but,
+ * unlike DL_ParseSymbolMap(), the DLL's actual code, data and tables are
+ * referenced directly from the provided buffer. The buffer must not be moved
+ * or deallocated, at least not before calling dlclose() on the DLL struct
+ * returned by this function.
+ *
+ * The third argument specifies when symbols in the DLL should be resolved.
+ * Setting it to RTLD_LAZY defers resolution of undefined functions to when
+ * they are first called, while RTLD_DEFAULT forces all symbols to be resolved
+ * immediately. If a custom resolver has been set via DL_SetResolveCallback(),
+ * it will be called for each symbol to resolve.
+ *
+ * @param ptr
+ * @param size
+ * @param mode RTLD_LAZY or RTLD_NOW
+ * @return NULL or pointer to a new DLL struct
+ */
+DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode);
+/**
+ * @brief File wrapper around dlinit(). Allocates a new buffer, loads the
+ * specified file into it (using BIOS APIs) and calls dlinit() on that. When
+ * calling dlclose() on a DLL loaded from a file, the file buffer is
+ * automatically destroyed.
+ *
+ * @param filename Must always contain device name, e.g. "cdrom:MODULE.DLL;1"
+ * @param mode RTLD_LAZY or RTLD_NOW
+ * @return NULL or pointer to a new DLL struct
+ */
+DLL *dlopen(const char *filename, DL_ResolveMode mode);
+/**
+ * @brief Destroys a loaded DLL by calling its global destructors and freeing
+ * the buffer it's loaded in. Any pointer passed to dlclose() should no longer
+ * be used after the call. If the DLL was initialized in-place using dlinit(),
+ * dlclose() will *NOT* free the buffer initially passed to dlinit().
+ *
+ * @param dll
+ */
+void dlclose(DLL *dll);
+/**
+ * @brief Returns a pointer to the DLL symbol with the given name, or null if
+ * it can't be found. If null or RTLD_DEFAULT is passed as first argument, the
+ * executable itself is searched instead using the symbol map (behaving the
+ * same as DL_GetSymbolByName()).
+ *
+ * @param dll DLL struct or RTLD_DEFAULT
+ * @param name
+ * @return NULL or pointer to symbol (any type)
+ */
+void *dlsym(DLL *dll, const char *name);
+/**
+ * @brief Returns a string describing the last error that occurred, or null if
+ * no error has occurred since the last call to dlerror() (i.e. calling this
+ * also resets the internal error flags).
+ *
+ * @return NULL or pointer to const string
+ */
+const char *const dlerror(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libpsn00b/include/elf.h b/libpsn00b/include/elf.h
new file mode 100644
index 0000000..b4c4408
--- /dev/null
+++ b/libpsn00b/include/elf.h
@@ -0,0 +1,138 @@
+/*
+ * PSn00bSDK dynamic linker
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * This file is used internally by the dynamic linker to parse the "header"
+ * (.dynamic and .dynsym sections) of dynamically-linked libraries built with
+ * the provided linker script. Most of it is copied from the standard Unix
+ * elf.h header, with the only changes being removed typedefs and #defines
+ * converted to enums.
+ */
+
+#ifndef __ELF_H
+#define __ELF_H
+
+#include <sys/types.h>
+
+typedef enum {
+ DT_NULL = 0, /* Marks end of dynamic section */
+ DT_NEEDED = 1, /* Name of needed library */
+ DT_PLTRELSZ = 2, /* Size in bytes of PLT relocs */
+ DT_PLTGOT = 3, /* Processor defined value */
+ DT_HASH = 4, /* Address of symbol hash table */
+ DT_STRTAB = 5, /* Address of string table */
+ DT_SYMTAB = 6, /* Address of symbol table */
+ DT_RELA = 7, /* Address of Rela relocs */
+ DT_RELASZ = 8, /* Total size of Rela relocs */
+ DT_RELAENT = 9, /* Size of one Rela reloc */
+ DT_STRSZ = 10, /* Size of string table */
+ DT_SYMENT = 11, /* Size of one symbol table entry */
+ DT_INIT = 12, /* Address of init function */
+ DT_FINI = 13, /* Address of termination function */
+ DT_SONAME = 14, /* Name of shared object */
+ DT_RPATH = 15, /* Library search path (deprecated) */
+ DT_SYMBOLIC = 16, /* Start symbol search here */
+ DT_REL = 17, /* Address of Rel relocs */
+ DT_RELSZ = 18, /* Total size of Rel relocs */
+ DT_RELENT = 19, /* Size of one Rel reloc */
+ DT_PLTREL = 20, /* Type of reloc in PLT */
+ DT_DEBUG = 21, /* For debugging; unspecified */
+ DT_TEXTREL = 22, /* Reloc might modify .text */
+ DT_JMPREL = 23, /* Address of PLT relocs */
+ DT_BIND_NOW = 24, /* Process relocations of object */
+ DT_INIT_ARRAY = 25, /* Array with addresses of init fct */
+ DT_FINI_ARRAY = 26, /* Array with addresses of fini fct */
+ DT_INIT_ARRAYSZ = 27, /* Size in bytes of DT_INIT_ARRAY */
+ DT_FINI_ARRAYSZ = 28, /* Size in bytes of DT_FINI_ARRAY */
+ DT_RUNPATH = 29, /* Library search path */
+ DT_FLAGS = 30, /* Flags for the object being loaded */
+ DT_ENCODING = 32, /* Start of encoded range */
+ DT_PREINIT_ARRAY = 32, /* Array with addresses of preinit fct*/
+ DT_PREINIT_ARRAYSZ = 33, /* size in bytes of DT_PREINIT_ARRAY */
+ DT_SYMTAB_SHNDX = 34, /* Address of SYMTAB_SHNDX section */
+ DT_NUM = 35, /* Number used */
+ DT_LOOS = 0x6000000d, /* Start of OS-specific */
+ DT_HIOS = 0x6ffff000, /* End of OS-specific */
+ DT_LOPROC = 0x70000000, /* Start of processor-specific */
+ DT_HIPROC = 0x7fffffff, /* End of processor-specific */
+
+ DT_MIPS_RLD_VERSION = 0x70000001,
+ DT_MIPS_FLAGS = 0x70000005,
+ DT_MIPS_BASE_ADDRESS = 0x70000006,
+ DT_MIPS_LOCAL_GOTNO = 0x7000000a,
+ DT_MIPS_SYMTABNO = 0x70000011,
+ DT_MIPS_UNREFEXTNO = 0x70000012,
+ DT_MIPS_GOTSYM = 0x70000013,
+ DT_MIPS_HIPAGENO = 0x70000014
+} Elf32_d_tag;
+
+typedef enum {
+ RHF_NONE = 0, /* No flags */
+ RHF_QUICKSTART = 1, /* Use quickstart */
+ RHF_NOTPOT = 2, /* Hash size not power of 2 */
+ RHF_NO_LIBRARY_REPLACEMENT = 4 /* Ignore LD_LIBRARY_PATH */
+} Elf32_d_MIPS_FLAGS;
+
+typedef struct {
+ Elf32_d_tag d_tag; /* Dynamic entry type */
+ union {
+ uint32_t d_val; /* Integer value */
+ void *d_ptr; /* Address value */
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+ uint32_t st_name; /* Symbol name (string tbl index) */
+ void *st_value; /* Symbol value */
+ size_t st_size; /* Symbol size */
+ uint8_t st_info; /* Symbol type and binding */
+ uint8_t st_other; /* Symbol visibility */
+ uint16_t st_shndx; /* Section index */
+} Elf32_Sym;
+
+#define ELF32_ST_BIND(val) ((Elf32_st_bind) (((uint8_t) (val)) >> 4))
+#define ELF32_ST_TYPE(val) ((Elf32_st_type) ((val) & 0xf))
+#define ELF32_ST_INFO(bind, type) ((((uint8_t) (bind)) << 4) + (((uint8_t) (type)) & 0xf))
+
+typedef enum {
+ STB_LOCAL = 0, /* Local symbol */
+ STB_GLOBAL = 1, /* Global symbol */
+ STB_WEAK = 2, /* Weak symbol */
+ STB_NUM = 3, /* Number of defined types. */
+ STB_LOOS = 10, /* Start of OS-specific */
+ STB_GNU_UNIQUE = 10, /* Unique symbol. */
+ STB_HIOS = 12, /* End of OS-specific */
+ STB_LOPROC = 13, /* Start of processor-specific */
+ STB_HIPROC = 15 /* End of processor-specific */
+} Elf32_st_bind;
+
+typedef enum {
+ STT_NOTYPE = 0, /* Symbol type is unspecified */
+ STT_OBJECT = 1, /* Symbol is a data object */
+ STT_FUNC = 2, /* Symbol is a code object */
+ STT_SECTION = 3, /* Symbol associated with a section */
+ STT_FILE = 4, /* Symbol's name is file name */
+ STT_COMMON = 5, /* Symbol is a common data object */
+ STT_TLS = 6, /* Symbol is thread-local data object*/
+ STT_NUM = 7, /* Number of defined types. */
+ STT_LOOS = 10, /* Start of OS-specific */
+ STT_GNU_IFUNC = 10, /* Symbol is indirect code object */
+ STT_HIOS = 12, /* End of OS-specific */
+ STT_LOPROC = 13, /* Start of processor-specific */
+ STT_HIPROC = 15 /* End of processor-specific */
+} Elf32_st_type;
+
+// If you need to add more constants, you may use the following Python snippet
+// to quickly convert #defines to enums:
+/*
+import re
+t = """<paste #defines here>"""
+t = re.sub(
+ r"(0x[0-9a-f]+|0b[01]+|[0-9]+)",
+ lambda m: f"= {m.group(1)},",
+ t.replace("#define ", "\t").replace("#define\t", "\t")
+)
+print("typedef enum {\n" + t + "\n} NAME;")
+*/
+
+#endif
diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h
index c366702..9e92568 100644
--- a/libpsn00b/include/psxapi.h
+++ b/libpsn00b/include/psxapi.h
@@ -180,6 +180,7 @@ void ChangeClearRCnt(int t, int m);
// Executable functions
int Exec(struct EXEC *exec, int argc, char **argv);
+void FlushCache(void);
void _boot(void);
diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h
index ddb4522..f50b841 100644
--- a/libpsn00b/include/psxgpu.h
+++ b/libpsn00b/include/psxgpu.h
@@ -1,6 +1,8 @@
#ifndef __PSXGPU_H
#define __PSXGPU_H
+#include <sys/types.h>
+
// Low-level display parameters for DISPENV_RAW. A leftover from prototyping
#define DISP_WIDTH_256 0
#define DISP_WIDTH_320 1
diff --git a/libpsn00b/include/stdio.h b/libpsn00b/include/stdio.h
index cf1909d..97a2f5a 100644
--- a/libpsn00b/include/stdio.h
+++ b/libpsn00b/include/stdio.h
@@ -56,6 +56,9 @@ int vsprintf(char *string, const char *fmt, va_list ap);
int sprintf(char *string, const char *fmt, ...);
int snprintf(char *string, unsigned int size, const char *fmt, ...);
+int vsscanf(const char *str, const char *format, va_list ap);
+int sscanf(const char *str, const char *fmt, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpsn00b/ldscripts/dll.ld b/libpsn00b/ldscripts/dll.ld
new file mode 100644
index 0000000..59cbb53
--- /dev/null
+++ b/libpsn00b/ldscripts/dll.ld
@@ -0,0 +1,122 @@
+/*
+ * PSn00bSDK linker script for dynamically-loaded libraries
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * This script is similar to the one for executables. The main differences are
+ * the header at the beginning of the file, the .sdata/.sbss sections being
+ * replaced by the global offset table (GOT) and .bss being merged with .data.
+ */
+
+OUTPUT_FORMAT(elf32-littlemips)
+/*ENTRY(_start)
+STARTUP(start.o)*/
+
+MEMORY {
+ /* Code is position-independent, so we just set zero as address */
+ RELOC_RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 1M
+}
+
+SECTIONS {
+ /*
+ * DLL "header", containing the following sections:
+ *
+ * .dynamic: key-value pairs describing various section offsets, flags and
+ * other stuff
+ * .dynsym: dynamic symbol table, listing all functions to relocate as well
+ * as exported symbols
+ * .hash: pre-generated hash table to quickly look up symbol table
+ * entries by their names
+ * .dynstr: string blob referenced by symbol table entries
+ */
+
+ .dynamic : { *(.dynamic) } > RELOC_RAM
+ .dynsym : { *(.dynsym) } > RELOC_RAM
+ .hash : { *(.hash) } > RELOC_RAM
+ .dynstr : { *(.dynstr) } > RELOC_RAM
+
+ /* Text section, i.e. code and constants */
+
+ .text : ALIGN(16) {
+ __text_start = .;
+
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.plt .MIPS.stubs)
+ } > RELOC_RAM
+ .rodata : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ } > RELOC_RAM
+
+ /* Global constructor and destructor arrays (length-prefixed) */
+
+ /*
+ * https://sourceware.org/binutils/docs/ld/Output-Section-Keywords.html
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770
+ */
+ .ctors : ALIGN(16) {
+ __CTOR_LIST__ = .;
+
+ LONG(((__CTOR_END__ - __CTOR_LIST__) / 4) - 2)
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ LONG(0)
+
+ __CTOR_END__ = .;
+ } > RELOC_RAM
+ .dtors : ALIGN(16) {
+ __DTOR_LIST__ = .;
+
+ LONG(((__DTOR_END__ - __DTOR_LIST__) / 4) - 2)
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ LONG(0)
+
+ __DTOR_END__ = .;
+ } > RELOC_RAM
+
+ /* Data and BSS sections, i.e. variables */
+
+ .data : {
+ *(.data .data.* .gnu.linkonce.d.*)
+
+ /*
+ * Merge the .bss section into the .data section, so uninitialized
+ * variables are treated as if they were initialized and preallocated.
+ * This makes DLLs unnecessarily larger (BSS values shouldn't be stored
+ * as they are always zero) but greatly simplifies the dynamic linker,
+ * as we don't have to worry about managing .bss separately from the
+ * main DLL blob.
+ */
+ __bss_start = .;
+
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+
+ . = ALIGN((. != 0) ? 4 : 1);
+ } > RELOC_RAM
+
+ /*
+ * Set _gp to point to the beginning of the GOT plus 0x7ff0, so anything
+ * within the GOT can be accessed using the $gp register as base plus a
+ * signed 16-bit immediate. Note that $gp is set to _gp in all exported
+ * functions (GCC adds the relevant code automatically).
+ */
+ HIDDEN(_gp = ALIGN(16) + 0x7ff0);
+
+ .got : {
+ *(.got)
+ } > RELOC_RAM
+
+ _end = .;
+
+ /* Dummy section */
+
+ .dummy (NOLOAD) : {
+ KEEP(*(.dummy))
+ } > RELOC_RAM
+
+ /* Remove anything flagged as link-time optimized */
+
+ /DISCARD/ : {
+ *(.gnu.lto_*)
+ }
+}
diff --git a/libpsn00b/ldscripts/exe.ld b/libpsn00b/ldscripts/exe.ld
new file mode 100644
index 0000000..3033636
--- /dev/null
+++ b/libpsn00b/ldscripts/exe.ld
@@ -0,0 +1,114 @@
+/*
+ * PSn00bSDK linker script for executables
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * GP-relative addressing (i.e. placing small variables in a 64 KB block and
+ * using $gp to reference them) is fully supported; the block is made up of
+ * sections .sdata and .sbss. Note that GP-relative addressing is not
+ * compatible with dynamic linking, as DLLs require GP to be unused.
+ */
+
+OUTPUT_FORMAT(elf32-littlemips)
+ENTRY(_start)
+/*STARTUP(start.o)*/
+
+MEMORY {
+ /* Mapped into KSEG0 */
+ KERNEL_RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x010000
+ APP_RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x1f0000
+}
+
+SECTIONS {
+ /* Text section, i.e. code and constants */
+
+ .text : {
+ __text_start = .;
+
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.plt .MIPS.stubs)
+ } > APP_RAM
+ .rodata : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ } > APP_RAM
+
+ /* Global constructor and destructor arrays (length-prefixed) */
+
+ /*
+ * TODO: replace this crap with .init_array and .fini_array, which are the
+ * "modern" way of doing it without reversed arrays and weird length
+ * prefixes. That would require even more patching though.
+ *
+ * https://sourceware.org/binutils/docs/ld/Output-Section-Keywords.html
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770
+ */
+ .ctors : ALIGN(16) {
+ __CTOR_LIST__ = .;
+
+ LONG(((__CTOR_END__ - __CTOR_LIST__) / 4) - 2)
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ LONG(0)
+
+ __CTOR_END__ = .;
+ } > APP_RAM
+ .dtors : ALIGN(16) {
+ __DTOR_LIST__ = .;
+
+ LONG(((__DTOR_END__ - __DTOR_LIST__) / 4) - 2)
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ LONG(0)
+
+ __DTOR_END__ = .;
+ } > APP_RAM
+
+ /* Data sections, i.e. variables with default values */
+
+ .data : {
+ *(.data .data.* .gnu.linkonce.d.*)
+ } > APP_RAM
+
+ /*
+ * Set _gp to point to the beginning of .sdata plus 0x7ff0, so anything
+ * within .sdata (and .sbss) can be accessed using the $gp register as
+ * base plus a signed 16-bit immediate. Note that $gp is set to _gp on
+ * boot by _start() in the SDK.
+ */
+ HIDDEN(_gp = ALIGN(16) + 0x7ff0);
+
+ .sdata : {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ } > APP_RAM
+
+ /* BSS sections, i.e. uninitialized variables */
+
+ __bss_start = .;
+
+ .sbss (NOLOAD) : {
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ } > APP_RAM
+ .bss (NOLOAD) : {
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+
+ /*
+ * This crap was in the stock GCC linker script.
+ */
+ . = ALIGN((. != 0) ? 4 : 1);
+ } > APP_RAM
+
+ _end = .;
+
+ /* Dummy section */
+
+ .dummy (NOLOAD) : {
+ KEEP(*(.dummy))
+ } > APP_RAM
+
+ /* Remove anything flagged as link-time optimized */
+
+ /DISCARD/ : {
+ *(.gnu.lto_*)
+ }
+}
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]();
+}
diff --git a/libpsn00b/lzp/makefile b/libpsn00b/lzp/makefile
index 729a500..02654ed 100644
--- a/libpsn00b/lzp/makefile
+++ b/libpsn00b/lzp/makefile
@@ -1,40 +1,59 @@
-# 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 = liblzp.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-CFILES = $(notdir $(wildcard ./*.c))
-OFILES = $(addprefix build/,$(CFILES:.c=.o))
+# Project target name
+TARGET = liblzp.a
-CFLAGS = -g -O2 -msoft-float -fno-builtin -nostdlib -fdata-sections \
- -ffunction-sections -Wa,--strip-local-absolute
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-all: $(TARGET)
+## Build rules
+
+all: build/$(TARGET)
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(OFILES)
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
-
build/%.o: %.c
- @mkdir -p build
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS_LIB) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cxx
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS_LIB) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(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 $(OFILES) $(TARGET)
+ rm -rf build
diff --git a/libpsn00b/psxapi/makefile b/libpsn00b/psxapi/makefile
index 0b0d603..f300e5f 100644
--- a/libpsn00b/psxapi/makefile
+++ b/libpsn00b/psxapi/makefile
@@ -1,41 +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 = libpsxapi.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-SOURCES = stdio fs sys
+# Project target name
+TARGET = libpsxapi.a
-AFILES = $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.s))
-OFILES = $(addprefix build/,$(AFILES:.s=.o))
+## Files
-AFLAGS = -g -msoft-float -Wa,--strip-local-absolute
+SOURCES = stdio fs sys
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
+CXXFILES= $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.cxx))
+AFILES = $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-all: $(TARGET)
-
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+## Build rules
+
+all: build/$(TARGET)
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(OFILES)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS_LIB) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cxx
+ @mkdir -p $(dir $@)
+ $(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/psxapi/sys/flushcache.s b/libpsn00b/psxapi/sys/flushcache.s
new file mode 100644
index 0000000..7eeb510
--- /dev/null
+++ b/libpsn00b/psxapi/sys/flushcache.s
@@ -0,0 +1,10 @@
+.set noreorder
+
+.section .text
+
+.global FlushCache
+.type FlushCache, @function
+FlushCache:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x44
diff --git a/libpsn00b/psxcd/makefile b/libpsn00b/psxcd/makefile
index cf1eda5..ee9b958 100644
--- a/libpsn00b/psxcd/makefile
+++ b/libpsn00b/psxcd/makefile
@@ -1,46 +1,59 @@
-# 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 = libpsxcd.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-CFILES = $(notdir $(wildcard ./*.c))
-AFILES = $(notdir $(wildcard ./*.s))
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+# Project target name
+TARGET = libpsxcd.a
-CFLAGS = -g -msoft-float -fno-builtin -fdata-sections \
- -ffunction-sections -Wa,--strip-local-absolute
-AFLAGS = -g -msoft-float -Wa,--strip-local-absolute
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
-all: $(TARGET)
+all: build/$(TARGET)
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(OFILES)
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) -O2 $(CFLAGS) $(INCLUDE) -c $< -o $@
+ $(CC) $(CFLAGS_LIB) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cxx
+ @mkdir -p $(dir $@)
+ $(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/psxetc/_dl_resolve_wrapper.s b/libpsn00b/psxetc/_dl_resolve_wrapper.s
new file mode 100644
index 0000000..069ee84
--- /dev/null
+++ b/libpsn00b/psxetc/_dl_resolve_wrapper.s
@@ -0,0 +1,54 @@
+# PSn00bSDK dynamic linker
+# (C) 2021 spicyjpeg - MPL licensed
+#
+# This function is called by the lazy loader stubs generated by GCC in the
+# .plt/.MIPS.stubs section when attempting to call a GOT entry whose address
+# hasn't yet been resolved. The generated stubs conform to the MIPS ABI and
+# uses the following registers to pass the following parameters:
+# - $t7 = address the resolved function should return to (i.e. $ra of the
+# caller that triggered the stub)
+# - $t8 = index of the function in the .dynsym symbol table
+# - $t9 = _dl_resolve_wrapper itself's address
+
+.set noreorder
+.section .text
+
+.global _dl_resolve_wrapper
+.type _dl_resolve_wrapper, @function
+_dl_resolve_wrapper:
+ # Push the registers we're going to use onto the stack.
+ addiu $sp, -16
+ sw $a0, 0($sp)
+ sw $a1, 4($sp)
+ sw $v0, 8($sp)
+ sw $t7, 12($sp) # (will be restored directly to $ra)
+
+ # Figure out where the DLL's struct is. dlinit() places a pointer to the
+ # struct in the second GOT entry, so it's just a matter of indexing the GOT
+ # using GP. Then call _dl_resolve_helper with the struct and $t8 as
+ # arguments, and store the return value into $t0.
+ lw $a0, -0x7fec($gp) # sizeof(uint32_t) - 0x7ff0 (see dll.ld)
+ move $a1, $t8
+
+ jal _dl_resolve_helper
+ addiu $sp, -8 # (branch delay)
+ addiu $sp, 8
+
+ move $t0, $v0
+
+ # Restore registers from the stack and tail-call the function at the
+ # address returned by the resolver. This will cause the resolved function
+ # to run and return directly to the code that called the stub.
+ lw $a0, 0($sp)
+ lw $a1, 4($sp)
+ lw $v0, 8($sp)
+ lw $ra, 12($sp)
+ addiu $sp, 16
+
+ jr $t0
+ nop
+
+.global _dl_credits
+.type _dl_credits, @object
+_dl_credits:
+ .asciiz "psxetc runtime dynamic linker by spicyjpeg\n"
diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c
new file mode 100644
index 0000000..1485183
--- /dev/null
+++ b/libpsn00b/psxetc/dl.c
@@ -0,0 +1,665 @@
+/*
+ * PSn00bSDK dynamic linker
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * The bulk of this code is MIPS-specific but not PS1-specific, so the whole
+ * dynamic linker could be ported to other MIPS platforms that do not have one
+ * in their OS/SDK (e.g. N64, PIC32 microcontrollers). Note that, despite the
+ * various ELF references, I did *not* implement a full ELF file parser: this
+ * implementation just expects all library files to begin with several metadata
+ * sections (.dynamic, .dynsym, .hash, .dynstr) laid out in a fixed order. Use
+ * the dll.ld linker script to generate compatible libraries.
+ *
+ * Most of the stuff implemented here, despite looking like black magic, is
+ * actually well-documented across several PDFs scattered around the internet:
+ * - http://www.sco.com/developers/devspecs/gabi41.pdf
+ * - http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf
+ * - http://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf
+ *
+ * TODO:
+ * - Clean up duplicated code, especially hash-table-related loops
+ * - Fix bugs and improve allocation checks
+ * - Find a way to predict the smallest ELF hash table size for a certain set
+ * of entries
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <elf.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <psxapi.h>
+
+/* Compile options */
+
+// Uncomment before building to enable debug logging (via printf()).
+#define DEBUG
+
+// Comment before building to disable functions that rely on BIOS file APIs,
+// i.e. DL_LoadSymbolMap() and dlopen().
+#define USE_FILE_API
+
+/* Private types */
+
+typedef struct {
+ uint32_t hash;
+ void *ptr;
+} MapEntry;
+
+typedef enum {
+ ERR_NONE,
+ ERR_FILE,
+ ERR_FILE_MALLOC,
+ ERR_FILE_READ,
+ ERR_NO_MAP,
+ ERR_MAP_MALLOC,
+ ERR_NO_SYMBOLS,
+ ERR_DLL_NULL,
+ ERR_DLL_MALLOC,
+ ERR_DLL_FORMAT,
+ ERR_NO_FILE_API,
+ ERR_MAP_SYMBOL,
+ ERR_DLL_SYMBOL
+} ErrorCode;
+
+/* Data */
+
+static const char *const DL_ERROR_MESSAGES[] = {
+ "Unable to find file",
+ "Unable to allocate buffer to load file into",
+ "Failed to read file",
+ "No symbol map has been loaded yet",
+ "Unable to allocate symbol map structures",
+ "No symbols found in symbol map",
+ "Unable to initialize DLL from null pointer",
+ "Unable to allocate DLL metadata structures",
+ "Unsupported DLL type or format",
+ "psxetc has been built without file support",
+ "Symbol not found in symbol map",
+ "Symbol not found in DLL"
+};
+
+static ErrorCode _error_code = ERR_NONE;
+static uint32_t *_map_hash_table = 0;
+static MapEntry *_map_entry_table = 0;
+
+// Accessed by _dl_resolve_helper, stores the pointer to the current resolver
+// function. Can be changed using DL_SetResolveCallback().
+void *(*_dl_resolve_callback)(DLL *, const char *) = 0;
+
+/* Private utilities */
+
+#ifdef DEBUG
+#define _LOG(...) printf(__VA_ARGS__)
+#define _ERROR(code, ret) { \
+ _LOG("psxetc: ERROR! %s\n", DL_ERROR_MESSAGES[code - 1]); \
+ _error_code = code; \
+ return ret; \
+}
+#else
+#define _LOG(...)
+#define _ERROR(code, ret) { \
+ _error_code = code; \
+ return ret; \
+}
+#endif
+
+void _dl_resolve_wrapper(void);
+
+// Called by _dl_resolve_wrapper() (which is in turn called by GCC stubs) to
+// resolve a function.
+void *_dl_resolve_helper(DLL *dll, uint32_t index) {
+ Elf32_Sym *sym = &(dll->symtab[index]);
+ const char *_name = &(dll->strtab[sym->st_name]);
+ void *address;
+
+ if (_dl_resolve_callback)
+ address = _dl_resolve_callback(dll, _name);
+ else
+ address = DL_GetSymbolByName(_name);
+
+ if (!address) {
+ _LOG("psxetc: FATAL! Can't resolve %s, locking up\n", _name);
+ while (1)
+ __asm__ volatile("nop");
+ }
+
+ // Patch the GOT entry to "cache" the resolved address. This can probably
+ // be implemented in a faster way, but this thing is already too complex.
+ for (uint32_t i = 0; i < dll->got_length; i++) {
+ if (dll->got[2 + i] == (uint32_t) sym->st_value) {
+ dll->got[2 + i] = (uint32_t) address;
+ break;
+ }
+ }
+
+ return address;
+}
+
+// Implementation of the weird obscure hashing function used in the ELF .hash
+// section. Not sure how collision-prone this is.
+// https://en.wikipedia.org/wiki/PJW_hash_function
+static uint32_t _elf_hash(const char *str) {
+ uint32_t value = 0;
+
+ while (*str) {
+ value <<= 4;
+ value += (uint32_t) *(str++);
+
+ uint32_t nibble = value & 0xf0000000;
+ if (nibble)
+ value ^= nibble >> 24;
+
+ value &= ~nibble;
+ }
+
+ return value;
+}
+
+#ifdef USE_FILE_API
+static uint8_t *_load_file(const char *filename, size_t *size_output) {
+ int32_t fd = open(filename, 1);
+ if (fd < 0)
+ _ERROR(ERR_FILE, 0);
+
+ // Extract file size from the file's associated control block.
+ // https://problemkaputt.de/psx-spx.htm#biosmemorymap
+ FCB *fcb = (FCB *) *((FCB **) 0x80000140);
+ size_t size = fcb[fd].filesize;
+
+ uint8_t *buffer = malloc(size);
+ if (!buffer)
+ _ERROR(ERR_FILE_MALLOC, 0);
+
+ _LOG("psxetc: Loading %s (%d bytes)..", filename, size);
+
+ for (uint32_t offset = 0; offset < size; ) {
+ int32_t length = read(fd, &(buffer[offset]), 0x800);
+
+ if (length <= 0) {
+ close(fd);
+ free(buffer);
+ _ERROR(ERR_FILE_READ, 0);
+ }
+
+ _LOG(".");
+ offset += length;
+ }
+
+ close(fd);
+ _LOG(" done\n");
+
+ if (size_output)
+ *size_output = size;
+ return buffer;
+}
+#endif
+
+/* Symbol map loading/parsing API */
+
+int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
+ DL_UnloadSymbolMap();
+
+ // Perform a quick scan over the entire map text and count the number of
+ // newlines. This allows us to (over)estimate the number of entries and
+ // allocate a sufficiently large hash/entry table.
+ uint32_t entries = 0;
+ for (uint32_t pos = 0; pos < size; pos++) {
+ if (ptr[pos] == '\n')
+ entries++;
+ }
+
+ // TODO: find a way to calculate the optimal number of hash table "buckets"
+ // in order to minimize hash table size
+ uint32_t nbucket = entries;
+ _LOG("psxetc: Predicted %d entries, %d hash buckets\n", entries, nbucket);
+
+ // Allocate an entry table to store parsed symbols in, and an associated
+ // hash table (same format as .hash section, with 8-byte header).
+ _map_hash_table = malloc(sizeof(uint32_t) * (2 + nbucket + entries));
+ _map_entry_table = malloc(sizeof(MapEntry) * entries);
+ if (!_map_hash_table || !_map_entry_table)
+ _ERROR(ERR_MAP_MALLOC, -1);
+
+ _map_hash_table[0] = nbucket;
+ _map_hash_table[1] = entries;
+ for (uint32_t i = 0; i < (nbucket + entries); i++)
+ _map_hash_table[2 + i] = 0xffffffff;
+
+ // Go again through the symbol map and fill in the hash table.
+ uint32_t index = 0;
+ for (uint32_t pos = 0; (pos < size) && ptr[pos]; pos++) {
+ char name[64];
+ char type_string[2];
+ uint64_t address64;
+ size_t _size;
+
+ // e.g. "main T ffffffff80000000 100 ...\n"
+ int32_t parsed = sscanf(
+ &(ptr[pos]),
+ "%63s %1s %Lx %x",
+ name,
+ type_string,
+ &address64,
+ &_size // Optional, unused (yet)
+ );
+
+ if (parsed >= 3) {
+ // Drop the upper 32 bits of the address (for some reason MIPS nm
+ // insists on printing 64-bit addresses... wtf) and normalize the
+ // type letter to upper case, then check if the entry is valid and
+ // non-null.
+ void *address = (void *) address64;
+ char _type = toupper(type_string[0]);
+ uint32_t hash = _elf_hash(name);
+ uint32_t hash_mod = hash % nbucket;
+
+ if (address && (
+ (_type == 'T') || // .text
+ (_type == 'R') || // .rodata
+ (_type == 'D') || // .data
+ (_type == 'B') // .bss
+ )) {
+ _LOG(
+ "psxetc: Map sym: %08x,%08x [%c %s]\n",
+ address,
+ _size,
+ _type,
+ name
+ );
+
+ MapEntry *entry = &(_map_entry_table[index]);
+ entry->hash = hash;
+ entry->ptr = address;
+
+ // Append a reference to the entry to the hash table's chain
+ // for the current hash_mod. I can't explain this properly.
+ uint32_t *hash_entry = &(_map_hash_table[2 + hash_mod]);
+ while (*hash_entry != 0xffffffff)
+ hash_entry = &(_map_hash_table[2 + nbucket + *hash_entry]);
+
+ *hash_entry = index;
+ index++;
+ }
+ }
+
+ // Skip the line by advancing the pointer until a newline is found. The
+ // for loop will then skip the newline itself.
+ while ((pos < size) && (ptr[pos] != '\n'))
+ pos++;
+ }
+
+ _LOG("psxetc: Parsed %d symbols from map\n", entries);
+ if (!entries)
+ _ERROR(ERR_NO_SYMBOLS, -1);
+
+ return entries;
+}
+
+int32_t DL_LoadSymbolMap(const char *filename) {
+#ifdef USE_FILE_API
+ size_t size;
+ char *ptr = _load_file(filename, &size);
+ if (!ptr)
+ return -1;
+
+ int32_t entries = DL_ParseSymbolMap(ptr, size);
+ free(ptr);
+
+ return entries;
+#else
+ _ERROR(ERR_NO_FILE_API, -1);
+#endif
+}
+
+void DL_UnloadSymbolMap(void) {
+ if (!_map_hash_table)
+ return;
+
+ free(_map_hash_table);
+ free(_map_entry_table);
+ _map_hash_table = 0;
+}
+
+void *DL_GetSymbolByName(const char *name) {
+ if (!_map_hash_table)
+ _ERROR(ERR_NO_MAP, 0);
+
+ // https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-48031.html
+ uint32_t nbucket = _map_hash_table[0];
+ uint32_t hash = _elf_hash(name);
+ uint32_t hash_mod = hash % nbucket;
+
+ // Go through the hash table's chain until the symbol hash matches the one
+ // calculated.
+ for (uint32_t i = _map_hash_table[2 + hash_mod]; i;) {
+ MapEntry *entry = &(_map_entry_table[i]);
+
+ if (hash == entry->hash) {
+ _LOG("psxetc: Map lookup [%s = %08x]\n", name, entry->ptr);
+ return entry->ptr;
+ }
+
+ i = _map_hash_table[2 + nbucket + i];
+ }
+
+ _ERROR(ERR_MAP_SYMBOL, 0);
+}
+
+void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)) {
+ _dl_resolve_callback = callback;
+}
+
+/* Library loading and linking API */
+
+DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
+ if (!ptr)
+ _ERROR(ERR_DLL_NULL, 0);
+
+ DLL *dll = malloc(sizeof(DLL));
+ if (!dll)
+ _ERROR(ERR_DLL_MALLOC, 0);
+
+ dll->ptr = ptr;
+ dll->malloc_ptr = 0;
+ dll->size = size;
+ _LOG("psxetc: Initializing DLL at %08x\n", ptr);
+
+ // Interpret the key-value pairs in the .dynamic section to obtain info
+ // about all the other sections. The pairs are null-terminated, which makes
+ // parsing trivial.
+ uint32_t local_got_len = 0;
+ uint32_t first_got_sym = 0;
+
+ for (Elf32_Dyn *dyn = (Elf32_Dyn *) ptr; dyn->d_tag; dyn++) {
+ _LOG("psxetc: .dynamic %08x=%08x ", dyn->d_tag, dyn->d_un.d_val);
+
+ switch (dyn->d_tag) {
+ // Offset of .got section
+ case DT_PLTGOT:
+ _LOG("[PLTGOT]\n");
+
+ dll->got = (void *) (ptr + dyn->d_un.d_val);
+ break;
+
+ // Offset of .hash section
+ case DT_HASH:
+ _LOG("[HASH]\n");
+
+ dll->hash = (void *) (ptr + dyn->d_un.d_val);
+ break;
+
+ // Offset of .dynstr (NOT .strtab) section
+ case DT_STRTAB:
+ _LOG("[STRTAB]\n");
+
+ dll->strtab = (void *) (ptr + dyn->d_un.d_val);
+ break;
+
+ // Offset of .dynsym (NOT .symtab) section
+ case DT_SYMTAB:
+ _LOG("[SYMTAB]\n");
+
+ dll->symtab = (void *) (ptr + dyn->d_un.d_val);
+ break;
+
+ // Length of .dynstr section
+ //case DT_STRSZ:
+ //_LOG("[STRSZ]\n");
+ //break;
+
+ // Length of each .dynsym entry
+ case DT_SYMENT:
+ _LOG("[SYMENT]\n");
+
+ // Only 16-byte symbol table entries are supported.
+ if (dyn->d_un.d_val != sizeof(Elf32_Sym)) {
+ free(dll);
+ _ERROR(ERR_DLL_FORMAT, 0);
+ }
+ break;
+
+ // MIPS ABI (?) version
+ case DT_MIPS_RLD_VERSION:
+ _LOG("[MIPS_RLD_VERSION]\n");
+
+ // Versions other than 1 are unsupported (do they even exist?).
+ if (dyn->d_un.d_val != 1) {
+ free(dll);
+ _ERROR(ERR_DLL_FORMAT, 0);
+ }
+ break;
+
+ // DLL/ABI flags
+ case DT_MIPS_FLAGS:
+ _LOG("[MIPS_FLAGS]\n");
+
+ // Shortcut pointers (whatever they are) are not supported.
+ if (dyn->d_un.d_val & RHF_QUICKSTART) {
+ free(dll);
+ _ERROR(ERR_DLL_FORMAT, 0);
+ }
+ break;
+
+ // Number of local (not to resolve) GOT entries
+ case DT_MIPS_LOCAL_GOTNO:
+ _LOG("[MIPS_LOCAL_GOTNO]\n");
+
+ local_got_len = dyn->d_un.d_val;
+ break;
+
+ // Base address DLL was compiled for
+ case DT_MIPS_BASE_ADDRESS:
+ _LOG("[MIPS_BASE_ADDRESS]\n");
+
+ // Base addresses other than zero are not supported. It would
+ // be easy enough to support them, but why?
+ if (dyn->d_un.d_val) {
+ free(dll);
+ _ERROR(ERR_DLL_FORMAT, 0);
+ }
+ break;
+
+ // Number of symbol table entries
+ case DT_MIPS_SYMTABNO:
+ _LOG("[MIPS_SYMTABNO]\n");
+
+ dll->symbol_count = dyn->d_un.d_val;
+ break;
+
+ // Index of first unresolved symbol table entry
+ //case DT_MIPS_UNREFEXTNO:
+ //_LOG("[MIPS_UNREFEXTNO]\n");
+ //break;
+
+ // Index of first symbol table entry which has a matching GOT entry
+ case DT_MIPS_GOTSYM:
+ _LOG("[MIPS_GOTSYM]\n");
+
+ first_got_sym = dyn->d_un.d_val;
+ break;
+
+ // Number of pages the GOT is split into (does not apply to PS1)
+ //case DT_MIPS_HIPAGENO:
+ //_LOG("[MIPS_HIPAGENO]\n");
+ //break;
+
+ default:
+ _LOG("[ignored]\n");
+ }
+ }
+
+ // Calculate the number of GOT entries (and symbols, if MIPS_SYMTABNO was
+ // not found in the .dynamic section).
+ //dll->symbol_count = \
+ ((uint32_t) dll->hash - (uint32_t) dll->symtab) / sizeof(Elf32_Sym);
+ //dll->got_length = \
+ ((uint32_t) ptr + size - (uint32_t) dll->got) / sizeof(uint32_t) - 2;
+
+ dll->got_length = local_got_len + (dll->symbol_count - first_got_sym) - 2;
+ _LOG(
+ "psxetc: %d symbols, %d GOT entries\n",
+ dll->symbol_count,
+ dll->got_length
+ );
+
+ // Relocate the DLL by adding its base address to all pointers in the GOT
+ // except the first two, which are reserved. The first entry in particular
+ // is a pointer to the lazy resolver, called by auto-generated stubs when a
+ // function is first used. got[1] is normally unused, but here we'll set it
+ // to the DLL's metadata struct so we can look that up when resolving
+ // functions (see _dl_resolve_wrapper()).
+ dll->got[0] = (uint32_t) &_dl_resolve_wrapper;
+ dll->got[1] = (uint32_t) dll;
+
+ for (uint32_t i = 0; i < dll->got_length; i++)
+ dll->got[2 + i] += (uint32_t) ptr;
+
+ // Fix addresses in the symbol table.
+ // TODO: clean this shit up
+ uint32_t got_offset = first_got_sym;
+
+ for (uint32_t i = 0; i < dll->symbol_count; i++) {
+ Elf32_Sym *sym = &(dll->symtab[i]);
+ const char *_name = &(dll->strtab[sym->st_name]);
+
+ if (!sym->st_value)
+ continue;
+
+ sym->st_value += (uint32_t) ptr;
+ _LOG(
+ "psxetc: DLL sym: %08x,%08x [%s]\n",
+ sym->st_value,
+ sym->st_size,
+ _name
+ );
+
+ // If RTLD_NOW was passed, resolve GOT entries ahead of time by
+ // cross-referencing them with the symbol table.
+ if (mode != RTLD_NOW)
+ continue;
+
+ for (uint32_t j = got_offset; j < dll->got_length; j++) {
+ if (dll->got[2 + j] != (uint32_t) sym->st_value)
+ continue;
+
+ got_offset = j;
+
+ // If the symbol is undefined (st_shndx = 0) and is either a
+ // variable or a function, resolve it immediately.
+ // TODO: linking of external variables needs more testing
+ if (!(sym->st_shndx) && (
+ ELF32_ST_TYPE(sym->st_info) == STT_OBJECT ||
+ ELF32_ST_TYPE(sym->st_info) == STT_FUNC
+ )) {
+ dll->got[2 + j] = (uint32_t) _dl_resolve_callback(dll, _name);
+
+ if (!dll->got[2 + j]) {
+ free(dll);
+ _ERROR(ERR_MAP_SYMBOL, 0);
+ }
+ }
+
+ break;
+ }
+ }
+
+ EnterCriticalSection();
+ FlushCache();
+ ExitCriticalSection();
+
+ // Call the DLL's global constructors. This is the same thing we'd do in
+ // _start() for regular executables, but we have to do it outside of the
+ // DLL as there's no _start() or even a defined entry point within the
+ // DLL itself.
+ const uint32_t *ctor_list = dlsym(dll, "__CTOR_LIST__");
+ if (ctor_list) {
+ for (uint32_t i = ((uint32_t) ctor_list[0]); i >= 1; i--) {
+ void (*ctor)(void) = (void (*)(void)) ctor_list[i];
+ DL_CALL(ctor);
+ }
+ }
+
+ return dll;
+}
+
+DLL *dlopen(const char *filename, DL_ResolveMode mode) {
+#ifdef USE_FILE_API
+ size_t size;
+ char *ptr = _load_file(filename, &size);
+ if (!ptr)
+ return 0;
+
+ DLL *dll = dlinit(ptr, size, mode);
+ if (dll)
+ dll->malloc_ptr = dll->ptr;
+ else
+ free(ptr);
+
+ return dll;
+#else
+ _ERROR(ERR_NO_FILE_API, 0);
+#endif
+}
+
+void dlclose(DLL *dll) {
+ if (dll == RTLD_DEFAULT)
+ return;
+
+ if (dll->ptr) {
+ // Call the DLL's global destructors.
+ const uint32_t *dtor_list = dlsym(dll, "__DTOR_LIST__");
+ if (dtor_list) {
+ for (uint32_t i = 0; i < ((uint32_t) dtor_list[0]); i++) {
+ void (*dtor)(void) = (void (*)(void)) dtor_list[i + 1];
+ DL_CALL(dtor);
+ }
+ }
+ }
+
+ // If the DLL is associated to a buffer allocated by dlopen(), free that
+ // buffer.
+ if (dll->malloc_ptr)
+ free(dll->malloc_ptr);
+
+ free(dll);
+}
+
+void *dlsym(DLL *dll, const char *name) {
+ if (dll == RTLD_DEFAULT)
+ return DL_GetSymbolByName(name);
+ //return _dl_resolve_callback(RTLD_DEFAULT, name);
+
+ // https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-48031.html
+ const uint32_t *hash_table = dll->hash;
+ uint32_t nbucket = hash_table[0];
+ uint32_t hash_mod = _elf_hash(name) % nbucket;
+
+ // Go through the hash table's chain until the symbol name matches the one
+ // provided.
+ for (uint32_t i = hash_table[2 + hash_mod]; i;) {
+ Elf32_Sym *sym = &(dll->symtab[i]);
+ const char *_name = &(dll->strtab[sym->st_name]);
+
+ if (!strcmp(name, _name)) {
+ _LOG("psxetc: DLL lookup [%s = %08x]\n", name, sym->st_value);
+ return sym->st_value;
+ }
+
+ i = hash_table[2 + nbucket + i];
+ }
+
+ _ERROR(ERR_DLL_SYMBOL, 0);
+}
+
+const char *const dlerror(void) {
+ uint32_t last = _error_code;
+ _error_code = ERR_NONE;
+
+ if (last)
+ return DL_ERROR_MESSAGES[last - 1];
+
+ return 0;
+}
diff --git a/libpsn00b/psxetc/makefile b/libpsn00b/psxetc/makefile
index cc12944..84bb64b 100644
--- a/libpsn00b/psxetc/makefile
+++ b/libpsn00b/psxetc/makefile
@@ -1,46 +1,59 @@
-# 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 = libpsxetc.a
+PSN00BSDK_LIBS ?= ..
-CFILES = $(notdir $(wildcard ./*.c))
-AFILES = $(notdir $(wildcard ./*.s))
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+include ../../psn00bsdk-setup.mk
-CFLAGS = -g -O2 -msoft-float -fno-builtin -nostdlib -fdata-sections \
- -ffunction-sections -Wa,--strip-local-absolute
-AFLAGS = -g -msoft-float -strip-local-absolute
+# Project target name
+TARGET = libpsxetc.a
-INCLUDE = -I../include
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-all: $(TARGET)
+## Build rules
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+all: build/$(TARGET)
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(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) $(CPPFLAGS_LIB) $(INCLUDE) -c $< -o $@
build/%.o: %.s
@mkdir -p $(dir $@)
- $(AS) $(AFLAGS) $(INCLUDE) $< -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/psxetc/readme.txt b/libpsn00b/psxetc/readme.txt
index f2e7649..24645f7 100644
--- a/libpsn00b/psxetc/readme.txt
+++ b/libpsn00b/psxetc/readme.txt
@@ -1,18 +1,20 @@
PSX Misc library, part of PSn00bSDK
-2019 Lameguy64 / Meido-Tek Productions
+2021 Lameguy64 / Meido-Tek Productions
Licensed under Mozilla Public License
-Open source implementation of the ETC library. Doesn't really provide much
-aside from some debug font stuff at the moment.
-
+Open source implementation of the ETC library. Currently provides the interrupt
+and DMA callback dispatchers (used by other libraries) as well as the DL_* and
+dl* functions for dynamic library loading (original, not present in the official
+SDK but similar to the standard dlopen() API).
Library developer(s):
Lameguy64
-
-
+ spicyjpeg
+
Library header(s):
psxetc.h
-
+ dlfcn.h
+ elf.h (used internally)
diff --git a/libpsn00b/psxgpu/makefile b/libpsn00b/psxgpu/makefile
index 5442958..adcb7fa 100644
--- a/libpsn00b/psxgpu/makefile
+++ b/libpsn00b/psxgpu/makefile
@@ -1,46 +1,59 @@
-# 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 = libpsxgpu.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-CFILES = $(notdir $(wildcard ./*.c))
-AFILES = $(notdir $(wildcard ./*.s))
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+# Project target name
+TARGET = libpsxgpu.a
-CFLAGS = -g -O2 -msoft-float -fno-builtin -fdata-sections \
- -ffunction-sections -Wa,--strip-local-absolute
-AFLAGS = -g -msoft-float -Wa,--strip-local-absolute
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-all: $(TARGET)
+## Build rules
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+all: build/$(TARGET)
+
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(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) $(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/psxgte/makefile b/libpsn00b/psxgte/makefile
index 7c1683f..e60ff1e 100644
--- a/libpsn00b/psxgte/makefile
+++ b/libpsn00b/psxgte/makefile
@@ -1,46 +1,59 @@
-# 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 = libpsxgte.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-CFILES = $(notdir $(wildcard ./*.c))
-AFILES = $(notdir $(wildcard ./*.s))
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+# Project target name
+TARGET = libpsxgte.a
-CFLAGS = -g -O2 -msoft-float -fno-builtin -fdata-sections \
- -ffunction-sections -Wa,--strip-local-absolute
-AFLAGS = -g -msoft-float -strip-local-absolute
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
-all: $(TARGET)
+all: build/$(TARGET)
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(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) $(CPPFLAGS_LIB) $(INCLUDE) -c $< -o $@
build/%.o: %.s
@mkdir -p $(dir $@)
- $(AS) $(AFLAGS) $(INCLUDE) $< -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/psxsio/makefile b/libpsn00b/psxsio/makefile
index 06971ba..c9dcade 100644
--- a/libpsn00b/psxsio/makefile
+++ b/libpsn00b/psxsio/makefile
@@ -1,46 +1,59 @@
-# 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 = libpsxsio.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-CFILES = $(notdir $(wildcard ./*.c))
-AFILES = $(notdir $(wildcard ./*.s))
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+# Project target name
+TARGET = libpsxsio.a
-CFLAGS = -g -O2 -msoft-float -fno-builtin -fdata-sections \
- -ffunction-sections -Wa,--strip-local-absolute
-AFLAGS = -g -msoft-float -Wa,--strip-local-absolute
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
-all: $(TARGET)
+all: build/$(TARGET)
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(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) $(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/psxspu/makefile b/libpsn00b/psxspu/makefile
index 7948f34..5710f39 100644
--- a/libpsn00b/psxspu/makefile
+++ b/libpsn00b/psxspu/makefile
@@ -1,46 +1,59 @@
-# 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 = libpsxspu.a
+PSN00BSDK_LIBS ?= ..
-INCLUDE = -I../include
+include ../../psn00bsdk-setup.mk
-CFILES = $(notdir $(wildcard ./*.c))
-AFILES = $(notdir $(wildcard ./*.s))
-OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+# Project target name
+TARGET = libpsxspu.a
-CFLAGS = -g -O2 -msoft-float -fdata-sections -ffunction-sections \
- -Wa,--strip-local-absolute
-AFLAGS = -g -msoft-float -strip-local-absolute
+## Files
-ifndef PSN00BSDK_LIBS
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CXXFILES= $(notdir $(wildcard *.cxx))
+AFILES = $(notdir $(wildcard *.s))
-PSN00BSDK_LIBS = ..
+# Create names for object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CXXFILES:.cxx=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-endif
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
+
+## Build rules
-all: $(TARGET)
+all: build/$(TARGET)
-$(TARGET): $(OFILES)
- $(AR) cr $(TARGET) $(OFILES)
- $(RANLIB) $(TARGET)
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(AR) crs $@ $(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) $(CPPFLAGS_LIB) $(INCLUDE) -c $< -o $@
build/%.o: %.s
@mkdir -p $(dir $@)
- $(AS) $(AFLAGS) $(INCLUDE) $< -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/psxspu/transfer.s b/libpsn00b/psxspu/transfer.s
index 086bb3b..5b62c28 100644
--- a/libpsn00b/psxspu/transfer.s
+++ b/libpsn00b/psxspu/transfer.s
@@ -20,7 +20,8 @@ SpuSetTransferStartAddr:
li $v0, 0x1000 # Check if value is valid
blt $a0, $v0, .Lbad_value
nop
- li $v0, 0xffff
+ lui $v0, 8 # 0x7ffff = (8<<16)-1
+ addiu $v0, -1
bgt $a0, $v0, .Lbad_value
nop
diff --git a/psn00bsdk-setup.mk b/psn00bsdk-setup.mk
new file mode 100644
index 0000000..8417358
--- /dev/null
+++ b/psn00bsdk-setup.mk
@@ -0,0 +1,121 @@
+# PSn00bSDK project setup file
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+#
+# This file does not depend on any other files (besides paths specified via
+# environment variables) and may be copied for use with your projects. See the
+# template directory for a makefile template.
+
+#PREFIX ?= mipsel-none-elf
+PREFIX ?= mipsel-unknown-elf
+
+## Path setup
+
+# PSn00bSDK library/include path setup
+ifndef PSN00BSDK_LIBS
+ # Default assumes PSn00bSDK is in the same parent dir as this project
+ LIBDIRS = -L../libpsn00b
+ INCLUDE = -I../libpsn00b/include -I../libpsn00b/lzp
+ LDBASE = ../libpsn00b/ldscripts
+else
+ LIBDIRS = -L$(PSN00BSDK_LIBS)
+ INCLUDE = -I$(PSN00BSDK_LIBS)/include -I$(PSN00BSDK_LIBS)/lzp
+ LDBASE = ${PSN00BSDK_LIBS}/ldscripts
+endif
+
+# PSn00bSDK toolchain path setup
+ifndef PSN00BSDK_TC
+ # Default assumes GCC toolchain is in root of C drive or /usr/local
+ ifeq "$(OS)" "Windows_NT"
+ GCC_BASE ?= /c/$(PREFIX)
+ GCC_BIN ?=
+ else
+ GCC_BASE ?= /usr/local/$(PREFIX)
+ GCC_BIN ?=
+ endif
+else
+ GCC_BASE ?= $(PSN00BSDK_TC)
+ GCC_BIN ?= $(PSN00BSDK_TC)/bin/
+endif
+
+# Autodetect GCC version by folder name (ugly but it works, lol)
+#GCC_VERSION ?= 7.4.0
+GCC_VERSION ?= $(word 1, $(notdir $(wildcard $(GCC_BASE)/lib/gcc/$(PREFIX)/*)))
+
+# PSn00bSDK tools path setup (TODO)
+PSN00BSDK_BIN ?=
+
+## Commands
+
+# GCC toolchain
+CC = $(GCC_BIN)$(PREFIX)-gcc
+CXX = $(GCC_BIN)$(PREFIX)-g++
+AS = $(GCC_BIN)$(PREFIX)-as
+AR = $(GCC_BIN)$(PREFIX)-ar
+LD = $(GCC_BIN)$(PREFIX)-ld
+RANLIB = $(GCC_BIN)$(PREFIX)-ranlib
+OBJCOPY = $(GCC_BIN)$(PREFIX)-objcopy
+NM = $(GCC_BIN)$(PREFIX)-nm
+
+# PSn00bSDK tools + mkpsxiso
+ELF2X = $(PSN00BSDK_BIN)elf2x
+LZPACK = $(PSN00BSDK_BIN)lzpack
+SMXLINK = $(PSN00BSDK_BIN)smxlink
+MKPSXISO = $(PSN00BSDK_BIN)mkpsxiso
+
+## Flags
+
+# SDK libraries (IMPORTANT: don't change the order)
+LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxcd -lpsxsio -lpsxetc -lpsxapi -lc
+
+# Common options:
+# - Debugging symbols enabled
+# - Wrap each symbol in a separate section
+# - Optimize for R3000, no FPU, 32-bit ABI
+# - Division by zero causes break opcodes to be executed
+# - C standard library (including libgcc) disabled
+# - C++ features that rely on runtime support disabled
+AFLAGS = -g -msoft-float -march=r3000 -mtune=r3000 -mabi=32
+CFLAGS = $(AFLAGS) -mdivide-breaks -O2 -ffreestanding -fno-builtin -nostdlib \
+ -fdata-sections -ffunction-sections -fsigned-char -fno-strict-overflow
+CPPFLAGS= $(CFLAGS) -fno-exceptions -fno-rtti -fno-unwind-tables \
+ -fno-threadsafe-statics -fno-use-cxa-atexit
+LDFLAGS = -nostdlib
+
+# Options for static libraries (and SDK libraries):
+# - GP-relative addressing disabled
+# - ABI-compatible calls disabled
+# - Local stripping enabled
+AFLAGS_LIB = $(AFLAGS) -G0 -Wa,--strip-local-absolute
+CFLAGS_LIB = $(CFLAGS) -G0 -mno-abicalls -mno-gpopt
+CPPFLAGS_LIB = $(CPPFLAGS) -G0 -mno-abicalls -mno-gpopt
+
+# Options for executables without support for dynamic linking:
+# - Position-independent code disabled
+# - GP-relative addressing enabled only for local symbols
+# - ABI-compatible calls disabled (incompatible with GP-relative addressing)
+# - Unused section stripping enabled
+AFLAGS_EXE = $(AFLAGS) -G8
+CFLAGS_EXE = $(CFLAGS) -G8 -mno-abicalls -mgpopt -mno-extern-sdata
+CPPFLAGS_EXE = $(CPPFLAGS) -G8 -mno-abicalls -mgpopt -mno-extern-sdata
+LDFLAGS_EXE = $(LDFLAGS) -G8 -static -T$(LDBASE)/exe.ld -gc-sections
+
+# Options for executables with support for dynamic linking:
+# - Position-independent code disabled
+# - GP-relative addressing disabled
+# - ABI-compatible calls disabled (must be done manually)
+# - Unused section stripping enabled
+AFLAGS_EXEDYN = $(AFLAGS) -G0
+CFLAGS_EXEDYN = $(CFLAGS) -G0 -mno-abicalls -mno-gpopt
+CPPFLAGS_EXEDYN = $(CPPFLAGS) -G0 -mno-abicalls -mno-gpopt
+LDFLAGS_EXEDYN = $(LDFLAGS) -G0 -static -T$(LDBASE)/exe.ld -gc-sections
+
+# Options for dynamically-loaded libraries:
+# - Position-independent code enabled
+# - GP-relative addressing disabled (incompatible with ABI calls)
+# - ABI-compatible calls enabled
+# - Unused section stripping not available
+AFLAGS_DLL = $(AFLAGS) -G0
+CFLAGS_DLL = $(CFLAGS) -G0 -mabicalls -mshared -mno-gpopt -fPIC
+CPPFLAGS_DLL = $(CPPFLAGS) -G0 -mabicalls -mshared -mno-gpopt -fPIC
+LDFLAGS_DLL = $(LDFLAGS) -G0 -shared -T$(LDBASE)/dll.ld
diff --git a/template/iso.xml b/template/iso.xml
new file mode 100644
index 0000000..ba2b29d
--- /dev/null
+++ b/template/iso.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<iso_project
+ image_name="build/template.bin"
+ cue_sheet="build/template.cue"
+>
+ <track type="data">
+ <identifiers
+ system ="PLAYSTATION"
+ volume ="PSN00BSDK"
+ volume_set ="PSN00BSDK"
+ publisher ="MEIDOTEK"
+ data_preparer ="PSN00BSDK BUILD SCRIPT"
+ application ="PLAYSTATION"
+ copyright ="README.TXT;1"
+ />
+
+ <directory_tree>
+ <file name="SYSTEM.CNF" type="data" source="system.cnf" />
+ <file name="TEMPLATE.EXE" type="data" source="build/template.exe" />
+ <file name="TEMPLATE.MAP" type="data" source="build/template.map" />
+
+ <dummy sectors="1024"/>
+ </directory_tree>
+ </track>
+
+ <!--<track type="audio" source="track2.wav" />-->
+</iso_project>
diff --git a/template/makefile b/template/makefile
index 42ff370..707a8d7 100644
--- a/template/makefile
+++ b/template/makefile
@@ -1,54 +1,69 @@
-include psn00bsdk-setup.mk
+# PSn00bSDK makefile template
+# Part of the PSn00bSDK Project
+# 2019 - 2021 Lameguy64 / Meido-Tek Productions
+
+## Settings
+
+# You can edit these here or pass them as environment variables.
+#PREFIX =
+#GCC_VERSION =
+#PSN00BSDK_TC =
+#PSN00BSDK_LIBS =
+
+# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
+# root folder (it only depends on environment variables).
+include ../psn00bsdk-setup.mk
# Project target name
-TARGET = template.elf
+TARGET = template
+
+## Files
# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES = $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES= $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
# Create names for object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
-# Project specific include and library directories
-# (use -I for include dirs, -L for library dirs)
-INCLUDE +=
-LIBDIRS +=
+# Project specific includes and libraries
+# (use -I for include dirs, -L for library dirs, -l for static libraries)
+INCLUDE +=
+LIBDIRS +=
+LIBS +=
-# Libraries to link
-LIBS = -lpsxgpu -lpsxgte -lpsxspu -lpsxetc -lpsxapi -lc
+## Build rules
-# C compiler flags
-CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+all: iso
+#all: build/$(TARGET)
-# C++ compiler flags
-CPPFLAGS = $(CFLAGS) -fno-exceptions
+iso: build/$(TARGET) resources
+ $(MKPSXISO) -y -q iso.xml
-# Assembler flags
-AFLAGS = -g
+resources:
+ # Add commands to build/convert your assets here
+ #$(LZPACK) data.xml
-# Linker flags (-Ttext specifies the program text address)
-LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
- -T $(GCC_BASE)/$(PREFIX)/lib/ldscripts/elf32elmip.x
+build/$(TARGET): $(OFILES)
+ @mkdir -p $(dir $@)
+ $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
+ $(NM) -f posix -l -n $@ >$@.map
+ $(ELF2X) -q $@ $@.exe
-all: $(OFILES)
- $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
- elf2x -q $(TARGET)
-
build/%.o: %.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.cpp
@mkdir -p $(dir $@)
- $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
build/%.o: %.s
@mkdir -p $(dir $@)
- $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
-
+ $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
+
clean:
- rm -rf build $(TARGET) $(TARGET:.elf=.exe)
+ rm -rf build
diff --git a/template/psn00bsdk-setup.mk b/template/psn00bsdk-setup.mk
deleted file mode 100644
index 6ba23ae..0000000
--- a/template/psn00bsdk-setup.mk
+++ /dev/null
@@ -1,68 +0,0 @@
-# PSn00bSDK project setup file
-# Part of the PSn00bSDK Project
-# 2019 - 2020 Lameguy64 / Meido-Tek Productions
-#
-# This file may be copied for use with your projects, see the template
-# directory for a makefile template
-
-ifndef PREFIX
-
-PREFIX = mipsel-unknown-elf
-
-endif # PREFIX
-
-ifndef GCC_VERSION
-
-GCC_VERSION = 7.4.0
-
-endif # GCC_VERSION
-
-# PSn00bSDK library/include path setup
-ifndef PSN00BSDK_LIBS
-
-# Default assumes PSn00bSDK is in the same parent dir as this project
-
-LIBDIRS = -L../psn00bsdk/libpsn00b
-INCLUDE = -I../psn00bsdk/libpsn00b/include
-
-else
-
-LIBDIRS = -L$(PSN00BSDK_LIBS)
-INCLUDE = -I$(PSN00BSDK_LIBS)/include
-
-endif # PSN00BSDK_LIBS
-
-# PSn00bSDK toolchain path setup
-ifndef GCC_BASE
-
-ifndef PSN00BSDK_TC
-
-# Default assumes GCC toolchain is in root of C drive or /usr/local
-
-ifeq "$(OS)" "Windows_NT"
-
-GCC_BASE = /c/mipsel-unknown-elf
-GCC_BIN =
-
-else
-
-GCC_BASE = /usr/local/mipsel-unknown-elf
-GCC_BIN =
-
-endif
-
-else
-
-GCC_BASE = $(PSN00BSDK_TC)
-GCC_BIN = $(PSN00BSDK_TC)/bin/
-
-endif # PSN00BSDK_TC
-
-endif # GCC_BASE
-
-CC = $(GCC_BIN)$(PREFIX)-gcc
-CXX = $(GCC_BIN)$(PREFIX)-g++
-AS = $(GCC_BIN)$(PREFIX)-as
-AR = $(GCC_BIN)$(PREFIX)-ar
-LD = $(GCC_BIN)$(PREFIX)-ld
-RANLIB = $(GCC_BIN)$(PREFIX)-ranlib \ No newline at end of file
diff --git a/template/system.cnf b/template/system.cnf
new file mode 100644
index 0000000..e221726
--- /dev/null
+++ b/template/system.cnf
@@ -0,0 +1,4 @@
+BOOT=cdrom:\template.exe;1
+TCB=4
+EVENT=10
+STACK=801FFFF0
diff --git a/toolchain.txt b/toolchain.txt
index 439f486..e67cfe1 100644
--- a/toolchain.txt
+++ b/toolchain.txt
@@ -107,12 +107,27 @@ Under Windows, you'll have to add the path to the PATH environment variable
through System Properties.
-Updating the ldscript:
+Note regarding C++ support:
+
+C++ support in PSn00bSDK only goes as far as basic classes, namespaces and
+the ability to dynamically create and delete class objects at any point of
+the program. The required dependencies are supplied by libc of libpsn00b.
+
+Standard C++ libraries are not implemented and likely never going to be
+implemented due to bloat concerns that it may introduce. Besides, the official
+SDK lacks full C++ support as well.
+
+If you're trying to compile with C++ code and you get a linker error about
+undefined vtables, try specifying --fno-rtti to the g++ command line.
+
+-----------------------------------------------------------------------------
+Updating the ldscript (NO LONGER REQUIRED as PSn00bSDK now ships with its own
+linker scripts, the section below is only kept for reference):
-The following changes are required in order for basic C++ functionality to work
-in PSn00bSDK. The changes define the constructor and deconstructor sections
-which are required for the relevant support functions in PSn00bSDK's libc
-library to be linked properly for C++.
+The following changes used to be required in order for basic C++ functionality
+to work in older PSn00bSDK versions. The changes define the constructor and
+deconstructor sections which are required for the relevant support functions
+in PSn00bSDK's libc library to be linked properly for C++.
* Go to mipsel-unknown-elf/lib/ldscripts in the toolchain directory.
@@ -150,16 +165,3 @@ Alternatively, you can make a copy of the ldscript file and modify it within
your project directory. This is especially useful if your project uses code
overlays.
-
-Note regarding C++ support:
-
-C++ support in PSn00bSDK only goes as far as basic classes, namespaces and
-the ability to dynamically create and delete class objects at any point of
-the program. The required dependencies are supplied by libc of libpsn00b.
-
-Standard C++ libraries are not implemented and likely never going to be
-implemented due to bloat concerns that it may introduce. Besides, the official
-SDK lacks full C++ support as well.
-
-If you're trying to compile with C++ code and you get a linker error about
-undefined vtables, try specifying --fno-rtti to the g++ command line. \ No newline at end of file