mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
gx: bridge internal libogc's __syscalls table to modern devkitPPC
The default GameCube/Wii build links the prebuilt in-tree libogc, whose SYS_Init installs its heap, lock, exit and time handlers into newlib's __syscalls dispatch table -- a table devkitPPC r38 and later no longer provide, so the EXTERNAL_LIBOGC=0 path has not linked on any current toolchain (CI never sees it because it builds EXTERNAL_LIBOGC=1). Defining bare storage for the symbol would link but misbehave: libsysbase's default sbrk would place the heap by linker symbols instead of libogc's MEM1 arena, colliding with SYS_GetArena1Lo allocations, and malloc would run unlocked under lwp threads. wii/libogc_syscalls_compat.c therefore defines the table with the slot layout the prebuilt SYS_Init actually stores to (offsets 0..32, verified against the archive's relocations) and provides strong definitions for the per-symbol weak __syscall_* hooks that modern libsysbase dispatches through -- sbrk, the four lock operations, the malloc locks, exit and gettod all route to the same libogc handlers the old toolchain reached, with the old pre-SYS_Init NULL-slot behaviour preserved. The file is compiled only under EXTERNAL_LIBOGC=0, external-libogc builds are untouched, and the default make -f Makefile.ngc links again on the CI toolchain (devkitPPC r38, GCC 10.2.0).
This commit is contained in:
1 parent
e43ea7cf34
commit
ce8f93cc1c
2 files changed
+120
No files matched your search
@@ -173,6 +173,10 @@ CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(PLATCFLAGS) $(INCLUDE)
|
||||
OBJ = $(PLATOBJS) audio/drivers/gx_audio.o gfx/drivers/gx_gfx.o gfx/display_servers/dispserv_gx.o gfx/display_servers/dispserv_gx_modes.o input/drivers/gx_input.o frontend/drivers/platform_gx.o input/drivers_joypad/gx_joypad.o
|
||||
|
||||
ifeq ($(EXTERNAL_LIBOGC), 0)
|
||||
# Bridge the prebuilt in-tree libogc's __syscalls table onto the
|
||||
# per-symbol __syscall_* hooks modern devkitPPC libsysbase dispatches
|
||||
# through (see wii/libogc_syscalls_compat.c).
|
||||
OBJ += wii/libogc_syscalls_compat.o
|
||||
OBJ += wii/libogc/libfat/libfat.o wii/libogc/libfat/fatfile.o wii/libogc/libfat/file_allocation_table.o wii/libogc/libfat/cache.o wii/libogc/libfat/fatdir.o wii/libogc/libfat/partition.o wii/libogc/libfat/directory.o wii/libogc/libfat/filetime.o wii/libogc/libfat/disc.o
|
||||
endif
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/* Internal-libogc syscall bridge for modern devkitPPC newlibs.
|
||||
*
|
||||
* The in-tree prebuilt libogc installs its heap, lock, exit and
|
||||
* time-of-day handlers into newlib's __syscalls dispatch table at
|
||||
* SYS_Init (system.c), and the devkitPPC libsysbase of its era routed
|
||||
* everything through that table. devkitPPC r38 and later removed the
|
||||
* table: libsysbase now dispatches through per-symbol weak
|
||||
* __syscall_* hooks instead, so the internal-libogc link fails on the
|
||||
* undefined __syscalls -- and merely defining storage for it would be
|
||||
* worse than the link error, because libsysbase's default sbrk would
|
||||
* place the heap by linker symbols instead of libogc's MEM1 arena,
|
||||
* colliding with SYS_GetArena1Lo allocations, and malloc would run
|
||||
* unlocked under lwp threads.
|
||||
*
|
||||
* This file defines the table the prebuilt SYS_Init writes into and
|
||||
* provides strong __syscall_* hooks that forward to it, so the modern
|
||||
* libsysbase routes exactly where the old one did. The table layout
|
||||
* is fixed by the prebuilt binary, not by any header we control:
|
||||
* SYS_Init stores its nine handlers at offsets 0..32 in declaration
|
||||
* order (verified against the archive's relocations), so the slots are
|
||||
* mirrored here, with the old libsysbase's pre-SYS_Init behaviour kept
|
||||
* for NULL slots. Compiled only for EXTERNAL_LIBOGC=0 GameCube/Wii
|
||||
* builds; external libogc pairs with its own toolchain's libsysbase
|
||||
* and never sees this file. */
|
||||
|
||||
#ifdef INTERNAL_LIBOGC
|
||||
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <reent.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Slot layout written by the prebuilt SYS_Init. Offsets are
|
||||
* load-bearing; the trailing reserve absorbs whatever the era's
|
||||
* iosupport.h declared beyond the slots libogc touches. */
|
||||
struct __syscalls_compat
|
||||
{
|
||||
void *(*sbrk_r)(struct _reent *r, ptrdiff_t incr); /* +0 */
|
||||
int (*lock_init)(int *lock); /* +4 */
|
||||
int (*lock_close)(int *lock); /* +8 */
|
||||
int (*lock_release)(int *lock); /* +12 */
|
||||
int (*lock_acquire)(int *lock); /* +16 */
|
||||
void (*malloc_lock)(struct _reent *r); /* +20 */
|
||||
void (*malloc_unlock)(struct _reent *r); /* +24 */
|
||||
void (*exit)(int rc); /* +28 */
|
||||
int (*gettod_r)(struct _reent *r,
|
||||
struct timeval *tv, struct timezone *tz); /* +32 */
|
||||
void *reserved[23];
|
||||
};
|
||||
|
||||
struct __syscalls_compat __syscalls;
|
||||
|
||||
void *__syscall_sbrk_r(struct _reent *r, ptrdiff_t incr)
|
||||
{
|
||||
if (__syscalls.sbrk_r)
|
||||
return __syscalls.sbrk_r(r, incr);
|
||||
r->_errno = ENOMEM;
|
||||
return (void*)-1;
|
||||
}
|
||||
|
||||
/* Before SYS_Init there is one context and no lwp threads, so a
|
||||
* missing lock handler is a safe no-op, exactly as the old dispatch
|
||||
* behaved with a zeroed table. */
|
||||
void __syscall_lock_init(int *lock)
|
||||
{
|
||||
if (__syscalls.lock_init)
|
||||
__syscalls.lock_init(lock);
|
||||
}
|
||||
|
||||
void __syscall_lock_close(int *lock)
|
||||
{
|
||||
if (__syscalls.lock_close)
|
||||
__syscalls.lock_close(lock);
|
||||
}
|
||||
|
||||
void __syscall_lock_acquire(int *lock)
|
||||
{
|
||||
if (__syscalls.lock_acquire)
|
||||
__syscalls.lock_acquire(lock);
|
||||
}
|
||||
|
||||
void __syscall_lock_release(int *lock)
|
||||
{
|
||||
if (__syscalls.lock_release)
|
||||
__syscalls.lock_release(lock);
|
||||
}
|
||||
|
||||
void __syscall_malloc_lock(struct _reent *r)
|
||||
{
|
||||
if (__syscalls.malloc_lock)
|
||||
__syscalls.malloc_lock(r);
|
||||
}
|
||||
|
||||
void __syscall_malloc_unlock(struct _reent *r)
|
||||
{
|
||||
if (__syscalls.malloc_unlock)
|
||||
__syscalls.malloc_unlock(r);
|
||||
}
|
||||
|
||||
int __syscall_gettod_r(struct _reent *r, struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
if (__syscalls.gettod_r)
|
||||
return __syscalls.gettod_r(r, tv, tz);
|
||||
r->_errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __syscall_exit(int rc)
|
||||
{
|
||||
if (__syscalls.exit)
|
||||
__syscalls.exit(rc);
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* INTERNAL_LIBOGC */
|
||||
Reference in new issue
Block a user