mirror of https://github.com/flysand7/ciabatta.git
make dynamic linker perform relocs and jump into the main code
This commit is contained in:
parent
48a3a48ce8
commit
35717f62a0
8
build.py
8
build.py
|
@ -72,7 +72,7 @@ dependencies.append(args.compiler)
|
||||||
includes = ['src/include']
|
includes = ['src/include']
|
||||||
cc = args.compiler
|
cc = args.compiler
|
||||||
cc_defines = []
|
cc_defines = []
|
||||||
cc_flags = ['-nostdlib']
|
cc_flags = ['-nostdlib', '-fno-stack-protector', '-mno-sse']
|
||||||
crt_file = 'crt.lib'
|
crt_file = 'crt.lib'
|
||||||
lib_file = 'cia.lib'
|
lib_file = 'cia.lib'
|
||||||
dl_file = 'ld-cia.so'
|
dl_file = 'ld-cia.so'
|
||||||
|
@ -292,9 +292,9 @@ if target == 'linux':
|
||||||
|
|
||||||
print_step(f'Compiling {crt_file}\n')
|
print_step(f'Compiling {crt_file}\n')
|
||||||
if target == 'linux':
|
if target == 'linux':
|
||||||
assemble('src/linux/crt-entry.asm', 'bin/crt-entry.o')
|
# assemble('src/linux/crt-entry.asm', 'bin/crt-entry.o')
|
||||||
compile(['src/linux/crt-ctors.c'], 'bin/crt-ctors.o', '-c')
|
compile(['src/linux/crt-ctors.c'], 'bin/crt-ctors.o', '-c')
|
||||||
archive(['bin/crt-ctors.o', 'bin/crt-entry.o'], crt_lib)
|
archive(['bin/crt-ctors.o'], crt_lib)
|
||||||
elif target == 'windows':
|
elif target == 'windows':
|
||||||
assemble('src/windows/chkstk.asm', 'bin/chkstk.o')
|
assemble('src/windows/chkstk.asm', 'bin/chkstk.o')
|
||||||
compile(['src/windows/crt-entry.c'], 'bin/crt-entry.o', '-c')
|
compile(['src/windows/crt-entry.c'], 'bin/crt-entry.o', '-c')
|
||||||
|
@ -306,6 +306,6 @@ archive(['bin/ciabatta.o'], cia_lib)
|
||||||
|
|
||||||
if args.test:
|
if args.test:
|
||||||
if target == 'linux':
|
if target == 'linux':
|
||||||
compile([args.test, crt_lib, cia_lib], 'a', f'-pie -Wl,-dynamic-linker,{dl_lib}')
|
compile([args.test, crt_lib, cia_lib], 'a', f'-pie -Wl,-dynamic-linker,{dl_lib} -fno-stack-protector')
|
||||||
elif target == 'windows':
|
elif target == 'windows':
|
||||||
compile([args.test, crt_lib, cia_lib], 'a.exe', '-lkernel32.lib')
|
compile([args.test, crt_lib, cia_lib], 'a.exe', '-lkernel32.lib')
|
||||||
|
|
|
@ -286,6 +286,7 @@ typedef i64 Elf64_Sxword;
|
||||||
#define SHT_GROUP 17
|
#define SHT_GROUP 17
|
||||||
#define SHT_SYMTAB_SHNDX 18
|
#define SHT_SYMTAB_SHNDX 18
|
||||||
#define SHT_LOOS 0x60000000
|
#define SHT_LOOS 0x60000000
|
||||||
|
#define SHT_GNU_HASH 0x6ffffff6
|
||||||
#define SHT_HIOS 0x6fffffff
|
#define SHT_HIOS 0x6fffffff
|
||||||
#define SHT_LOPROC 0x70000000
|
#define SHT_LOPROC 0x70000000
|
||||||
#define SHT_X86_64_UNWIND 0x70000001
|
#define SHT_X86_64_UNWIND 0x70000001
|
||||||
|
|
|
@ -1,6 +1,22 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(KB)
|
||||||
|
#define KB ((i64)1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MB)
|
||||||
|
#define MB ((i64)1024*KB)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(GB)
|
||||||
|
#define GB ((i64)1024*MB)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(TB)
|
||||||
|
#define TB ((i64)1024*GB)
|
||||||
|
#endif
|
||||||
|
|
||||||
void *cia_ptr_alignf(void *ptr, u64 alignment);
|
void *cia_ptr_alignf(void *ptr, u64 alignment);
|
||||||
void *cia_ptr_alignb(void *ptr, u64 alignment);
|
void *cia_ptr_alignb(void *ptr, u64 alignment);
|
||||||
u64 cia_size_alignf(u64 size, u64 alignment);
|
u64 cia_size_alignf(u64 size, u64 alignment);
|
||||||
|
|
|
@ -15,3 +15,4 @@
|
||||||
#define O_SYNC 04010000
|
#define O_SYNC 04010000
|
||||||
#define O_FSYNC O_SYNC
|
#define O_FSYNC O_SYNC
|
||||||
#define O_ASYNC 020000
|
#define O_ASYNC 020000
|
||||||
|
#define O_CLOEXEC 02000000
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#define MAP_FIXED 0x10
|
#define MAP_FIXED 0x10
|
||||||
#define MAP_FILE 0
|
#define MAP_FILE 0
|
||||||
#define MAP_ANONYMOUS
|
|
||||||
#define MAP_ANONYMOUS 0x20
|
#define MAP_ANONYMOUS 0x20
|
||||||
#define MAP_ANON MAP_ANONYMOUS
|
#define MAP_ANON MAP_ANONYMOUS
|
||||||
#define MAP_HUGE_SHIFT 26
|
#define MAP_HUGE_SHIFT 26
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
|
|
||||||
bits 64
|
|
||||||
|
|
||||||
section .text
|
|
||||||
default rel
|
|
||||||
global _start
|
|
||||||
extern __libc_global_fini
|
|
||||||
extern __libc_global_init
|
|
||||||
extern __libc_start_main
|
|
||||||
extern main
|
|
||||||
_start:
|
|
||||||
xor ebp, ebp
|
|
||||||
;; Save rtld_fini address to r9
|
|
||||||
mov r9, rdx
|
|
||||||
;; Get argc and argv from the stack
|
|
||||||
pop rsi
|
|
||||||
mov rdx, rsp
|
|
||||||
;; Align stack to 16, push junk and stack ptr
|
|
||||||
and rsp, ~0xf
|
|
||||||
push rax
|
|
||||||
push rsp
|
|
||||||
;; Load fini and init initializers as function parameters
|
|
||||||
push rbx
|
|
||||||
lea rbx, [__libc_global_init wrt ..plt]
|
|
||||||
mov rcx, rbx
|
|
||||||
lea rbx, [__libc_global_fini wrt ..plt]
|
|
||||||
mov r8, rbx
|
|
||||||
lea rbx, [main wrt ..plt]
|
|
||||||
mov rdi, rbx
|
|
||||||
pop rbx
|
|
||||||
;; Call start main
|
|
||||||
call __libc_start_main wrt ..plt
|
|
||||||
;; No idea why halt it, I guess that's a funny
|
|
||||||
;; way to crash your application if the function we called
|
|
||||||
;; returns instead of calling the exit syscall
|
|
||||||
hlt
|
|
|
@ -11,23 +11,17 @@ void __stack_chk_fail(void) {
|
||||||
sys_exit(1);
|
sys_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int main(int argc, char **argv, char **envp);
|
||||||
static void _fileapi_init();
|
static void _fileapi_init();
|
||||||
|
|
||||||
void __libc_start_main(
|
void _start() {
|
||||||
int (*main)(int, char**, char**),
|
|
||||||
int argc, char **argv,
|
|
||||||
int (*init)(int, char**, char**),
|
|
||||||
void (*fini)(void),
|
|
||||||
void (*dl_fini)(void),
|
|
||||||
void *stack_end
|
|
||||||
) {
|
|
||||||
// Get the envp
|
// Get the envp
|
||||||
char **envp = argv + (argc + 1);
|
// char **envp = argv + (argc + 1);
|
||||||
init(argc, argv, envp);
|
// init(argc, argv, envp);
|
||||||
_fileapi_init();
|
_fileapi_init();
|
||||||
main(argc, argv, envp);
|
int code = main(0, NULL, NULL);
|
||||||
fini();
|
// fini();
|
||||||
// glibc bug
|
// glibc bug
|
||||||
// dl_fini();
|
// dl_fini();
|
||||||
sys_exit(0);
|
sys_exit(code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,126 +17,9 @@
|
||||||
#include <bin/elf.h>
|
#include <bin/elf.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
#define AUX_CNT 32
|
extern void loader_entry(Loader_Info *ld_info);
|
||||||
#define DYN_CNT 37
|
|
||||||
|
|
||||||
#define _mfence() asm volatile("" ::: "memory")
|
|
||||||
|
|
||||||
static void print_string_n(char *str, u64 len) {
|
|
||||||
sys_write(STDOUT_FILENO, str, len);
|
|
||||||
}
|
|
||||||
static void print_char(char c) {
|
|
||||||
print_string_n(&c, 1);
|
|
||||||
}
|
|
||||||
static void print_string(char *str) {
|
|
||||||
int str_len = 0;
|
|
||||||
while(str[str_len] != 0) {
|
|
||||||
str_len += 1;
|
|
||||||
}
|
|
||||||
print_string_n(str, str_len);
|
|
||||||
}
|
|
||||||
static void print_int(i64 number) {
|
|
||||||
if(number < 0) {
|
|
||||||
print_char('-');
|
|
||||||
number = -number;
|
|
||||||
}
|
|
||||||
char buf[20];
|
|
||||||
buf[19] = 0;
|
|
||||||
char *p = buf + sizeof buf - 1;
|
|
||||||
do {
|
|
||||||
*--p = (number%10) + '0';
|
|
||||||
number /= 10;
|
|
||||||
} while(number > 0);
|
|
||||||
print_string(p);
|
|
||||||
}
|
|
||||||
static void print_uint(u64 number) {
|
|
||||||
char buf[20];
|
|
||||||
buf[19] = 0;
|
|
||||||
char *p = buf + sizeof buf - 1;
|
|
||||||
do {
|
|
||||||
*--p = (number%10) + '0';
|
|
||||||
number /= 10;
|
|
||||||
} while(number > 0);
|
|
||||||
print_string(p);
|
|
||||||
}
|
|
||||||
static void print_hex(u64 number) {
|
|
||||||
// print_string("0x");
|
|
||||||
char digits[] = "0123456789abcdef";
|
|
||||||
char buf[20];
|
|
||||||
buf[19] = 0;
|
|
||||||
char *p = buf + sizeof buf - 1;
|
|
||||||
for(int i = 0; i < 64; i += 4) {
|
|
||||||
if(i != 0 && i % 16 == 0) {
|
|
||||||
*--p = '_';
|
|
||||||
}
|
|
||||||
u8 bits = (number >> i) & 0x0f;
|
|
||||||
char digit = digits[bits];
|
|
||||||
*--p = digit;
|
|
||||||
}
|
|
||||||
print_string(p);
|
|
||||||
}
|
|
||||||
static void printf(char *fmt, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
char str_buf[256];
|
|
||||||
i64 buf_i = 0;
|
|
||||||
while(*fmt != 0) {
|
|
||||||
while(*fmt != '%' && *fmt != 0 && buf_i != sizeof str_buf-1) {
|
|
||||||
str_buf[buf_i] = *fmt;
|
|
||||||
buf_i += 1;
|
|
||||||
fmt++;
|
|
||||||
}
|
|
||||||
str_buf[buf_i] = 0;
|
|
||||||
print_string_n(str_buf, buf_i);
|
|
||||||
buf_i = 0;
|
|
||||||
if(*fmt == '%') {
|
|
||||||
++fmt;
|
|
||||||
if(*fmt == 'd') {
|
|
||||||
i64 number = va_arg(args, i64);
|
|
||||||
print_int(number);
|
|
||||||
}
|
|
||||||
else if(*fmt == 'u') {
|
|
||||||
u64 number = va_arg(args, u64);
|
|
||||||
print_uint(number);
|
|
||||||
}
|
|
||||||
else if(*fmt == 'x') {
|
|
||||||
u64 number = va_arg(args, u64);
|
|
||||||
print_hex(number);
|
|
||||||
}
|
|
||||||
else if(*fmt == 's') {
|
|
||||||
char *str = va_arg(args, char *);
|
|
||||||
print_string(str);
|
|
||||||
}
|
|
||||||
else if(*fmt == 'c') {
|
|
||||||
int c = va_arg(args, int);
|
|
||||||
print_char(c);
|
|
||||||
}
|
|
||||||
++fmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_DEBUG)
|
|
||||||
#define _dbg_print_char(c) print_char(c)
|
|
||||||
#define _dbg_print_string(s) print_string(s)
|
|
||||||
#define _dbg_print_string_n(s,n) print_string_n(s,n)
|
|
||||||
#define _dbg_print_int(d) print_int(d)
|
|
||||||
#define _dbg_print_uint(u) print_uint(u)
|
|
||||||
#define _dbg_print_hex(x) print_hex(x)
|
|
||||||
#define _dbg_printf(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define _dbg_print_char(c) do {} while(0)
|
|
||||||
#define _dbg_print_string(s) do {} while(0)
|
|
||||||
#define _dbg_print_string_n(s,n) do {} while(0)
|
|
||||||
#define _dbg_print_int(d) do {} while(0)
|
|
||||||
#define _dbg_print_uint(u) do {} while(0)
|
|
||||||
#define _dbg_print_hex(x) do {} while(0)
|
|
||||||
#define _dbg_printf(fmt, ...) do {} while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void loader_entry(u64 *sp, u64 *dyn, u64 *aux);
|
|
||||||
|
|
||||||
void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
||||||
_dbg_print_string("Entered dynamic loader\n");
|
_dbg_print_string("Entered dynamic loader\n");
|
||||||
|
@ -221,13 +104,13 @@ void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
||||||
u64 offs = rel->r_offset;
|
u64 offs = rel->r_offset;
|
||||||
u32 sym = ELF64_R_SYM(rel->r_info);
|
u32 sym = ELF64_R_SYM(rel->r_info);
|
||||||
u32 type = ELF64_R_TYPE(rel->r_info);
|
u32 type = ELF64_R_TYPE(rel->r_info);
|
||||||
_dbg_printf(" rel sym: %d type %d\n", sym, type);
|
_dbg_printf(" %d @ %d (%d)\n", sym, offs, type);
|
||||||
// TODO: if needed
|
// TODO: if needed
|
||||||
rel_offs += rel_ent;
|
rel_offs += rel_ent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(dyn[DT_RELA] != 0) {
|
if(dyn[DT_RELA] != 0) {
|
||||||
_dbg_printf("RELA Relocations found\n");
|
_dbg_printf("RELA:\n");
|
||||||
u8 *rela_ents = (void *)(base + dyn[DT_RELA]);
|
u8 *rela_ents = (void *)(base + dyn[DT_RELA]);
|
||||||
u64 rela_ent = dyn[DT_RELAENT];
|
u64 rela_ent = dyn[DT_RELAENT];
|
||||||
u64 rela_size = dyn[DT_RELASZ];
|
u64 rela_size = dyn[DT_RELASZ];
|
||||||
|
@ -238,16 +121,24 @@ void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
||||||
u64 addend = rela->r_addend;
|
u64 addend = rela->r_addend;
|
||||||
u32 sym_idx = ELF64_R_SYM(rela->r_info);
|
u32 sym_idx = ELF64_R_SYM(rela->r_info);
|
||||||
u32 type = ELF64_R_TYPE(rela->r_info);
|
u32 type = ELF64_R_TYPE(rela->r_info);
|
||||||
_dbg_printf(" rela sym: %x, rela offs: %x, type: %d, addend: %d\n",
|
_dbg_printf(" %x+%d, @%x (%d)\n", sym_idx, addend, reloc_offs, type);
|
||||||
sym_idx, reloc_offs, type, addend
|
|
||||||
);
|
|
||||||
if(type == R_X86_64_GLOB_DAT) {
|
if(type == R_X86_64_GLOB_DAT) {
|
||||||
Elf64_Sym *sym = &symtab[sym_idx];
|
Elf64_Sym *sym = &symtab[sym_idx];
|
||||||
void *sym_addr = (void *)(base + sym->st_value);
|
void *sym_addr = (void *)(base + sym->st_value);
|
||||||
void **reloc_addr = (void *)(base + reloc_offs);
|
void **reloc_addr = (void *)(base + reloc_offs);
|
||||||
_dbg_printf(" -> resolving with %x\n", sym_addr);
|
_dbg_printf(" -> %x\n", sym_addr);
|
||||||
*reloc_addr = sym_addr;
|
*reloc_addr = sym_addr;
|
||||||
}
|
}
|
||||||
|
else if(type == R_X86_64_RELATIVE) {
|
||||||
|
void *addr = (void *)(base + addend);
|
||||||
|
void **reloc_addr = (void *)(base + reloc_offs);
|
||||||
|
*reloc_addr = addr;
|
||||||
|
_dbg_printf(" -> %x\n", addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("ERROR: unhandled relocation type: %d\n", type);
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
rela_offs += rela_ent;
|
rela_offs += rela_ent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,11 +146,12 @@ void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
||||||
_dbg_printf("PLT relocations found\n");
|
_dbg_printf("PLT relocations found\n");
|
||||||
if(dyn[DT_PLTREL] == DT_REL) {
|
if(dyn[DT_PLTREL] == DT_REL) {
|
||||||
_dbg_printf(" PLT relocations use relocations of type REL\n");
|
_dbg_printf(" PLT relocations use relocations of type REL\n");
|
||||||
|
printf("ERROR: .plt relocations of type REL not implemented\n");
|
||||||
|
sys_exit(1);
|
||||||
}
|
}
|
||||||
else if(dyn[DT_PLTREL] == DT_RELA) {
|
else if(dyn[DT_PLTREL] == DT_RELA) {
|
||||||
_dbg_printf(" PLT relocations use relocations of type RELA\n");
|
_dbg_printf(" PLT relocations use relocations of type RELA\n");
|
||||||
}
|
}
|
||||||
_dbg_printf("plt: %x, rela.plt: %x, rela.pltsz: %x\n", dyn[DT_PLTGOT], dyn[DT_JMPREL], dyn[DT_PLTRELSZ]);
|
|
||||||
void *plt = (void *)(base + dyn[DT_PLTGOT]);
|
void *plt = (void *)(base + dyn[DT_PLTGOT]);
|
||||||
void *rela_plt = (void *)(base + dyn[DT_JMPREL]);
|
void *rela_plt = (void *)(base + dyn[DT_JMPREL]);
|
||||||
u64 rela_ent = sizeof(Elf64_Rela);
|
u64 rela_ent = sizeof(Elf64_Rela);
|
||||||
|
@ -271,9 +163,7 @@ void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
||||||
u64 addend = rela->r_addend;
|
u64 addend = rela->r_addend;
|
||||||
u32 sym_idx = ELF64_R_SYM(rela->r_info);
|
u32 sym_idx = ELF64_R_SYM(rela->r_info);
|
||||||
u32 type = ELF64_R_TYPE(rela->r_info);
|
u32 type = ELF64_R_TYPE(rela->r_info);
|
||||||
_dbg_printf(" rela sym: %x, rela offs: %x, type: %d, addend: %d\n",
|
_dbg_printf(" %x+%d, @%x (%d)\n", sym_idx, addend, reloc_offs, type);
|
||||||
sym_idx, reloc_offs, type, addend
|
|
||||||
);
|
|
||||||
if(type == R_X86_64_JUMP_SLOT) {
|
if(type == R_X86_64_JUMP_SLOT) {
|
||||||
Elf64_Sym *sym = &symtab[sym_idx];
|
Elf64_Sym *sym = &symtab[sym_idx];
|
||||||
void *sym_addr = (void *)(base + sym->st_value);
|
void *sym_addr = (void *)(base + sym->st_value);
|
||||||
|
@ -282,13 +172,17 @@ void _dlstart_reloc_c(u64 *sp, Elf64_Dyn *dynv) {
|
||||||
*reloc_addr = sym_addr;
|
*reloc_addr = sym_addr;
|
||||||
}
|
}
|
||||||
rela_offs += rela_ent;
|
rela_offs += rela_ent;
|
||||||
_dbg_printf("%x\n", rela_offs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
_mfence();
|
_mfence();
|
||||||
|
Loader_Info ld_info;
|
||||||
|
ld_info.sp = sp;
|
||||||
|
ld_info.ldso_base = base;
|
||||||
|
ld_info.dyn = dyn;
|
||||||
|
ld_info.aux = aux;
|
||||||
_dbg_printf("Self-relocation finished. Entering the loader\n");
|
_dbg_printf("Self-relocation finished. Entering the loader\n");
|
||||||
loader_entry(sp, dyn, aux);
|
loader_entry(&ld_info);
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,276 @@
|
||||||
#include <cia-def.h>
|
#include <cia-def.h>
|
||||||
#include <bin/elf.h>
|
#include <bin/elf.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "../linux/tinyrt-iface.h"
|
||||||
|
#include <tinyrt.h>
|
||||||
|
#include "../linux/tinyrt.c"
|
||||||
|
|
||||||
|
#include <cia-mem.h>
|
||||||
|
#include "../impl/cia-mem/util.c"
|
||||||
|
#include "../impl/cia-mem/allocator.c"
|
||||||
|
#include "../impl/cia-mem/arena.c"
|
||||||
|
#include "../impl/cia-mem/pool.c"
|
||||||
|
|
||||||
struct Elf_Image typedef Elf_Image;
|
struct Elf_Image typedef Elf_Image;
|
||||||
struct Elf_Image {
|
struct Elf_Image {
|
||||||
|
Cia_Arena arena;
|
||||||
|
char *name;
|
||||||
u8 *base;
|
u8 *base;
|
||||||
u8 *phdr;
|
u8 *phdr;
|
||||||
u64 ph_num;
|
u64 ph_num;
|
||||||
u64 ph_ent;
|
u64 ph_ent;
|
||||||
char *name;
|
u8 *shdr;
|
||||||
|
u64 sh_num;
|
||||||
|
u64 sh_ent;
|
||||||
|
u64 *dyn;
|
||||||
};
|
};
|
||||||
|
|
||||||
void loader_entry(u64 *sp, u64 *dynv, u64 *aux) {
|
#define elf_addr(elf, off) (void *)((elf)->base + (u64)off)
|
||||||
char str[] = "Hello world??\n";
|
|
||||||
sys_write(STDOUT_FILENO, str, sizeof str);
|
static Cia_Pool image_pool;
|
||||||
|
|
||||||
|
static u32 elf_sym_gnu_hash(char *name) {
|
||||||
|
unsigned char *s = (void *)name;
|
||||||
|
u32 h = 5381;
|
||||||
|
for(int i = 0; s[i] != 0; ++i) {
|
||||||
|
char c = s[i];
|
||||||
|
h = ((h << 5) + h) + c;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 elf_sym_hash(char *name) {
|
||||||
|
unsigned char *s = (void *)name;
|
||||||
|
u64 h = 0;
|
||||||
|
u64 g;
|
||||||
|
for(int i = 0; s[i] != 0; ++i) {
|
||||||
|
h = (h<<4) + s[i];
|
||||||
|
g = (h & 0xf0000000);
|
||||||
|
if(g) {
|
||||||
|
h ^= g >> 24;
|
||||||
|
}
|
||||||
|
h &= 0x0fffffff;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elf_load(Elf_Image *image, int fd) {
|
||||||
|
printf("ERROR: image loading from file not implemented\n");
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Elf64_Sym *elf_symbol_by_name(Elf_Image *image, char *name) {
|
||||||
|
Elf64_Ehdr *eh = (void *)image->base;
|
||||||
|
u8 *shdr = elf_addr(image, eh->e_shoff);
|
||||||
|
u64 sh_num = eh->e_shnum;
|
||||||
|
u64 sh_ent = eh->e_shentsize;
|
||||||
|
// Get the GNU symbol hash table
|
||||||
|
Elf64_Shdr *sh_gnu_hash = NULL;
|
||||||
|
for(int i = 0; i < sh_num; ++i) {
|
||||||
|
u64 sh_off = i * sh_ent;
|
||||||
|
Elf64_Shdr *sh = (void *)(shdr + sh_off);
|
||||||
|
if(sh->sh_type == SHT_GNU_HASH) {
|
||||||
|
sh_gnu_hash = sh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if we got gnu hash table
|
||||||
|
_dbg_printf("gnu hash section: %x\n", sh_gnu_hash->sh_addr);
|
||||||
|
if(sh_gnu_hash != NULL) {
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_entry(Loader_Info *ld_info) {
|
||||||
|
_dbg_printf("Loader entry point reached!\n");
|
||||||
|
// Get our loader data back
|
||||||
|
u64 *sp = ld_info->sp;
|
||||||
|
u8 *ldso_base = ld_info->ldso_base;
|
||||||
|
u64 *dyn = ld_info->dyn;
|
||||||
|
u64 *aux = ld_info->aux;
|
||||||
|
cia_pool_create(&image_pool, cia_allocator_pages(), 1*KB, sizeof(Elf_Image), 0x10);
|
||||||
|
Elf_Image *ldso = cia_pool_alloc(&image_pool);
|
||||||
|
Elf_Image *app = cia_pool_alloc(&image_pool);
|
||||||
|
cia_arena_create(&app->arena, cia_allocator_pages(), 1*MB);
|
||||||
|
ldso->base = ldso_base;
|
||||||
|
ldso->dyn = dyn;
|
||||||
|
// Read ldso elf header
|
||||||
|
{
|
||||||
|
Elf64_Ehdr *eh = (void *)ldso->base;
|
||||||
|
ldso->phdr = elf_addr(ldso, eh->e_phoff);
|
||||||
|
ldso->ph_num = eh->e_phnum;
|
||||||
|
ldso->ph_ent = eh->e_phentsize;
|
||||||
|
ldso->name = "ld-cia.so";
|
||||||
|
}
|
||||||
|
int fd = 0;
|
||||||
|
app->name = (void *)aux[AT_EXECFN];
|
||||||
|
if(aux[AT_PHDR] != (u64)ldso->base) {
|
||||||
|
_dbg_printf("Linux loaded the image with phdrs at: %x\n", aux[AT_PHDR]);
|
||||||
|
// Figure out executable base from its phdrs
|
||||||
|
u8 *phdr = (void *)aux[AT_PHDR];
|
||||||
|
u64 ph_ent = aux[AT_PHENT];
|
||||||
|
u64 ph_num = aux[AT_PHNUM];
|
||||||
|
for(u64 i = 0; i < ph_num; ++i) {
|
||||||
|
u64 ph_off = i * ph_ent;
|
||||||
|
Elf64_Phdr *ph = (void *)(phdr + ph_off);
|
||||||
|
if(ph->p_type == PT_PHDR) {
|
||||||
|
app->base = (void *)(aux[AT_PHDR] - ph->p_vaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_dbg_printf("app base: %x\n", app->base);
|
||||||
|
app->phdr = phdr;
|
||||||
|
app->ph_ent = ph_ent;
|
||||||
|
app->ph_num = ph_num;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_dbg_printf("Exec filename: %x\n", aux[AT_EXECFN]);
|
||||||
|
char *filename = (void *)aux[AT_EXECFN];
|
||||||
|
app->name = filename;
|
||||||
|
if(filename == NULL) {
|
||||||
|
printf("ERROR: no data about the executable to load dynamically\n");
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
|
int fd = sys_open(filename, O_CLOEXEC, O_RDWR);
|
||||||
|
if(fd < 0) {
|
||||||
|
printf("ERROR: cannot open file %s\n", filename);
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
|
elf_load(app, fd);
|
||||||
|
}
|
||||||
|
if(fd != 0) {
|
||||||
|
sys_close(fd);
|
||||||
|
}
|
||||||
|
// Find .dynamic section
|
||||||
|
{
|
||||||
|
u8 *phdr = (void *)aux[AT_PHDR];
|
||||||
|
u64 ph_ent = aux[AT_PHENT];
|
||||||
|
u64 ph_num = aux[AT_PHNUM];
|
||||||
|
Elf64_Phdr *ph_dynamic = NULL;
|
||||||
|
for(u64 i = 0; i < ph_num; ++i) {
|
||||||
|
u64 ph_off = i * ph_ent;
|
||||||
|
Elf64_Phdr *ph = (void *)(phdr + ph_off);
|
||||||
|
if(ph->p_type == PT_DYNAMIC) {
|
||||||
|
ph_dynamic = ph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read and decode dynamic vector
|
||||||
|
Elf64_Dyn *dynv = elf_addr(app, ph_dynamic->p_vaddr);
|
||||||
|
u64 dyn[DYN_CNT];
|
||||||
|
for(int i = 0; i < DYN_CNT; ++i) {
|
||||||
|
dyn[i] = 0;
|
||||||
|
}
|
||||||
|
for(int i = 0; dynv[i].d_tag != DT_NULL; ++i) {
|
||||||
|
i64 d_tag = dynv[i].d_tag;
|
||||||
|
if(d_tag < DYN_CNT) {
|
||||||
|
dyn[0] |= 1ul << d_tag;
|
||||||
|
dyn[d_tag] = dynv[i].d_un.d_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app->dyn = &dyn[0];
|
||||||
|
}
|
||||||
|
// Load section headers for app
|
||||||
|
_dbg_printf("Loading section headers\n");
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// Relocate app
|
||||||
|
{
|
||||||
|
_dbg_printf("Relocating app\n");
|
||||||
|
Elf64_Ehdr *eh = (void *)app->base;
|
||||||
|
// Resolve relocations
|
||||||
|
Elf64_Sym *symtab = (void *)app->dyn[DT_SYMTAB];
|
||||||
|
if(app->dyn[DT_REL] != 0) {
|
||||||
|
_dbg_printf("REL Relocations found. This part isn't implemented\n");
|
||||||
|
u8 *rel_ents = elf_addr(app, app->dyn[DT_REL]);
|
||||||
|
u64 rel_ent = app->dyn[DT_RELENT];
|
||||||
|
u64 rel_size = app->dyn[DT_RELSZ];
|
||||||
|
u64 rel_offs = 0;
|
||||||
|
while(rel_offs < rel_size) {
|
||||||
|
Elf64_Rel *rel = (void *)(rel_ents + rel_offs);
|
||||||
|
u64 offs = rel->r_offset;
|
||||||
|
u32 sym = ELF64_R_SYM(rel->r_info);
|
||||||
|
u32 type = ELF64_R_TYPE(rel->r_info);
|
||||||
|
_dbg_printf(" %d @ %d (%d)\n", sym, offs, type);
|
||||||
|
// TODO: if needed
|
||||||
|
rel_offs += rel_ent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(app->dyn[DT_RELA] != 0) {
|
||||||
|
_dbg_printf("RELA:\n");
|
||||||
|
u8 *rela_ents = elf_addr(app, app->dyn[DT_RELA]);
|
||||||
|
u64 rela_ent = app->dyn[DT_RELAENT];
|
||||||
|
u64 rela_size = app->dyn[DT_RELASZ];
|
||||||
|
u64 rela_offs = 0;
|
||||||
|
while(rela_offs < rela_size) {
|
||||||
|
Elf64_Rela *rela = (void *)(rela_ents + rela_offs);
|
||||||
|
u64 reloc_offs = rela->r_offset;
|
||||||
|
u64 addend = rela->r_addend;
|
||||||
|
u32 sym_idx = ELF64_R_SYM(rela->r_info);
|
||||||
|
u32 type = ELF64_R_TYPE(rela->r_info);
|
||||||
|
_dbg_printf(" %x+%d, @%x (%d)\n", sym_idx, addend, reloc_offs, type);
|
||||||
|
if(type == R_X86_64_GLOB_DAT) {
|
||||||
|
Elf64_Sym *sym = &symtab[sym_idx];
|
||||||
|
void *sym_addr = elf_addr(app, sym->st_value);
|
||||||
|
void **reloc_addr = elf_addr(app, reloc_offs);
|
||||||
|
*reloc_addr = sym_addr;
|
||||||
|
_dbg_printf(" -> %x\n", sym_addr);
|
||||||
|
}
|
||||||
|
else if(type == R_X86_64_RELATIVE) {
|
||||||
|
void *addr = elf_addr(app, addend);
|
||||||
|
void **reloc_addr = elf_addr(app, reloc_offs);
|
||||||
|
*reloc_addr = addr;
|
||||||
|
_dbg_printf(" -> %x\n", addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("ERROR: unhandled relocation type: %d\n", type);
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
|
rela_offs += rela_ent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(app->dyn[DT_PLTGOT] != 0) {
|
||||||
|
_dbg_printf("PLT relocations found\n");
|
||||||
|
if(app->dyn[DT_PLTREL] == DT_REL) {
|
||||||
|
_dbg_printf(" PLT relocations use relocations of type REL\n");
|
||||||
|
printf("ERROR: .plt relocations of type REL not implemented\n");
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
|
else if(app->dyn[DT_PLTREL] == DT_RELA) {
|
||||||
|
_dbg_printf(" PLT relocations use relocations of type RELA\n");
|
||||||
|
}
|
||||||
|
void *plt = elf_addr(app, app->dyn[DT_PLTGOT]);
|
||||||
|
void *rela_plt = elf_addr(app, app->dyn[DT_JMPREL]);
|
||||||
|
u64 rela_ent = sizeof(Elf64_Rela);
|
||||||
|
u64 rela_size = app->dyn[DT_PLTRELSZ];
|
||||||
|
u64 rela_offs = 0;
|
||||||
|
while(rela_offs < rela_size) {
|
||||||
|
Elf64_Rela *rela = (void *)(rela_plt + rela_offs);
|
||||||
|
u64 reloc_offs = rela->r_offset;
|
||||||
|
u64 addend = rela->r_addend;
|
||||||
|
u32 sym_idx = ELF64_R_SYM(rela->r_info);
|
||||||
|
u32 type = ELF64_R_TYPE(rela->r_info);
|
||||||
|
_dbg_printf(" %x+%d, @%x (%d)\n", sym_idx, addend, reloc_offs, type);
|
||||||
|
if(type == R_X86_64_JUMP_SLOT) {
|
||||||
|
Elf64_Sym *sym = &symtab[sym_idx];
|
||||||
|
void *sym_addr = elf_addr(app, sym->st_value);
|
||||||
|
void **reloc_addr = elf_addr(app, reloc_offs);
|
||||||
|
_dbg_printf(" -> resolving with %x\n", sym_addr);
|
||||||
|
*reloc_addr = sym_addr;
|
||||||
|
}
|
||||||
|
rela_offs += rela_ent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_dbg_printf("%x\n", 0);
|
||||||
|
// Get the app main
|
||||||
|
// Elf64_Sym *app_main = elf_symbol_by_name(app, "main");
|
||||||
|
// _dbg_printf("app main: %x\n", app_main);
|
||||||
|
void (*crt_entry)() = elf_addr(app, eh->e_entry);
|
||||||
|
_dbg_printf("Exiting the dynamic loader, trying to enter the main app\n");
|
||||||
|
crt_entry();
|
||||||
|
}
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
|
||||||
|
#define AUX_CNT 32
|
||||||
|
#define DYN_CNT 37
|
||||||
|
|
||||||
|
#define _mfence() asm volatile("" ::: "memory")
|
||||||
|
|
||||||
|
struct Loader_Info typedef Loader_Info;
|
||||||
|
struct Loader_Info {
|
||||||
|
u64 *sp;
|
||||||
|
u8 *ldso_base;
|
||||||
|
u64 *dyn;
|
||||||
|
u64 *aux;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_string_n(char *str, u64 len) {
|
||||||
|
sys_write(STDOUT_FILENO, str, len);
|
||||||
|
}
|
||||||
|
static void print_char(char c) {
|
||||||
|
print_string_n(&c, 1);
|
||||||
|
}
|
||||||
|
static void print_string(char *str) {
|
||||||
|
int str_len = 0;
|
||||||
|
while(str[str_len] != 0) {
|
||||||
|
str_len += 1;
|
||||||
|
}
|
||||||
|
print_string_n(str, str_len);
|
||||||
|
}
|
||||||
|
static void print_int(i64 number) {
|
||||||
|
if(number < 0) {
|
||||||
|
print_char('-');
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
char buf[20];
|
||||||
|
buf[19] = 0;
|
||||||
|
char *p = buf + sizeof buf - 1;
|
||||||
|
do {
|
||||||
|
*--p = (number%10) + '0';
|
||||||
|
number /= 10;
|
||||||
|
} while(number > 0);
|
||||||
|
print_string(p);
|
||||||
|
}
|
||||||
|
static void print_uint(u64 number) {
|
||||||
|
char buf[20];
|
||||||
|
buf[19] = 0;
|
||||||
|
char *p = buf + sizeof buf - 1;
|
||||||
|
do {
|
||||||
|
*--p = (number%10) + '0';
|
||||||
|
number /= 10;
|
||||||
|
} while(number > 0);
|
||||||
|
print_string(p);
|
||||||
|
}
|
||||||
|
static void print_hex(u64 number) {
|
||||||
|
print_string("0x");
|
||||||
|
char digits[] = "0123456789abcdef";
|
||||||
|
char buf[20];
|
||||||
|
buf[19] = 0;
|
||||||
|
char *p = buf + sizeof buf - 1;
|
||||||
|
for(int i = 0; i < 64; i += 4) {
|
||||||
|
// if(i != 0 && i % 16 == 0) {
|
||||||
|
// *--p = '_';
|
||||||
|
// }
|
||||||
|
u8 bits = (number >> i) & 0x0f;
|
||||||
|
char digit = digits[bits];
|
||||||
|
*--p = digit;
|
||||||
|
}
|
||||||
|
print_string(p);
|
||||||
|
}
|
||||||
|
static void printf(char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
char str_buf[256];
|
||||||
|
i64 buf_i = 0;
|
||||||
|
while(*fmt != 0) {
|
||||||
|
while(*fmt != '%' && *fmt != 0 && buf_i != sizeof str_buf-1) {
|
||||||
|
str_buf[buf_i] = *fmt;
|
||||||
|
buf_i += 1;
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
str_buf[buf_i] = 0;
|
||||||
|
print_string_n(str_buf, buf_i);
|
||||||
|
buf_i = 0;
|
||||||
|
if(*fmt == '%') {
|
||||||
|
++fmt;
|
||||||
|
if(*fmt == 'd') {
|
||||||
|
i64 number = va_arg(args, i64);
|
||||||
|
print_int(number);
|
||||||
|
}
|
||||||
|
else if(*fmt == 'u') {
|
||||||
|
u64 number = va_arg(args, u64);
|
||||||
|
print_uint(number);
|
||||||
|
}
|
||||||
|
else if(*fmt == 'x') {
|
||||||
|
u64 number = va_arg(args, u64);
|
||||||
|
print_hex(number);
|
||||||
|
}
|
||||||
|
else if(*fmt == 's') {
|
||||||
|
char *str = va_arg(args, char *);
|
||||||
|
print_string(str);
|
||||||
|
}
|
||||||
|
else if(*fmt == 'c') {
|
||||||
|
int c = va_arg(args, int);
|
||||||
|
print_char(c);
|
||||||
|
}
|
||||||
|
++fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
#define _dbg_print_char(c) print_char(c)
|
||||||
|
#define _dbg_print_string(s) print_string(s)
|
||||||
|
#define _dbg_print_string_n(s,n) print_string_n(s,n)
|
||||||
|
#define _dbg_print_int(d) print_int(d)
|
||||||
|
#define _dbg_print_uint(u) print_uint(u)
|
||||||
|
#define _dbg_print_hex(x) print_hex(x)
|
||||||
|
#define _dbg_printf(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _dbg_print_char(c) do {} while(0)
|
||||||
|
#define _dbg_print_string(s) do {} while(0)
|
||||||
|
#define _dbg_print_string_n(s,n) do {} while(0)
|
||||||
|
#define _dbg_print_int(d) do {} while(0)
|
||||||
|
#define _dbg_print_uint(u) do {} while(0)
|
||||||
|
#define _dbg_print_hex(x) do {} while(0)
|
||||||
|
#define _dbg_printf(fmt, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue