mirror of
https://github.com/ps5-payload-dev/sdk.git
synced 2026-10-19 01:51:19 -05:00
rtld: initial experiment with homebrew shared objects
This commit is contained in:
1 parent
f78074899a
commit
7c3a832633
19 files changed
+2159
-838
No files matched your search
+6
-1
@@ -33,12 +33,17 @@ endif
|
||||
CFLAGS += -ffreestanding -fno-builtin -nostdlib -fPIC
|
||||
CFLAGS += -target x86_64-sie-ps5 -fno-plt -fno-stack-protector
|
||||
CFLAGS += -fvisibility-nodllstorageclass=default -Wall -Werror
|
||||
CFLAGS += -fms-extensions -Wno-microsoft-anon-tag
|
||||
CFLAGS += -g
|
||||
|
||||
OBJ := crt.o syscall.o klog.o nid.o kernel.o rtld.o rtld_so.o rtld_sprx.o \
|
||||
rtld_payload.o patch.o mdbg.o
|
||||
|
||||
ARCHIVE := libcrt.a
|
||||
|
||||
all: $(ARCHIVE)
|
||||
|
||||
$(ARCHIVE): crt.o syscall.o klog.o nid.o kernel.o rtld.o patch.o mdbg.o
|
||||
$(ARCHIVE): $(OBJ)
|
||||
$(AR) -rsc $@ $^
|
||||
|
||||
%.o: %.c
|
||||
|
||||
@@ -19,12 +19,6 @@ along with this program; see the file COPYING. If not, see
|
||||
#include "payload.h"
|
||||
|
||||
|
||||
/**
|
||||
* Convenient macro for loading symbols.
|
||||
**/
|
||||
#define DLSYM(handle, sym) (sym=(void*)kernel_dynlib_dlsym(-1, handle, #sym))
|
||||
|
||||
|
||||
/**
|
||||
* Dependencies provided by the ELF linker.
|
||||
**/
|
||||
@@ -44,6 +38,9 @@ extern unsigned char __bss_end[] __attribute__((weak));
|
||||
extern int main(int argc, char* argv[], char *envp[]);
|
||||
|
||||
|
||||
/**
|
||||
* Init functrions for crt modules.
|
||||
**/
|
||||
int __syscall_init(payload_args_t* args);
|
||||
int __kernel_init(payload_args_t* args);
|
||||
int __klog_init(void);
|
||||
@@ -77,7 +74,7 @@ pre_init(payload_args_t *args) {
|
||||
klog_puts("Unable to initialize patches");
|
||||
return error;
|
||||
}
|
||||
if(!DLSYM(0x2, __isthreaded)) {
|
||||
if(!KERNEL_DLSYM(0x2, __isthreaded)) {
|
||||
klog_puts("Unable to resolve the symbol '__isthreaded'");
|
||||
return -1;
|
||||
}
|
||||
@@ -101,7 +98,7 @@ terminate(payload_args_t *args) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(DLSYM(0x2, exit)) {
|
||||
if(KERNEL_DLSYM(0x2, exit)) {
|
||||
exit(*args->payloadout);
|
||||
}
|
||||
}
|
||||
@@ -124,16 +121,16 @@ _start(payload_args_t *args) {
|
||||
*bss = 0;
|
||||
}
|
||||
|
||||
// Init runtime
|
||||
// Init runtime.
|
||||
if((*args->payloadout=pre_init(args))) {
|
||||
terminate(args);
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtain argc, argv and envp from libkernel
|
||||
if((DLSYM(0x1, getargc) || DLSYM(0x2001, getargc)) &&
|
||||
(DLSYM(0x1, getargv) || DLSYM(0x2001, getargv)) &&
|
||||
(DLSYM(0x1, environ) || DLSYM(0x2001, environ))) {
|
||||
// Obtain argc, argv and envp from libkernel.
|
||||
if((KERNEL_DLSYM(0x1, getargc) || KERNEL_DLSYM(0x2001, getargc)) &&
|
||||
(KERNEL_DLSYM(0x1, getargv) || KERNEL_DLSYM(0x2001, getargv)) &&
|
||||
(KERNEL_DLSYM(0x1, environ) || KERNEL_DLSYM(0x2001, environ))) {
|
||||
argc = getargc();
|
||||
argv = getargv();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define ELF64_R_SYM(info) ((info) >> 32)
|
||||
#define ELF64_ST_BIND(info) ((info) >> 4)
|
||||
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
|
||||
#define DT_NULL 0
|
||||
#define DT_NEEDED 1
|
||||
#define DT_STRTAB 5
|
||||
#define DT_SYMTAB 6
|
||||
#define DT_RELA 7
|
||||
#define DT_RELASZ 8
|
||||
#define DT_GNU_HASH 0x6ffffef5
|
||||
|
||||
#define R_X86_64_64 1
|
||||
#define R_X86_64_GLOB_DAT 6
|
||||
#define R_X86_64_JMP_SLOT 7
|
||||
#define R_X86_64_RELATIVE 8
|
||||
|
||||
#define ET_DYN 3
|
||||
|
||||
#define STB_WEAK 2
|
||||
|
||||
#define SHT_RELA 4
|
||||
|
||||
#define PF_X (1 << 0)
|
||||
#define PF_W (1 << 1)
|
||||
#define PF_R (1 << 2)
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[16];
|
||||
unsigned short e_type;
|
||||
unsigned short e_machine;
|
||||
unsigned int e_version;
|
||||
unsigned long e_entry;
|
||||
unsigned long e_phoff;
|
||||
unsigned long e_shoff;
|
||||
unsigned int e_flags;
|
||||
unsigned short e_ehsize;
|
||||
unsigned short e_phentsize;
|
||||
unsigned short e_phnum;
|
||||
unsigned short e_shentsize;
|
||||
unsigned short e_shnum;
|
||||
unsigned short e_shstrndx;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int p_type;
|
||||
unsigned int p_flags;
|
||||
unsigned long p_offset;
|
||||
unsigned long p_vaddr;
|
||||
unsigned long p_paddr;
|
||||
unsigned long p_filesz;
|
||||
unsigned long p_memsz;
|
||||
unsigned long p_align;
|
||||
} Elf64_Phdr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int sh_name;
|
||||
unsigned int sh_type;
|
||||
unsigned long sh_flags;
|
||||
unsigned long sh_addr;
|
||||
unsigned long sh_offset;
|
||||
unsigned long sh_size;
|
||||
unsigned int sh_link;
|
||||
unsigned int sh_info;
|
||||
unsigned long sh_addralign;
|
||||
unsigned long sh_entsize;
|
||||
} Elf64_Shdr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
long d_tag;
|
||||
union {
|
||||
unsigned long d_val;
|
||||
unsigned long d_ptr;
|
||||
} d_un;
|
||||
} Elf64_Dyn;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
unsigned short st_shndx;
|
||||
unsigned long st_value;
|
||||
unsigned long st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned long r_offset;
|
||||
unsigned long r_info;
|
||||
long r_addend;
|
||||
} Elf64_Rela;
|
||||
|
||||
@@ -17,6 +17,10 @@ along with this program; see the file COPYING. If not, see
|
||||
#pragma once
|
||||
|
||||
|
||||
#define KERNEL_DLSYM(handle, sym) \
|
||||
(sym=(void*)kernel_dynlib_dlsym(-1, handle, #sym))
|
||||
|
||||
|
||||
/**
|
||||
* dynamic library loaded in kernel memory.
|
||||
**/
|
||||
|
||||
+135
-822
File diff suppressed because it is too large.
Load diff
+75
@@ -0,0 +1,75 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
/**
|
||||
* Prototypes for different kinds of libs (.sprx or .so).
|
||||
**/
|
||||
typedef struct rtld_lib {
|
||||
int (*open)(struct rtld_lib* ctx);
|
||||
void* (*sym)(struct rtld_lib* ctx, const char* name);
|
||||
int (*close)(struct rtld_lib* ctx);
|
||||
void (*destroy)(struct rtld_lib* ctx);
|
||||
|
||||
char *soname;
|
||||
|
||||
struct rtld_lib* next;
|
||||
struct rtld_lib* prev;
|
||||
} rtld_lib_t;
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a new lib object with the given soname.
|
||||
**/
|
||||
rtld_lib_t* __rtld_lib_new(rtld_lib_t* prev, const char* soname);
|
||||
|
||||
|
||||
/**
|
||||
* Open a lib and run its constructor.
|
||||
**/
|
||||
int __rtld_lib_open(rtld_lib_t* ctx);
|
||||
|
||||
|
||||
/**
|
||||
* Resolve a symbol in the lib.
|
||||
**/
|
||||
void* __rtld_lib_sym(rtld_lib_t* ctx, const char* name);
|
||||
|
||||
|
||||
/**
|
||||
* Close the lib and run its destructor.
|
||||
**/
|
||||
int __rtld_lib_close(rtld_lib_t* ctx);
|
||||
|
||||
|
||||
/**
|
||||
* Free up all memory associated with the lib.
|
||||
**/
|
||||
void __rtld_lib_destroy(rtld_lib_t* ctx);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the lib loader.
|
||||
**/
|
||||
int __rtld_init(void);
|
||||
|
||||
|
||||
/**
|
||||
* Finalize the lib loader.
|
||||
**/
|
||||
int __rtld_fini(void);
|
||||
@@ -0,0 +1,275 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "elf.h"
|
||||
#include "kernel.h"
|
||||
#include "klog.h"
|
||||
#include "syscall.h"
|
||||
#include "rtld.h"
|
||||
|
||||
|
||||
/**
|
||||
* Dependencies to standard libraries.
|
||||
**/
|
||||
static void* (*memcpy)(void*, const void*, unsigned long) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Dependencies provided by the ELF linker.
|
||||
**/
|
||||
extern unsigned char __image_start[] __attribute__((weak));
|
||||
extern Elf64_Dyn _DYNAMIC[];
|
||||
|
||||
|
||||
/**
|
||||
* Global variables.
|
||||
**/
|
||||
static rtld_lib_t* g_libhead = 0;
|
||||
static Elf64_Sym* g_symtab = 0;
|
||||
static char* g_strtab = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Process the DT_NEEDED entry in the .dynamic section.
|
||||
**/
|
||||
static int
|
||||
dt_needed(const char* soname) {
|
||||
rtld_lib_t* it = g_libhead;
|
||||
rtld_lib_t* lib;
|
||||
|
||||
while(it && it->next) {
|
||||
it = it->next;
|
||||
}
|
||||
|
||||
if(!(lib=__rtld_lib_new(it, soname))) {
|
||||
klog_printf("Unable to load %s\n", soname);
|
||||
return -1;
|
||||
|
||||
} else if(__rtld_lib_open(lib) < 0) {
|
||||
klog_printf("unable to load '%s'\n", soname);
|
||||
__rtld_lib_destroy(lib);
|
||||
return -1;
|
||||
|
||||
} else if(!g_libhead) {
|
||||
g_libhead = lib;
|
||||
|
||||
} else if(it) {
|
||||
it->next = lib;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_GLOB_DAT relocation type.
|
||||
**/
|
||||
static int
|
||||
r_glob_dat(Elf64_Rela* rela) {
|
||||
Elf64_Sym* sym = g_symtab + ELF64_R_SYM(rela->r_info);
|
||||
const char* name = g_strtab + sym->st_name;
|
||||
void* loc = __image_start + rela->r_offset;
|
||||
void* val = 0;
|
||||
|
||||
for(rtld_lib_t *lib=g_libhead; lib; lib=lib->next) {
|
||||
if((val=__rtld_lib_sym(lib, name))) {
|
||||
memcpy(loc, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
klog_printf("Unable to resolve '%s'\n", name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_JMP_SLOT relocation type.
|
||||
**/
|
||||
static int
|
||||
r_jmp_slot(Elf64_Rela* rela) {
|
||||
return r_glob_dat(rela);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_64 relocation type.
|
||||
**/
|
||||
static int
|
||||
r_direct_64(Elf64_Rela* rela) {
|
||||
Elf64_Sym* sym = g_symtab + ELF64_R_SYM(rela->r_info);
|
||||
const char* name = g_strtab + sym->st_name;
|
||||
void* loc = __image_start + rela->r_offset;
|
||||
void* val = 0;
|
||||
|
||||
for(rtld_lib_t *lib=g_libhead; lib!=0; lib=lib->next) {
|
||||
if((val=__rtld_lib_sym(lib, name))) {
|
||||
val += rela->r_addend;
|
||||
memcpy(loc, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
klog_printf("Unable to resolve '%s'\n", name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_RELATIVE relocation type.
|
||||
**/
|
||||
static int
|
||||
r_relative(Elf64_Rela* rela) {
|
||||
void* loc = __image_start + rela->r_offset;
|
||||
void* val = __image_start + rela->r_addend;
|
||||
|
||||
memcpy(loc, &val, sizeof(val));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static int
|
||||
payload_load(void) {
|
||||
Elf64_Rela* rela = 0;
|
||||
long relasz = 0;
|
||||
|
||||
// find lookup tables
|
||||
for(int i=0; _DYNAMIC[i].d_tag!=DT_NULL; i++) {
|
||||
switch(_DYNAMIC[i].d_tag) {
|
||||
case DT_SYMTAB:
|
||||
g_symtab = (Elf64_Sym*)(__image_start + _DYNAMIC[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_STRTAB:
|
||||
g_strtab = (char*)(__image_start + _DYNAMIC[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_RELA:
|
||||
rela = (Elf64_Rela*)(__image_start + _DYNAMIC[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_RELASZ:
|
||||
relasz = _DYNAMIC[i].d_un.d_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// load needed libraries
|
||||
for(int i=0; _DYNAMIC[i].d_tag!=DT_NULL; i++) {
|
||||
switch(_DYNAMIC[i].d_tag) {
|
||||
case DT_NEEDED:
|
||||
if(dt_needed(g_strtab + _DYNAMIC[i].d_un.d_val)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// apply relocations
|
||||
for(int i=0; i<relasz/sizeof(Elf64_Rela); i++) {
|
||||
switch(rela[i].r_info & 0xffffffffl) {
|
||||
case R_X86_64_JMP_SLOT:
|
||||
if(r_jmp_slot(&rela[i])) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_X86_64_64:
|
||||
if(r_direct_64(&rela[i])) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_X86_64_GLOB_DAT:
|
||||
if(r_glob_dat(&rela[i])) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_X86_64_RELATIVE:
|
||||
if(r_relative(&rela[i])) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__rtld_payload_init(void) {
|
||||
static const unsigned char privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
int pid = __syscall(SYS_getpid);
|
||||
unsigned char caps[16];
|
||||
unsigned long rootdir;
|
||||
int err;
|
||||
|
||||
if(!(rootdir=kernel_get_proc_rootdir(pid))) {
|
||||
return -1;
|
||||
}
|
||||
if(kernel_get_ucred_caps(pid, caps)) {
|
||||
return -1;
|
||||
}
|
||||
if(kernel_set_proc_rootdir(pid, kernel_get_root_vnode())) {
|
||||
return -1;
|
||||
}
|
||||
if(kernel_set_ucred_caps(pid, privcaps)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!KERNEL_DLSYM(0x2, memcpy)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = payload_load();
|
||||
|
||||
if(kernel_set_proc_rootdir(pid, rootdir)) {
|
||||
return -1;
|
||||
}
|
||||
if(kernel_set_ucred_caps(pid, caps)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__rtld_payload_fini(void) {
|
||||
int err;
|
||||
|
||||
err =__rtld_lib_close(g_libhead);
|
||||
__rtld_lib_destroy(g_libhead);
|
||||
|
||||
return err;
|
||||
}
|
||||
+738
@@ -0,0 +1,738 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "elf.h"
|
||||
#include "kernel.h"
|
||||
#include "klog.h"
|
||||
#include "rtld.h"
|
||||
#include "syscall.h"
|
||||
|
||||
|
||||
/**
|
||||
* Dependencies to standard libraries.
|
||||
**/
|
||||
static char* (*strdup)(const char*) = 0;
|
||||
static int (*strcmp)(const char*, const char*) = 0;
|
||||
static char* (*strcat)(char*, const char*) = 0;
|
||||
static char* (*strcpy)(char*, const char*) = 0;
|
||||
|
||||
static void* (*malloc)(unsigned long) = 0;
|
||||
static void* (*calloc)(unsigned long, unsigned long) = 0;
|
||||
static void* (*memcpy)(void*, const void*, unsigned long) = 0;
|
||||
static void (*free)(void*) = 0;
|
||||
|
||||
static char* (*getcwd)(char*, unsigned long) = 0;
|
||||
static char* (*getenv)(const char*) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Standard libc macros.
|
||||
**/
|
||||
#define PROT_NONE 0x00
|
||||
#define PROT_READ 0x01
|
||||
#define PROT_WRITE 0x02
|
||||
#define PROT_EXEC 0x04
|
||||
|
||||
#define MAP_SHARED 0x0001
|
||||
#define MAP_PRIVATE 0x0002
|
||||
#define MAP_FIXED 0x0010
|
||||
#define MAP_ANON 0x1000
|
||||
#define MAP_FAILED ((void*)-1)
|
||||
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_END 2
|
||||
|
||||
|
||||
/**
|
||||
* Convenient macros.
|
||||
**/
|
||||
#define PAGE_SIZE 0x4000
|
||||
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
|
||||
#define TRUNC_PG(x) ((x) & ~(PAGE_SIZE - 1))
|
||||
#define PFLAGS(x) ((((x) & PF_R) ? PROT_READ : 0) | \
|
||||
(((x) & PF_W) ? PROT_WRITE : 0) | \
|
||||
(((x) & PF_X) ? PROT_EXEC : 0))
|
||||
|
||||
|
||||
/**
|
||||
* Extend the rtld_lib_t type with auxiliary parameters needed by .so loader.
|
||||
* This requires -fms-extensions.
|
||||
**/
|
||||
typedef struct rtld_so_lib {
|
||||
struct rtld_lib;
|
||||
|
||||
unsigned char* image;
|
||||
|
||||
Elf64_Ehdr *ehdr;
|
||||
Elf64_Phdr *phdr;
|
||||
Elf64_Shdr *shdr;
|
||||
|
||||
char* strtab;
|
||||
Elf64_Sym* symtab;
|
||||
unsigned long symtab_size;
|
||||
|
||||
void* base_addr;
|
||||
unsigned long base_size;
|
||||
} rtld_so_lib_t;
|
||||
|
||||
|
||||
/**
|
||||
* Convenient function for a custom sony syscall that allocates shared memory
|
||||
* with JIT code execution permissions.
|
||||
**/
|
||||
static int
|
||||
jitshm_create(const char* name, unsigned long size, int flags) {
|
||||
return (int)__syscall(0x215, name, size, flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenient function for a custom sony syscall that creates an alias to
|
||||
* JIT memory for write permissions.
|
||||
**/
|
||||
static int
|
||||
jitshm_alias(int fd, int flags) {
|
||||
return (int)__syscall(0x216, fd, flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenient function for the standard mmap syscall.
|
||||
**/
|
||||
static void*
|
||||
mmap(void* addr, unsigned long len, int prot, int flags, int fd,
|
||||
unsigned long offset) {
|
||||
return (void*)__syscall(SYS_mmap, addr, len, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenient function for the standard mprotect syscall.
|
||||
**/
|
||||
static int
|
||||
mprotect(void* addr, unsigned long len, int prot) {
|
||||
return (int)__syscall(SYS_mprotect, addr, len, prot);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenient function for the standard munmap syscall.
|
||||
**/
|
||||
static int
|
||||
munmap(void* addr, unsigned long len) {
|
||||
return (int)__syscall(SYS_munmap, addr, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a file from disk at the given path.
|
||||
**/
|
||||
static unsigned char*
|
||||
readfile(const char* path) {
|
||||
unsigned char* buf;
|
||||
long len;
|
||||
int fd;
|
||||
|
||||
if((fd=(int)__syscall(SYS_open, path, 0)) < 0) {
|
||||
klog_perror("open");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((len=__syscall(SYS_lseek, fd, 0, SEEK_END)) < 0) {
|
||||
klog_perror("lseek");
|
||||
__syscall(SYS_close, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(__syscall(SYS_lseek, fd, 0, SEEK_SET) < 0) {
|
||||
klog_perror("lseek");
|
||||
__syscall(SYS_close, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(buf=malloc(len))) {
|
||||
klog_perror("malloc");
|
||||
__syscall(SYS_close, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(__syscall(SYS_read, fd, buf, len) != len) {
|
||||
klog_perror("read");
|
||||
free(buf);
|
||||
__syscall(SYS_close, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(__syscall(SYS_close, fd) < 0) {
|
||||
klog_perror("close");
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find a shared object image with the given soname.
|
||||
*
|
||||
* The search order is as follows:
|
||||
* 1 - absolute path
|
||||
* 2 - current work dir (cwd)
|
||||
* 3 - paths in the env var LD_LIBRARY_PATH
|
||||
* 4 - /user/homebrew/lib/
|
||||
**/
|
||||
static int
|
||||
so_find(const char* cwd, const char *soname, char* path) {
|
||||
unsigned long off = 0;
|
||||
const char *ldpaths;
|
||||
int err = 0;
|
||||
|
||||
if(!soname || !*soname || !path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
path[0] = 0;
|
||||
if(soname[0] == '/') {
|
||||
if(!(err=__syscall(SYS_access, soname, 0))) {
|
||||
strcpy(path, soname);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
if(cwd && *cwd) {
|
||||
strcpy(path, cwd);
|
||||
strcat(path, "/");
|
||||
strcat(path, soname);
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((ldpaths=getenv("LD_LIBRARY_PATH"))) {
|
||||
for(int i=0; ldpaths[i]; i++) {
|
||||
path[off++] = ldpaths[i];
|
||||
if(path[off] == ':' || ldpaths[i+1] == 0) {
|
||||
path[off] = '/';
|
||||
path[off+1] = 0;
|
||||
strcat(path, soname);
|
||||
off = 0;
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(path, "/user/homebrew/lib/");
|
||||
strcat(path, soname);
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
path[0] = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_GLOB_DAT relocation type.
|
||||
**/
|
||||
static int
|
||||
r_glob_dat(rtld_so_lib_t* lib, Elf64_Rela* rela) {
|
||||
Elf64_Sym* sym = lib->symtab + ELF64_R_SYM(rela->r_info);
|
||||
const char* name = lib->strtab + sym->st_name;
|
||||
void* loc = lib->base_addr + rela->r_offset;
|
||||
void* val = 0;
|
||||
|
||||
for(rtld_lib_t *l=(rtld_lib_t *)lib->next; l!=0; l=l->next) {
|
||||
if((val=__rtld_lib_sym(l, name))) {
|
||||
memcpy(loc, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
klog_printf("%s: unable to resolve '%s'\n", lib->soname, name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_GLOB_DAT relocation type.
|
||||
**/
|
||||
static int
|
||||
r_jmp_slot(rtld_so_lib_t* lib, Elf64_Rela* rela) {
|
||||
return r_glob_dat(lib, rela);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_64 relocation type.
|
||||
**/
|
||||
static int
|
||||
r_direct_64(rtld_so_lib_t* lib, Elf64_Rela* rela) {
|
||||
Elf64_Sym* sym = lib->symtab + ELF64_R_SYM(rela->r_info);
|
||||
const char* name = lib->strtab + sym->st_name;
|
||||
void* loc = lib->base_addr + rela->r_offset;
|
||||
void* val = 0;
|
||||
|
||||
for(rtld_lib_t *l=(rtld_lib_t *)lib->next; l!=0; l=l->next) {
|
||||
if((val=__rtld_lib_sym(l, name))) {
|
||||
val += rela->r_addend;
|
||||
memcpy(loc, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
klog_printf("%s: unable to resolve '%s'\n", lib->soname, name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the R_X86_64_RELATIVE relocation type.
|
||||
**/
|
||||
static int
|
||||
r_relative(rtld_so_lib_t *lib, Elf64_Rela* rela) {
|
||||
void* loc = lib->base_addr + rela->r_offset;
|
||||
void* val = lib->base_addr + rela->r_addend;
|
||||
|
||||
memcpy(loc, &val, sizeof(val));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the DT_NEEDED entry in the .dynamic section.
|
||||
**/
|
||||
static int
|
||||
dt_needed(rtld_so_lib_t *lib, const char* soname) {
|
||||
rtld_lib_t* it = (rtld_lib_t*)lib;
|
||||
rtld_lib_t* needed;
|
||||
|
||||
if(!(needed=__rtld_lib_new(it, soname))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(__rtld_lib_open(needed)) {
|
||||
klog_printf("%s: unable to load '%s'\n", lib->soname, soname);
|
||||
__rtld_lib_destroy(needed);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(it->next) {
|
||||
it = it->next;
|
||||
}
|
||||
it->next = needed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process a program header with the entry type PT_LOAD.
|
||||
**/
|
||||
static int
|
||||
pt_load(rtld_so_lib_t *lib, Elf64_Phdr *phdr) {
|
||||
if(!phdr->p_memsz) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!phdr->p_filesz) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(lib->base_addr + phdr->p_vaddr,
|
||||
lib->image + phdr->p_offset,
|
||||
phdr->p_filesz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reload a PT_LOAD program header that needs executable permissions.
|
||||
*
|
||||
* This is required to circumvent restrictions Sony put into place when user
|
||||
* space processes attempts to allocate memory with execute permissions.
|
||||
* We circumvent the protection using JIT capabillities provided by a couple of
|
||||
* custom Sony syscalls.
|
||||
*
|
||||
* Note: code allocated via JIT are not permitted to run syscall instructions.
|
||||
* To make syscalls, payloads can instead slide into a page that can,
|
||||
* e.g., at getpid+0xa in libkernel.sprx.
|
||||
**/
|
||||
static int
|
||||
pt_reload(rtld_so_lib_t *lib, Elf64_Phdr *phdr) {
|
||||
unsigned long memsz = ROUND_PG(phdr->p_memsz);
|
||||
void* addr = lib->base_addr + phdr->p_vaddr;
|
||||
int prot = PFLAGS(phdr->p_flags);
|
||||
int alias_fd = -1;
|
||||
int shm_fd = -1;
|
||||
int error = 0;
|
||||
void* data;
|
||||
void* addrx = 0;
|
||||
void* addrw = 0;
|
||||
|
||||
// Backup data.
|
||||
if(!(data=malloc(memsz))) {
|
||||
klog_perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
memcpy(data, addr, memsz);
|
||||
|
||||
// Create shm with executable permissions.
|
||||
if((shm_fd=jitshm_create(0, memsz, prot | PROT_WRITE | PROT_EXEC)) < 0) {
|
||||
klog_perror("jitshm_create");
|
||||
error = -1;
|
||||
}
|
||||
// Create an shm alias fd with write permissions.
|
||||
else if((alias_fd=jitshm_alias(shm_fd, PROT_WRITE)) < 0) {
|
||||
klog_perror("jitshm_alias");
|
||||
error = -1;
|
||||
}
|
||||
// Map shm into an executable address space.
|
||||
else if((addrx=mmap(addr, memsz, prot, MAP_FIXED | MAP_PRIVATE,
|
||||
shm_fd, 0)) == MAP_FAILED) {
|
||||
klog_perror("mmap");
|
||||
error = -1;
|
||||
}
|
||||
// Map shm alias into a writable address space.
|
||||
else if((addrw=mmap(0, memsz, PROT_WRITE, MAP_SHARED,
|
||||
alias_fd, 0)) == MAP_FAILED) {
|
||||
klog_perror("mmap");
|
||||
error = -1;
|
||||
}
|
||||
// Resore data.
|
||||
else {
|
||||
memcpy(addrw, data, memsz);
|
||||
munmap(addrw, memsz);
|
||||
}
|
||||
|
||||
// Cleanup.
|
||||
free(data);
|
||||
if(alias_fd != -1) {
|
||||
__syscall(SYS_close, alias_fd);
|
||||
}
|
||||
if(shm_fd != -1) {
|
||||
__syscall(SYS_close, shm_fd);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process a program header with the entry type PT_DYNAMIC.
|
||||
**/
|
||||
static int
|
||||
pt_dynamic(rtld_so_lib_t *lib, Elf64_Phdr *phdr) {
|
||||
Elf64_Dyn *dyn = (Elf64_Dyn *)(lib->image + phdr->p_offset);
|
||||
unsigned int *gnu_hash = 0;
|
||||
|
||||
// find lookup tables
|
||||
for(unsigned long i=0; dyn[i].d_tag!=DT_NULL; i++) {
|
||||
switch (dyn[i].d_tag) {
|
||||
case DT_SYMTAB:
|
||||
lib->symtab = (Elf64_Sym*)(lib->image + lib->phdr->p_offset +
|
||||
dyn[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_GNU_HASH:
|
||||
gnu_hash = (unsigned int*)(lib->image + lib->phdr->p_offset +
|
||||
dyn[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_STRTAB:
|
||||
lib->strtab = (char*)(lib->image + lib->phdr->p_offset +
|
||||
dyn[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// figure out the symtab size
|
||||
if(gnu_hash) {
|
||||
lib->symtab_size = gnu_hash[0] + gnu_hash[1] + gnu_hash[2];
|
||||
lib->symtab_size *= sizeof(Elf64_Sym);
|
||||
}
|
||||
|
||||
// load needed libraries
|
||||
for(unsigned long i=0; dyn[i].d_tag!=DT_NULL; i++) {
|
||||
switch (dyn[i].d_tag) {
|
||||
case DT_NEEDED:
|
||||
if(dt_needed(lib, lib->strtab + dyn[i].d_un.d_ptr)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a shared object into memory, and parse its attributes.
|
||||
**/
|
||||
static int
|
||||
so_load(rtld_so_lib_t* lib, const char* path) {
|
||||
unsigned long min_vaddr = -1;
|
||||
unsigned long max_vaddr = 0;
|
||||
Elf64_Rela* rela;
|
||||
int error = 0;
|
||||
|
||||
if(!(lib->image=readfile(path))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lib->ehdr = (Elf64_Ehdr*)lib->image;
|
||||
lib->phdr = (Elf64_Phdr*)(lib->image + lib->ehdr->e_phoff);
|
||||
lib->shdr = (Elf64_Shdr*)(lib->image + lib->ehdr->e_shoff);
|
||||
|
||||
// compute size of virtual memory region
|
||||
for(unsigned long i=0; i<lib->ehdr->e_phnum; i++) {
|
||||
if(lib->phdr[i].p_vaddr < min_vaddr) {
|
||||
min_vaddr = lib->phdr[i].p_vaddr;
|
||||
}
|
||||
|
||||
if(max_vaddr < lib->phdr[i].p_vaddr + lib->phdr[i].p_memsz) {
|
||||
max_vaddr = lib->phdr[i].p_vaddr + lib->phdr[i].p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
min_vaddr = TRUNC_PG(min_vaddr);
|
||||
max_vaddr = ROUND_PG(max_vaddr);
|
||||
lib->base_size = max_vaddr - min_vaddr;
|
||||
|
||||
int flags = MAP_PRIVATE | MAP_ANON;
|
||||
int prot = PROT_READ | PROT_WRITE;
|
||||
if(lib->ehdr->e_type != ET_DYN) {
|
||||
klog_printf("%s: Not a shared object\n", lib->soname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reserve an address space of sufficient size
|
||||
if((lib->base_addr=mmap(0, lib->base_size, prot, flags,
|
||||
-1, 0)) == MAP_FAILED) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(unsigned long i=0; i<lib->ehdr->e_phnum && !error; i++) {
|
||||
switch(lib->phdr[i].p_type) {
|
||||
case PT_LOAD:
|
||||
error = pt_load(lib, &lib->phdr[i]);
|
||||
break;
|
||||
|
||||
case PT_DYNAMIC:
|
||||
error = pt_dynamic(lib, &lib->phdr[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned long i=0; i<lib->ehdr->e_shnum && !error; i++) {
|
||||
if(lib->shdr[i].sh_type != SHT_RELA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rela = (Elf64_Rela*)(lib->image + lib->shdr[i].sh_offset);
|
||||
for(int j=0; j<lib->shdr[i].sh_size/sizeof(Elf64_Rela); j++) {
|
||||
switch(rela[j].r_info & 0xffffffffl) {
|
||||
|
||||
case R_X86_64_GLOB_DAT:
|
||||
error = r_glob_dat(lib, &rela[j]);
|
||||
break;
|
||||
|
||||
case R_X86_64_64:
|
||||
error = r_direct_64(lib, &rela[j]);
|
||||
break;
|
||||
|
||||
case R_X86_64_JMP_SLOT:
|
||||
error = r_jmp_slot(lib, &rela[j]);
|
||||
break;
|
||||
|
||||
case R_X86_64_RELATIVE:
|
||||
error = r_relative(lib, &rela[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set protection bits on mapped memory
|
||||
for(int i=0; i<lib->ehdr->e_phnum && !error; i++) {
|
||||
if(lib->phdr[i].p_type != PT_LOAD || lib->phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lib->phdr[i].p_flags & PF_X) {
|
||||
error = pt_reload(lib, &lib->phdr[i]);
|
||||
} else {
|
||||
if(mprotect(lib->base_addr + lib->phdr[i].p_vaddr,
|
||||
ROUND_PG(lib->phdr[i].p_memsz),
|
||||
PFLAGS(lib->phdr[i].p_flags))) {
|
||||
klog_perror("mprotect");
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(error) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
so_open(rtld_lib_t* ctx) {
|
||||
rtld_so_lib_t* lib = (rtld_so_lib_t*)ctx;
|
||||
char path[0x400];
|
||||
char cwd[0x400];
|
||||
|
||||
if(!getcwd(cwd, sizeof(cwd))) {
|
||||
klog_perror("getcwd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(so_find(cwd, lib->soname, path)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return so_load(lib, path);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
so_close(rtld_lib_t* ctx) {
|
||||
rtld_so_lib_t* lib = (rtld_so_lib_t*)ctx;
|
||||
|
||||
if(lib->image) {
|
||||
free(lib->image);
|
||||
}
|
||||
if(lib->base_addr) {
|
||||
munmap(lib->base_addr, lib->base_size);
|
||||
}
|
||||
|
||||
lib->image = 0;
|
||||
lib->ehdr = 0;
|
||||
lib->phdr = 0;
|
||||
lib->shdr = 0;
|
||||
lib->strtab = 0;
|
||||
lib->symtab = 0;
|
||||
lib->symtab_size = 0;
|
||||
lib->base_addr = 0;
|
||||
lib->base_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void*
|
||||
so_sym(rtld_lib_t* ctx, const char* name) {
|
||||
rtld_so_lib_t* lib = (rtld_so_lib_t*)ctx;
|
||||
|
||||
if(!lib->symtab || !lib->strtab || !lib->base_addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(unsigned long i=0; i<lib->symtab_size/sizeof(Elf64_Sym); i++) {
|
||||
if(!lib->symtab[i].st_size) {
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(name, lib->strtab + lib->symtab[i].st_name)) {
|
||||
return lib->base_addr + lib->symtab[i].st_value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
so_destroy(rtld_lib_t* ctx) {
|
||||
rtld_so_lib_t* lib = (rtld_so_lib_t*)ctx;
|
||||
|
||||
so_close(ctx);
|
||||
|
||||
free(lib->soname);
|
||||
free(lib);
|
||||
}
|
||||
|
||||
|
||||
rtld_lib_t*
|
||||
__rtld_so_new(rtld_lib_t* prev, const char *soname) {
|
||||
rtld_so_lib_t* lib = calloc(1, sizeof(rtld_so_lib_t));
|
||||
|
||||
lib->soname = strdup(soname);
|
||||
lib->prev = prev;
|
||||
lib->open = so_open;
|
||||
lib->sym = so_sym;
|
||||
lib->close = so_close;
|
||||
lib->destroy = so_destroy;
|
||||
|
||||
return (rtld_lib_t*)lib;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__rtld_so_init(void) {
|
||||
unsigned int libc = 0x2;
|
||||
|
||||
if(!KERNEL_DLSYM(libc, strdup)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, strcmp)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, strcat)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, strcpy)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, malloc)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, calloc)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, memcpy)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, free)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, getcwd)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, getenv)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+481
@@ -0,0 +1,481 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "elf.h"
|
||||
#include "klog.h"
|
||||
#include "kernel.h"
|
||||
#include "nid.h"
|
||||
#include "rtld.h"
|
||||
#include "syscall.h"
|
||||
|
||||
|
||||
/**
|
||||
* Dependencies to standard libraries.
|
||||
**/
|
||||
static char* (*strdup)(const char*) = 0;
|
||||
static int (*strcmp)(const char*, const char*) = 0;
|
||||
static int (*strncmp)(const char*, const char*, unsigned long) = 0;
|
||||
static int (*sprintf)(char*, const char*, ...) = 0;
|
||||
|
||||
static void* (*calloc)(unsigned long, unsigned long) = 0;
|
||||
static void* (*malloc)(unsigned long) = 0;
|
||||
static void (*free)(void*) = 0;
|
||||
|
||||
static char* (*getcwd)(char*, unsigned long) = 0;
|
||||
|
||||
static int (*sceKernelLoadStartModule)(const char*, unsigned long, const void*,
|
||||
unsigned int, void*, int*) = 0;
|
||||
static int (*sceKernelStopUnloadModule)(int, unsigned long, const void*, unsigned int,
|
||||
const void*, void*) = 0;
|
||||
static int (*sceSysmoduleLoadModuleInternal)(unsigned int) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Extend the rtld_lib_t type with auxiliary parameters needed by .sprx loader.
|
||||
* This requires -fms-extensions.
|
||||
**/
|
||||
typedef struct rtld_sprx_lib {
|
||||
struct rtld_lib;
|
||||
|
||||
int handle;
|
||||
char* strtab;
|
||||
Elf64_Sym* symtab;
|
||||
unsigned long symtab_size;
|
||||
|
||||
void* base_addr;
|
||||
unsigned long base_size;
|
||||
|
||||
int unload_on_close;
|
||||
} rtld_sprx_lib_t;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
typedef struct sysmodtab {
|
||||
const char* name;
|
||||
unsigned int handle;
|
||||
} sysmodtab_t;
|
||||
|
||||
|
||||
/**
|
||||
* Lookup table for sceSysmoduleLoadModuleInternal().
|
||||
**/
|
||||
static const sysmodtab_t sysmodtab[] = {
|
||||
{"libSceAbstractLocal.sprx", 0x8000005f},
|
||||
{"libSceAbstractStorage.sprx", 0x80000058},
|
||||
{"libSceAbstractTcs.sprx", 0x800000a1},
|
||||
{"libSceAbstractTwitter.sprx", 0x80000062},
|
||||
{"libSceAbstractYoutube.sprx", 0x80000061},
|
||||
{"libSceAc3Enc.sprx", 0x80000013},
|
||||
{"libSceAgc.sprx", 0x80000094},
|
||||
{"libSceAgcDriver.sprx", 0x80000080},
|
||||
{"libSceAgcResourceRegistration.sprx", 0x80000093},
|
||||
{"libSceAgcVsh.sprx", 0x80000086},
|
||||
{"libSceAgcVshDebug.sprx", 0x80000087},
|
||||
{"libSceAjm.native.sprx", 0x80000023},
|
||||
{"libSceAjmi.sprx", 0x8000007e},
|
||||
{"libSceAmpr.sprx", 0x800000b7},
|
||||
{"libSceAppChecker.sprx", 0x80000032},
|
||||
{"libSceAppDbShellCoreClient.sprx", 0x800000a7},
|
||||
{"libSceAppInstUtil.sprx", 0x80000014},
|
||||
{"libSceAsyncStorageInternal.sprx", 0x80000077},
|
||||
{"libSceAudioIn.sprx", 0x80000002},
|
||||
{"libSceAudioOut.sprx", 0x80000001},
|
||||
{"libSceAudioSystem.sprx", 0x80000083},
|
||||
{"libSceAudiodecCpuDtsHdMa.sprx", 0x8000002d},
|
||||
{"libSceAudiodecCpuLpcm.sprx", 0x8000002e},
|
||||
{"libSceAudiodecCpuTrhd.sprx", 0x80000082},
|
||||
{"libSceAvSetting.sprx", 0x80000021},
|
||||
{"libSceAvcap2.sprx", 0x80000085},
|
||||
{"libSceBackupRestoreUtil.sprx", 0x8000003f},
|
||||
{"libSceBgft.sprx", 0x8000002a},
|
||||
{"libSceBgsStorage.sprx", 0x800000a3},
|
||||
{"libSceCamera.sprx", 0x8000001a},
|
||||
{"libSceCdlgUtilServer.sprx", 0x80000007},
|
||||
{"libSceCommonDialog.sprx", 0x80000018},
|
||||
{"libSceComposite.sprx", 0x8000008a},
|
||||
{"libSceCompositeExt.sprx", 0x8000008b},
|
||||
{"libSceContentListController.sprx", 0x800000ad},
|
||||
{"libSceDataTransfer.sprx", 0x80000057},
|
||||
{"libSceDbg.sprx", 0x80000025},
|
||||
{"libSceDipsw.sprx", 0x80000029},
|
||||
{"libSceDseehx.sprx", 0x80000056},
|
||||
{"libSceDtsEnc.sprx", 0x80000028},
|
||||
{"libSceEmbeddedTts.sprx", 0x8000009c},
|
||||
{"libSceEmbeddedTtsCoreG3.sprx", 0x8000009b},
|
||||
{"libSceFsInternalForVsh.sprx", 0x80000066},
|
||||
{"libSceGLSlimVSH.sprx", 0x800000a9},
|
||||
{"libSceGifParser.sprx", 0x8000005e},
|
||||
{"libSceGpuCapture.sprx", 0x8000007f},
|
||||
{"libSceGpuTrace.sprx", 0x8000007b},
|
||||
{"libSceGvMp4Parser.sprx", 0x8000005c},
|
||||
{"libSceHidControl.sprx", 0x80000017},
|
||||
{"libSceHttp.sprx", 0x8000000a},
|
||||
{"libSceHttp2.sprx", 0x8000008c},
|
||||
{"libSceHttpCache.sprx", 0x80000078},
|
||||
{"libSceIcu.sprx", 0x800000a8},
|
||||
{"libSceIdu.sprx", 0x800000a6},
|
||||
{"libSceImageUtil.sprx", 0x80000059},
|
||||
{"libSceIpmi.sprx", 0x8000001d},
|
||||
{"libSceJemspace.sprx", 0x8000009e},
|
||||
{"libSceJitBridge.sprx", 0x8000006f},
|
||||
{"libSceJpegParser.sprx", 0x8000005b},
|
||||
{"libSceJsc.sprx", 0x800000b0},
|
||||
{"libSceJscCompiler.sprx", 0x80000070},
|
||||
{"libSceJxr.sprx", 0x800000b4},
|
||||
{"libSceJxrParser.sprx", 0x800000b5},
|
||||
{"libSceKbEmulate.sprx", 0x80000031},
|
||||
{"libSceLibreSsl.sprx", 0x80000065},
|
||||
{"libSceLibreSsl3.sprx", 0x800000b8},
|
||||
{"libSceLoginMgrServer.sprx", 0x80000045},
|
||||
{"libSceMarlin.sprx", 0x80000027},
|
||||
{"libSceMat.sprx", 0x80000048},
|
||||
{"libSceMbus.sprx", 0x8000001e},
|
||||
{"libSceMediaFrameworkInterface.sprx", 0x80000095},
|
||||
{"libSceMediaFrameworkUtil.sprx", 0x800000b6},
|
||||
{"libSceMetadataReaderWriter.sprx", 0x8000005a},
|
||||
{"libSceNKWeb.sprx", 0x80000079},
|
||||
{"libSceNKWebKit.sprx", 0x8000007a},
|
||||
{"libSceNet.sprx", 0x8000001c},
|
||||
{"libSceNetCtl.sprx", 0x80000009},
|
||||
{"libSceNgs2.sprx", 0x80000090},
|
||||
{"libSceNpCommon.sprx", 0x8000000c},
|
||||
{"libSceNpGameIntent.sprx", 0x8000008d},
|
||||
{"libSceNpManager.sprx", 0x8000000d},
|
||||
{"libSceNpRemotePlaySessionSignaling.sprx", 0x8000009a},
|
||||
{"libSceNpSns.sprx", 0x8000001b},
|
||||
{"libSceNpTcs.sprx", 0x800000a0},
|
||||
{"libSceNpWebApi.sprx", 0x8000000e},
|
||||
{"libSceNpWebApi2.sprx", 0x8000008f},
|
||||
{"libSceOpusCeltDec.sprx", 0x80000044},
|
||||
{"libSceOpusCeltEnc.sprx", 0x80000043},
|
||||
{"libSceOpusDec.sprx", 0x80000069},
|
||||
{"libSceOpusSilkEnc.sprx", 0x80000068},
|
||||
{"libSceOrbisCompat.sprx", 0x80000071},
|
||||
{"libScePad.sprx", 0x80000024},
|
||||
{"libScePngParser.sprx", 0x8000005d},
|
||||
{"libScePosixForWebKit.sprx", 0x80000098},
|
||||
{"libScePsm.sprx", 0x80000030},
|
||||
{"libSceRazorCpu_debug.sprx", 0x80000075},
|
||||
{"libSceRegMgr.sprx", 0x8000001f},
|
||||
{"libSceRemotePlayClientIpc.sprx", 0x800000b9},
|
||||
{"libSceResourceArbitrator.sprx", 0x80000092},
|
||||
{"libSceRnpsAppMgr.sprx", 0x80000076},
|
||||
{"libSceRtc.sprx", 0x80000020},
|
||||
{"libSceSaveData.sprx", 0x8000000f},
|
||||
{"libSceShareInternal.native.sprx", 0x8000008e},
|
||||
{"libSceSocialScreen.sprx", 0x800000ae},
|
||||
{"libSceSsl.sprx", 0x8000000b},
|
||||
{"libSceSulphaDrv.sprx", 0x8000003b},
|
||||
{"libSceSysCore.sprx", 0x80000004},
|
||||
{"libSceSysUtil.sprx", 0x80000026},
|
||||
{"libSceSystemLogger2.sprx", 0x800000b3},
|
||||
{"libSceSystemLogger2Delivery.sprx", 0x80000089},
|
||||
{"libSceSystemLogger2Game.sprx", 0x8000009f},
|
||||
{"libSceSystemLogger2NativeQueueClient.sprx", 0x80000088},
|
||||
{"libSceSystemService.sprx", 0x80000010},
|
||||
{"libSceSystemTts.sprx", 0x80000097},
|
||||
{"libSceTEEClient.sprx", 0x800000a2},
|
||||
{"libSceUserService.sprx", 0x80000011},
|
||||
{"libSceVcodec.sprx", 0x80000091},
|
||||
{"libSceVdecCore.native.sprx", 0x80000015},
|
||||
{"libSceVdecSavc2.native.sprx", 0x80000036},
|
||||
{"libSceVdecShevc.native.sprx", 0x8000003c},
|
||||
{"libSceVdecSvp9.native.sprx", 0x800000af},
|
||||
{"libSceVenc.sprx", 0x80000084},
|
||||
{"libSceVideoOut.sprx", 0x80000022},
|
||||
{"libSceVideoOutSecondary.sprx", 0x80000046},
|
||||
{"libSceVideoStreamingEngine_sys.sprx", 0x800000b2},
|
||||
{"libSceVisionManager.sprx", 0x80000012},
|
||||
{"libSceVnaInternal.sprx", 0x8000007c},
|
||||
{"libSceVnaWebsocket.sprx", 0x8000007d},
|
||||
{"libSceVoiceCommand.sprx", 0x80000099},
|
||||
{"libSceWeb.sprx", 0x80000072},
|
||||
{"libSceWebKit2.sprx", 0x80000073},
|
||||
{"libSceWebKit2Secure.sprx", 0x80000074},
|
||||
{"libSceWebmParserMdrw.sprx", 0x800000a4},
|
||||
{"libcairo.sprx", 0x800000ac},
|
||||
{"libcurl.sprx", 0x800000b1},
|
||||
{"libicu.sprx", 0x800000aa},
|
||||
{"libpng16.sprx", 0x800000ab}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Figure out the absolute path to an sprx file.
|
||||
**/
|
||||
static int
|
||||
sprx_find(const char* cwd, const char* soname, char *path) {
|
||||
if(*soname == '/') {
|
||||
sprintf(path, "%s", soname);
|
||||
} else if(cwd) {
|
||||
sprintf(path, "%s/%s", cwd, soname);
|
||||
} else {
|
||||
sprintf(path, "%s", soname);
|
||||
}
|
||||
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(path, "/system/priv/lib/%s", soname);
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(path, "/system/common/lib/%s", soname);
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(path, "/system_ex/priv_ex/lib/%s", soname);
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(path, "/system_ex/common_ex/lib/%s", soname);
|
||||
if(!__syscall(SYS_access, path, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
sprx_open(rtld_lib_t* ctx) {
|
||||
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
||||
unsigned int handle = 0;
|
||||
dynlib_dynsec_t dynsec;
|
||||
dynlib_obj_t obj;
|
||||
char path[0x400];
|
||||
char cwd[0x400];
|
||||
int unload = 0;
|
||||
int error = 0;
|
||||
|
||||
// check if lib is is an alias for libkernel
|
||||
if(!strcmp(lib->soname, "libkernel.sprx") ||
|
||||
!strcmp(lib->soname, "libkernel_web.sprx") ||
|
||||
!strcmp(lib->soname, "libkernel_sys.sprx") ||
|
||||
!strcmp(lib->soname, "libdl.sprx") ||
|
||||
!strcmp(lib->soname, "libpthread.sprx")) {
|
||||
if(kernel_dynlib_dlsym(-1, 0x1, "sceKernelDlsym")) {
|
||||
handle = 1;
|
||||
} else {
|
||||
handle = 0x2001;
|
||||
}
|
||||
}
|
||||
// check if lib is already opened
|
||||
else if(kernel_dynlib_handle(-1, lib->soname, &handle) < 0) {
|
||||
if(!getcwd(cwd, sizeof(cwd))) {
|
||||
klog_perror("getcwd");
|
||||
return -1;
|
||||
}
|
||||
if(sprx_find(cwd, lib->soname, path)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i=0; i<sizeof(sysmodtab)/sizeof(sysmodtab[0]); i++) {
|
||||
if(!strcmp(lib->soname, sysmodtab[i].name)) {
|
||||
if((error=sceSysmoduleLoadModuleInternal(sysmodtab[i].handle))) {
|
||||
klog_printf("sceSysmoduleLoadModuleInternal: 0x%x\n", error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) < 0) {
|
||||
klog_printf("sceKernelLoadStartModule: 0x%x\n", handle);
|
||||
return -1;
|
||||
}
|
||||
unload = 1;
|
||||
}
|
||||
|
||||
if(kernel_dynlib_obj(-1, handle, &obj) < 0) {
|
||||
error = 1;
|
||||
}
|
||||
else if(kernel_copyout(obj.dynsec, &dynsec, sizeof(dynsec)) < 0) {
|
||||
error = 1;
|
||||
}
|
||||
else if(!(lib->strtab=malloc(dynsec.strtabsize))) {
|
||||
klog_perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
else if(kernel_copyout(dynsec.strtab, lib->strtab, dynsec.strtabsize) < 0) {
|
||||
error = 1;
|
||||
}
|
||||
else if(!(lib->symtab=malloc(dynsec.symtabsize))) {
|
||||
klog_perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
else if(kernel_copyout(dynsec.symtab, lib->symtab, dynsec.symtabsize) < 0) {
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if(error) {
|
||||
klog_puts("Unknown kernel I/O error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lib->handle = handle;
|
||||
lib->unload_on_close = unload;
|
||||
lib->base_addr = (void*)obj.mapbase;
|
||||
lib->symtab_size = dynsec.symtabsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void*
|
||||
sprx_sym(rtld_lib_t* ctx, const char* name) {
|
||||
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
||||
char nid[12];
|
||||
|
||||
if(!lib->symtab || !lib->strtab || !lib->base_addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nid_encode(name, nid);
|
||||
|
||||
for(unsigned long i=0; i<lib->symtab_size/sizeof(Elf64_Sym); i++) {
|
||||
if(!lib->symtab[i].st_size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(nid, lib->strtab + lib->symtab[i].st_name, 11)) {
|
||||
return lib->base_addr + lib->symtab[i].st_value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
sprx_close(rtld_lib_t* ctx) {
|
||||
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
||||
int err = 0;
|
||||
|
||||
if(lib->unload_on_close) {
|
||||
if((err=sceKernelStopUnloadModule(lib->handle, 0, 0, 0, 0, 0))) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if(lib->strtab) {
|
||||
free(lib->strtab);
|
||||
}
|
||||
if(lib->symtab) {
|
||||
free(lib->symtab);
|
||||
}
|
||||
|
||||
lib->handle = -1;
|
||||
lib->strtab = 0;
|
||||
lib->symtab = 0;
|
||||
lib->symtab_size = 0;
|
||||
lib->base_addr = 0;
|
||||
lib->base_size = 0;
|
||||
lib->unload_on_close = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sprx_destroy(rtld_lib_t* ctx) {
|
||||
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
||||
|
||||
if(sprx_close(ctx)) {
|
||||
lib->unload_on_close = 0;
|
||||
sprx_close(ctx);
|
||||
}
|
||||
|
||||
free(lib->soname);
|
||||
free(lib);
|
||||
}
|
||||
|
||||
|
||||
rtld_lib_t*
|
||||
__rtld_sprx_new(rtld_lib_t* prev, const char *soname) {
|
||||
rtld_sprx_lib_t* lib = calloc(1, sizeof(rtld_sprx_lib_t));
|
||||
|
||||
lib->soname = strdup(soname);
|
||||
lib->prev = prev;
|
||||
lib->open = sprx_open;
|
||||
lib->sym = sprx_sym;
|
||||
lib->close = sprx_close;
|
||||
lib->destroy = sprx_destroy;
|
||||
|
||||
return (rtld_lib_t*)lib;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__rtld_sprx_init(void) {
|
||||
unsigned int libSceSysmodule;
|
||||
unsigned int libkernel = 0x1;
|
||||
unsigned int libc = 0x2;
|
||||
|
||||
if(!kernel_dynlib_dlsym(-1, libkernel, "sceKernelDlsym")) {
|
||||
libkernel = 0x2001;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libkernel, sceKernelLoadStartModule)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libkernel, sceKernelStopUnloadModule)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!KERNEL_DLSYM(libc, strdup)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, strcmp)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, strncmp)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, sprintf)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, calloc)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, malloc)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, free)) {
|
||||
return -1;
|
||||
}
|
||||
if(!KERNEL_DLSYM(libc, getcwd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_dynlib_handle(-1, "libSceSysmodule.sprx", &libSceSysmodule)) {
|
||||
if((libSceSysmodule=sceKernelLoadStartModule("/system/common/lib/libSceSysmodule.sprx",
|
||||
0, 0, 0, 0, 0)) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(!KERNEL_DLSYM(libSceSysmodule, sceSysmoduleLoadModuleInternal)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,16 @@ along with this program; see the file COPYING. If not, see
|
||||
|
||||
#define SYS_read 3
|
||||
#define SYS_write 4
|
||||
#define SYS_open 5
|
||||
#define SYS_close 6
|
||||
#define SYS_getpid 20
|
||||
#define SYS_access 33
|
||||
#define SYS_munmap 73
|
||||
#define SYS_mprotect 74
|
||||
#define SYS_setsockopt 105
|
||||
#define SYS_sysctl 202
|
||||
#define SYS_mmap 477
|
||||
#define SYS_lseek 478
|
||||
#define SYS_mdbg_call 573
|
||||
#define SYS_sprx_dlsym 591
|
||||
#define SYS_sprx_load 594
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ SECTIONS {
|
||||
PROVIDE_HIDDEN(__fini_array_end = .);
|
||||
} : ph_rodata
|
||||
|
||||
.eh_frame_hdr : {
|
||||
.eh_frame_hdr : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
PROVIDE_HIDDEN(__eh_frame_hdr_start = .);
|
||||
KEEP(*(.eh_frame_hdr))
|
||||
PROVIDE_HIDDEN(__eh_frame_hdr_end = .);
|
||||
|
||||
@@ -48,7 +48,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "")
|
||||
#
|
||||
# We only support positional independent executables
|
||||
#
|
||||
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available")
|
||||
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs turned off by default")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "")
|
||||
|
||||
#
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
|
||||
/**
|
||||
* See crt/rtld.h.
|
||||
**/
|
||||
struct rtld_lib;
|
||||
typedef struct rtld_lib rtld_lib_t;
|
||||
|
||||
rtld_lib_t* __rtld_lib_new(rtld_lib_t* prev, const char* soname);
|
||||
int __rtld_lib_open(rtld_lib_t* ctx);
|
||||
void* __rtld_lib_sym(rtld_lib_t* ctx, const char* name);
|
||||
int __rtld_lib_close(rtld_lib_t* ctx);
|
||||
void __rtld_lib_destroy(rtld_lib_t* ctx);
|
||||
|
||||
|
||||
char* _Strerror(int, char*);
|
||||
static int g_dlerrno = 0;
|
||||
|
||||
|
||||
void*
|
||||
dlopen(const char *filename, int flags) {
|
||||
rtld_lib_t* lib;
|
||||
|
||||
if(!(flags & RTLD_MODEMASK)) {
|
||||
g_dlerrno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
if(flags & RTLD_TRACE) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
if(flags & RTLD_NOW) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
if(flags & RTLD_GLOBAL) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(lib=__rtld_lib_new(0, filename))) {
|
||||
g_dlerrno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
if((g_dlerrno=__rtld_lib_open(lib))) {
|
||||
__rtld_lib_destroy(lib);
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_dlerrno = 0;
|
||||
return lib;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
dlsym(void *handle, const char *symbol) {
|
||||
void* addr;
|
||||
|
||||
if(handle == 0) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
if(handle == RTLD_DEFAULT) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
if(handle == RTLD_NEXT) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
if(handle == RTLD_SELF) {
|
||||
g_dlerrno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(addr=__rtld_lib_sym(handle, symbol))) {
|
||||
g_dlerrno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_dlerrno = 0;
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dlclose(void *handle) {
|
||||
if(!(g_dlerrno=__rtld_lib_close(handle))) {
|
||||
__rtld_lib_destroy(handle);
|
||||
}
|
||||
|
||||
return g_dlerrno;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
dlerror(void) {
|
||||
if(g_dlerrno) {
|
||||
return _Strerror(g_dlerrno, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
*.elf
|
||||
*.o
|
||||
*~
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# Copyright (C) 2024 John Törnblom
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
PS5_HOST ?= ps5
|
||||
PS5_PORT ?= 9021
|
||||
|
||||
ifdef PS5_PAYLOAD_SDK
|
||||
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
|
||||
else
|
||||
$(error PS5_PAYLOAD_SDK is undefined)
|
||||
endif
|
||||
|
||||
ELF := hello_so.elf
|
||||
|
||||
CFLAGS := -Wall -g -Wl,--as-needed
|
||||
|
||||
# DAG:
|
||||
# hello_so.elf
|
||||
# /data/libtest.so
|
||||
# libSceLibcInternal.sprx
|
||||
# /data/libA.so
|
||||
# libSceLibcInternal.sprx
|
||||
# /data/libB.so
|
||||
# libSceRandom.sprx
|
||||
|
||||
|
||||
all: $(ELF) libtest.so
|
||||
|
||||
$(ELF): main.c libtest.so
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
libA.so: libA.c
|
||||
$(CC) $(CFLAGS) -shared -o $@ $^ -Wl,-soname=/data/$@
|
||||
|
||||
libB.so: libB.c
|
||||
$(CC) $(CFLAGS) -shared -lSceRandom -o $@ $^ -Wl,-soname=/data/$@
|
||||
|
||||
libtest.so: libtest.c libA.so libB.so
|
||||
$(CC) $(CFLAGS) -shared -o $@ $^ -Wl,-soname=/data/$@
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o *.elf
|
||||
|
||||
upload:
|
||||
curl -T libA.so ftp://$(PS5_HOST):2121/data/libA.so
|
||||
curl -T libB.so ftp://$(PS5_HOST):2121/data/libB.so
|
||||
curl -T libtest.so ftp://$(PS5_HOST):2121/data/libtest.so
|
||||
|
||||
test: $(ELF)
|
||||
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
|
||||
|
||||
debug: $(ELF)
|
||||
gdb \
|
||||
-ex "target extended-remote $(PS5_HOST):2159" \
|
||||
-ex "file $(ELF)" \
|
||||
-ex "remote put $(ELF) /data/$(ELF)" \
|
||||
-ex "set remote exec-file /data/$(ELF)" \
|
||||
-ex "start"
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
void
|
||||
libA_hexdump(uint8_t* buf, size_t size) {
|
||||
for(int i=0; i<size; i++) {
|
||||
if(i%16 == 0 && i!= 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
int sceRandomGetRandomNumber(uint8_t* buf, size_t size);
|
||||
|
||||
|
||||
int
|
||||
libB_random(uint8_t* buf, size_t size) {
|
||||
return sceRandomGetRandomNumber(buf, size);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
void libA_hexdump(uint8_t* buf, size_t size);
|
||||
int libB_random(uint8_t* buf, size_t size);
|
||||
|
||||
|
||||
void
|
||||
libtest(void) {
|
||||
uint8_t buf[0x40];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
libB_random(buf, sizeof(buf));
|
||||
libA_hexdump(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/* Copyright (C) 2024 John Törnblom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
void libtest(void);
|
||||
|
||||
int main() {
|
||||
|
||||
libtest();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user