From 8b0915cb016e59c947020a06bee2330e6feddce3 Mon Sep 17 00:00:00 2001 From: M4xw Date: Tue, 7 Aug 2018 16:53:58 +0200 Subject: [PATCH] Implement elfloader/module support --- .gitignore | 2 +- Makefile | 23 +- README.md | 1 + common/common_gfx.h | 43 +++ common/common_heap.h | 33 ++ common/common_module.h | 38 ++ ipl/elfloader/README.md | 3 + ipl/elfloader/elf.h | 589 +++++++++++++++++++++++++++++++ ipl/elfloader/elfarch.h | 47 +++ ipl/elfloader/elfload.c | 322 +++++++++++++++++ ipl/elfloader/elfload.h | 125 +++++++ ipl/elfloader/elfreloc_aarch64.c | 83 +++++ ipl/elfloader/elfreloc_arm.c | 66 ++++ ipl/gfx.c | 2 + ipl/gfx.h | 25 +- ipl/heap.c | 23 +- ipl/heap.h | 1 + ipl/main.c | 121 ++++++- modules/sample/Makefile | 31 ++ modules/sample/module_sample.c | 10 + 20 files changed, 1542 insertions(+), 46 deletions(-) create mode 100644 common/common_gfx.h create mode 100644 common/common_heap.h create mode 100644 common/common_module.h create mode 100644 ipl/elfloader/README.md create mode 100644 ipl/elfloader/elf.h create mode 100644 ipl/elfloader/elfarch.h create mode 100644 ipl/elfloader/elfload.c create mode 100644 ipl/elfloader/elfload.h create mode 100644 ipl/elfloader/elfreloc_aarch64.c create mode 100644 ipl/elfloader/elfreloc_arm.c create mode 100644 modules/sample/Makefile create mode 100644 modules/sample/module_sample.c diff --git a/.gitignore b/.gitignore index 1e59098..b53e009 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .vs .vscode build_ipl/* -/ipl.bin +output/* diff --git a/Makefile b/Makefile index f073dc6..9860dfd 100755 --- a/Makefile +++ b/Makefile @@ -6,7 +6,9 @@ include $(DEVKITARM)/base_rules TARGET := ipl BUILD := build_ipl +OUTPUT := output SOURCEDIR := ipl + OBJS = $(addprefix $(BUILD)/, \ start.o \ main.o \ @@ -43,27 +45,34 @@ OBJS = $(addprefix $(BUILD)/, \ uart.o \ ini.o \ ) + OBJS += $(addprefix $(BUILD)/, diskio.o ff.o ffunicode.o ffsystem.o) +OBJS += $(addprefix $(BUILD)/elfloader/, elfload.o elfreloc_arm.o) ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -CUSTOMDEFINES := -DMENU_LOGO_ENABLE +CUSTOMDEFINES := -DMENU_LOGO_ENABLE #-DDEBUG CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -.PHONY: all clean +MODULEDIRS := $(wildcard modules/*) + +.PHONY: all clean $(MODULEDIRS) all: $(TARGET).bin @echo -n "Payload size is " - @wc -c < $(TARGET).bin + @wc -c < $(OUTPUT)/$(TARGET).bin @echo "Max size is 126296 Bytes." clean: @rm -rf $(OBJS) @rm -rf $(BUILD) - @rm -rf $(TARGET).bin + @rm -rf $(OUTPUT) -$(TARGET).bin: $(BUILD)/$(TARGET).elf - $(OBJCOPY) -S -O binary $< $@ +$(MODULEDIRS): + $(MAKE) -C $@ $(MAKECMDGOALS) + +$(TARGET).bin: $(BUILD)/$(TARGET).elf $(MODULEDIRS) + $(OBJCOPY) -S -O binary $< $(OUTPUT)/$@ $(BUILD)/$(TARGET).elf: $(OBJS) $(CC) $(LDFLAGS) -T ipl/link.ld $^ -o $@ @@ -73,4 +82,6 @@ $(BUILD)/%.o: $(SOURCEDIR)/%.c $(BUILD)/%.o: $(SOURCEDIR)/%.S @mkdir -p "$(BUILD)" + @mkdir -p "$(BUILD)/elfloader" + @mkdir -p "$(OUTPUT)" $(CC) $(CFLAGS) -c $< -o $@ diff --git a/README.md b/README.md index e70699c..5e01b91 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ Open source and free packages used: - FatFs R0.13a, Copyright (C) 2017, ChaN - bcl-1.2.0, Copyright (C) 2003-2006, Marcus Geelnard - Atmosphère (SE sha256, prc id kernel patches), Copyright (C) 2018, Atmosphère-NX + - elfload, Copyright (C) 2014 Owen Shepherd, Copyright (C) 2018 M4xw ___ .-' `'. diff --git a/common/common_gfx.h b/common/common_gfx.h new file mode 100644 index 0000000..e957f80 --- /dev/null +++ b/common/common_gfx.h @@ -0,0 +1,43 @@ +/* + * Common Gfx Header + * Copyright (c) 2018 naehrwert + * Copyright (C) 2018 CTCaer + * Copyright (C) 2018 M4xw + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. If not, see . +*/ + +#pragma once +#include "../ipl/types.h" + +typedef struct _gfx_ctxt_t +{ + u32 *fb; + u32 width; + u32 height; + u32 stride; +} gfx_ctxt_t; + +typedef struct _gfx_con_t +{ + gfx_ctxt_t *gfx_ctxt; + u32 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + int mute; +} gfx_con_t; diff --git a/common/common_heap.h b/common/common_heap.h new file mode 100644 index 0000000..7e8fd80 --- /dev/null +++ b/common/common_heap.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 M4xw + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. If not, see . +*/ + +#pragma once +#include "../ipl/types.h" + +typedef struct _hnode +{ + int used; + u32 size; + struct _hnode *prev; + struct _hnode *next; +} hnode_t; + +typedef struct _heap +{ + u32 start; + hnode_t *first; +} heap_t; diff --git a/common/common_module.h b/common/common_module.h new file mode 100644 index 0000000..cd22835 --- /dev/null +++ b/common/common_module.h @@ -0,0 +1,38 @@ +/* + * Common Module Header + * Copyright (C) 2018 M4xw + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. If not, see . +*/ + +#pragma once +#include +#include "common_gfx.h" +#include "common_heap.h" + +// Module Callback +typedef void (*cbMainModule_t)(const char *s); +typedef void (*memcpy_t)(void *, void *, size_t); +typedef void (*memset_t)(void *test, int, size_t); + +typedef struct moduleConfiguration_t +{ + gfx_con_t *gfxCon; + gfx_ctxt_t *gfxCtx; + heap_t *sharedHeap; + memcpy_t memcpy; + memset_t memset; +} *pmoduleConfiguration_t; + +// Module Entrypoint +typedef void (*moduleEntrypoint_t)(cbMainModule_t, pmoduleConfiguration_t); diff --git a/ipl/elfloader/README.md b/ipl/elfloader/README.md new file mode 100644 index 0000000..74a29ae --- /dev/null +++ b/ipl/elfloader/README.md @@ -0,0 +1,3 @@ +Simple elf-loader based on https://github.com/erincandescent/elfload + +Each file contains its own LICENSE diff --git a/ipl/elfloader/elf.h b/ipl/elfloader/elf.h new file mode 100644 index 0000000..196cf87 --- /dev/null +++ b/ipl/elfloader/elf.h @@ -0,0 +1,589 @@ +/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */ +/* + * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* imported sys/exec_elf.h from OpenBSD */ + +#ifndef ELF_H +#define ELF_H +#include + +typedef uint8_t Elf_Byte; + +typedef uint32_t Elf32_Addr; /* Unsigned program address */ +typedef uint32_t Elf32_Off; /* Unsigned file offset */ +typedef int32_t Elf32_Sword; /* Signed large integer */ +typedef uint32_t Elf32_Word; /* Unsigned large integer */ +typedef uint16_t Elf32_Half; /* Unsigned medium integer */ + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Shalf; + +#ifdef __alpha__ +typedef int64_t Elf64_Sword; +typedef uint64_t Elf64_Word; +#else +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +#endif + +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Xword; + +typedef uint32_t Elf64_Half; +typedef uint16_t Elf64_Quarter; + +/* + * e_ident[] identification indexes + * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html + */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI ID */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASS32 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] Operating System/ABI */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Id bytes */ + Elf64_Quarter e_type; /* file type */ + Elf64_Quarter e_machine; /* machine type */ + Elf64_Half e_version; /* version number */ + Elf64_Addr e_entry; /* entry point */ + Elf64_Off e_phoff; /* Program hdr offset */ + Elf64_Off e_shoff; /* Section hdr offset */ + Elf64_Half e_flags; /* Processor flags */ + Elf64_Quarter e_ehsize; /* sizeof ehdr */ + Elf64_Quarter e_phentsize; /* Program header entry size */ + Elf64_Quarter e_phnum; /* Number of program headers */ + Elf64_Quarter e_shentsize; /* Section header entry size */ + Elf64_Quarter e_shnum; /* Number of section headers */ + Elf64_Quarter e_shstrndx; /* String table index */ +} Elf64_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 - unused? */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +/* + * Don't know if EM_MIPS_RS4_BE, + * EM_SPARC64, EM_PARISC, + * or EM_PPC are ABI compliant + */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_PPC 20 /* PowerPC */ +#define EM_ARM 40 /* ARM AArch32 */ +#define EM_ALPHA 41 /* DEC ALPHA */ +#define EM_SH 42 /* Hitachi/Renesas Super-H */ +#define EM_SPARCV9 43 /* SPARC version 9 */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_AMD64 62 /* AMD64 architecture */ +#define EM_VAX 75 /* DEC VAX */ +#define EM_AARCH64 183 /* ARM AArch64 */ + +/* Non-standard */ +#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct +{ + Elf32_Word sh_name; /* name - index into section header + * string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Half sh_name; /* section name */ + Elf64_Half sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* virtual address */ + Elf64_Off sh_offset; /* file offset */ + Elf64_Xword sh_size; /* section size */ + Elf64_Half sh_link; /* link to another */ + Elf64_Half sh_info; /* misc info */ + Elf64_Xword sh_addralign; /* memory alignment */ + Elf64_Xword sh_entsize; /* table entry size */ +} Elf64_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_TEXT ".text" /* code */ + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_TLS 0x400 /* thread local storage */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \ + * specific section attributes */ + +/* Symbol Table Entry */ +typedef struct elf32_sym +{ + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Half st_name; /* Symbol name index in str table */ + Elf_Byte st_info; /* type / binding attrs */ + Elf_Byte st_other; /* unused */ + Elf64_Quarter st_shndx; /* section index of symbol */ + Elf64_Xword st_value; /* value of symbol */ + Elf64_Xword st_size; /* size of symbol */ +} Elf64_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +#define ELF64_ST_BIND(x) ((x) >> 4) +#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_TLS 6 /* thread local storage */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Relocation entry with implicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +typedef struct +{ + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ +} Elf64_Rel; + +typedef struct +{ + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ + Elf64_Sxword r_addend; /* adjustment value */ +} Elf64_Rela; + +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF) +#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t)) + +#if defined(__mips64__) && defined(__MIPSEL__) +/* + * The 64-bit MIPS ELF ABI uses a slightly different relocation format + * than the regular ELF ABI: the r_info field is split into several + * pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details). + */ +#undef ELF64_R_SYM +#undef ELF64_R_TYPE +#undef ELF64_R_INFO +#define ELF64_R_TYPE(info) (swap32((info) >> 32)) +#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF) +#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s)) +#endif /* __mips64__ && __MIPSEL__ */ + +/* Program Header */ +typedef struct +{ + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Half p_type; /* entry type */ + Elf64_Half p_flags; /* flags */ + Elf64_Off p_offset; /* offset */ + Elf64_Addr p_vaddr; /* virtual address */ + Elf64_Addr p_paddr; /* physical address */ + Elf64_Xword p_filesz; /* file size */ + Elf64_Xword p_memsz; /* memory size */ + Elf64_Xword p_align; /* memory & file alignment */ +} Elf64_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_TLS 7 /* thread local storage */ +#define PT_LOOS 0x60000000 /* reserved range for OS */ +#define PT_HIOS 0x6fffffff /* specific segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */ +#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ + +/* Dynamic structure */ +typedef struct +{ + Elf32_Sword d_tag; /* controls meaning of d_val */ + union { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Xword d_tag; /* controls meaning of d_val */ + union { + Elf64_Addr d_ptr; + Elf64_Xword d_val; + } d_un; +} Elf64_Dyn; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library \ + * search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ +#define DT_LOOS 0x6000000d /* reserved range for OS */ +#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ + +/* some other useful tags */ +#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */ +#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */ +#define DT_FLAGS_1 0x6ffffffb + +/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONLFAT 0x00002000 + +/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */ +#define DT_NUM (DT_JMPREL + 1) + +/* + * Note Definitions + */ +typedef struct +{ + Elf32_Word namesz; + Elf32_Word descsz; + Elf32_Word type; +} Elf32_Note; + +typedef struct +{ + Elf64_Half namesz; + Elf64_Half descsz; + Elf64_Half type; +} Elf64_Note; + +#if defined(ELFSIZE) && (ELFSIZE == 32) +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_RelA Elf32_Rela +#define Elf_Dyn Elf32_Dyn +#define Elf_Half Elf32_Half +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Addr Elf32_Addr +#define Elf_Off Elf32_Off +#define Elf_Nhdr Elf32_Nhdr +#define Elf_Note Elf32_Note + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO +#define ELFCLASS ELFCLASS32 + +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_INFO ELF32_ST_INFO + +#elif defined(ELFSIZE) && (ELFSIZE == 64) + +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_RelA Elf64_Rela +#define Elf_Dyn Elf64_Dyn +#define Elf_Half Elf64_Half +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Addr Elf64_Addr +#define Elf_Off Elf64_Off +#define Elf_Nhdr Elf64_Nhdr +#define Elf_Note Elf64_Note + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO +#define ELFCLASS ELFCLASS64 + +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_INFO ELF64_ST_INFO + +#endif + +#endif diff --git a/ipl/elfloader/elfarch.h b/ipl/elfloader/elfarch.h new file mode 100644 index 0000000..2dd8500 --- /dev/null +++ b/ipl/elfloader/elfarch.h @@ -0,0 +1,47 @@ +/* Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef ELFARCH_H +#define ELFARCH_H + +#if defined(__i386__) +#define EM_THIS EM_386 +#define EL_ARCH_USES_REL +#elif defined(__amd64__) +#define EM_THIS EM_AMD64 +#define EL_ARCH_USES_RELA +#elif defined(__arm__) +#define EM_THIS EM_ARM +#define EL_ARCH_USES_REL +#elif defined(__aarch64__) +#define EM_THIS EM_AARCH64 +#define EL_ARCH_USES_RELA +#define EL_ARCH_USES_REL +#else +#error specify your ELF architecture +#endif + +#if defined(__LP64__) || defined(__LLP64__) +#define ELFSIZE 64 +#else +#define ELFSIZE 32 +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define ELFDATATHIS ELFDATA2LSB +#else +#define ELFDATATHIS ELFDATA2MSB +#endif + +#endif diff --git a/ipl/elfloader/elfload.c b/ipl/elfloader/elfload.c new file mode 100644 index 0000000..a028f83 --- /dev/null +++ b/ipl/elfloader/elfload.c @@ -0,0 +1,322 @@ +/* Copyright © 2018, M4xw + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include "elfload.h" +#include + +el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset) +{ + return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO; +} + +#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize)) +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i) +{ + el_status rv = EL_OK; + for (; *i < ctx->ehdr.e_phnum; (*i)++) + { + if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i)))) + return rv; + + if (phdr->p_type == type) + { + return rv; + } + } + + *i = -1; + return rv; +} + +#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize)) +el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i) +{ + el_status rv = EL_OK; + + for (; *i < ctx->ehdr.e_shnum; (*i)++) + { + if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i)))) + + return rv; + + if (shdr->sh_type == type) + { + return rv; + } + } + + *i = -1; + + return rv; +} + +el_status el_init(el_ctx *ctx) +{ + el_status rv = EL_OK; + if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0))) + return rv; + + /* validate header */ + + if (!IS_ELF(ctx->ehdr)) + return EL_NOTELF; + + if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS) + return EL_WRONGBITS; + + if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS) + return EL_WRONGENDIAN; + + if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT) + return EL_NOTELF; + + if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN) + return EL_NOTEXEC; + + if (ctx->ehdr.e_machine != EM_THIS) + return EL_WRONGARCH; + + if (ctx->ehdr.e_version != EV_CURRENT) + return EL_NOTELF; + + /* load phdrs */ + Elf_Phdr ph; + + /* iterate through, calculate extents */ + ctx->base_load_paddr = ctx->base_load_vaddr = 0; + ctx->align = 1; + ctx->memsz = 0; + + unsigned i = 0; + for (;;) + { + if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) + return rv; + + if (i == (unsigned)-1) + break; + + Elf_Addr phend = ph.p_vaddr + ph.p_memsz; + if (phend > ctx->memsz) + ctx->memsz = phend; + + if (ph.p_align > ctx->align) + ctx->align = ph.p_align; + + i++; + } + + // Program Header + if (ctx->ehdr.e_type == ET_DYN) + { + i = 0; + + if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i))) + return rv; + + if (i == (unsigned)-1) + return EL_NODYN; + + ctx->dynoff = ph.p_offset; + ctx->dynsize = ph.p_filesz; + } + else + { + ctx->dynoff = 0; + ctx->dynsize = 0; + } + + // Section String Table + if (ctx->ehdr.e_type == ET_DYN) + { + + i = ctx->ehdr.e_shstrndx - 1; + + if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i))) + return rv; + + // Reset + i = 0; + + if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i))) + return rv; + + if (i == (unsigned)-1) + return EL_NODYN; + } + + return rv; +} + +/* +typedef void* (*el_alloc_cb)( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size); +*/ + +el_status el_load(el_ctx *ctx, el_alloc_cb alloc) +{ + el_status rv = EL_OK; + + /* address deltas */ + Elf_Addr pdelta = ctx->base_load_paddr; + Elf_Addr vdelta = ctx->base_load_vaddr; + + /* iterate paddrs */ + Elf_Phdr ph; + unsigned i = 0; + for (;;) + { + if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i))) + return rv; + + if (i == (unsigned)-1) + break; + + Elf_Addr pload = ph.p_paddr + pdelta; + Elf_Addr vload = ph.p_vaddr + vdelta; + + /* allocate mem */ + char *dest = alloc(ctx, pload, vload, ph.p_memsz); + if (!dest) + return EL_ENOMEM; + + EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n", + ph.p_offset, ph.p_vaddr, dest); + + /* read loaded portion */ + if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset))) + return rv; + + /* zero mem-only portion */ + memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz); + + i++; + } + + return rv; +} + +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag) +{ + el_status rv = EL_OK; + size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn); + + for (unsigned i = 0; i < ndyn; i++) + { + if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn))) + return rv; + + if (dyn->d_tag == tag) + return EL_OK; + } + + dyn->d_tag = DT_NULL; + return EL_OK; +} + +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type) +{ + el_status rv = EL_OK; + + Elf_Dyn rel, relsz, relent; + + if ((rv = el_finddyn(ctx, &rel, type))) + return rv; + + if ((rv = el_finddyn(ctx, &relsz, type + 1))) + return rv; + + if ((rv = el_finddyn(ctx, &relent, type + 2))) + return rv; + + if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL) + { + ri->entrysize = 0; + ri->tablesize = 0; + ri->tableoff = 0; + } + else + { + ri->tableoff = rel.d_un.d_ptr; + ri->tablesize = relsz.d_un.d_val; + ri->entrysize = relent.d_un.d_val; + } + + return rv; +} + +extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel); +extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela); + +el_status el_relocate(el_ctx *ctx) +{ + el_status rv = EL_OK; + + // not dynamic + if (ctx->ehdr.e_type != ET_DYN) + return EL_OK; + + char *base = (char *)ctx->base_load_paddr; + + el_relocinfo ri; +#ifdef EL_ARCH_USES_REL + if ((rv = el_findrelocs(ctx, &ri, DT_REL))) + return rv; + + if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize) + { + EL_DEBUG("Relocation size %u doesn't match expected %u\n", + ri.entrysize, sizeof(Elf_Rel)); + return EL_BADREL; + } + + size_t relcnt = ri.tablesize / sizeof(Elf_Rel); + Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff); + for (size_t i = 0; i < relcnt; i++) + { + if ((rv = el_applyrel(ctx, &reltab[i]))) + return rv; + } +#endif + +#ifdef EL_ARCH_USES_RELA + if ((rv = el_findrelocs(ctx, &ri, DT_RELA))) + return rv; + + if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize) + { + EL_DEBUG("Relocation size %u doesn't match expected %u\n", + ri.entrysize, sizeof(Elf_RelA)); + return EL_BADREL; + } + + size_t relacnt = ri.tablesize / sizeof(Elf_RelA); + Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff); + for (size_t i = 0; i < relacnt; i++) + { + if ((rv = el_applyrela(ctx, &relatab[i]))) + return rv; + } +#endif + +#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA) +#error No relocation type defined! +#endif + + return rv; +} diff --git a/ipl/elfloader/elfload.h b/ipl/elfloader/elfload.h new file mode 100644 index 0000000..436a031 --- /dev/null +++ b/ipl/elfloader/elfload.h @@ -0,0 +1,125 @@ +/* Copyright © 2018, M4xw + * Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ELFLOAD_H +#define ELFLOAD_H +#include +#include +#include "elfarch.h" +#include "elf.h" + +#ifdef DEBUG +#include "../gfx.h" +extern gfx_con_t gfx_con; +#define EL_DEBUG(format, ...) \ + gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__) +#else +#define EL_DEBUG(...) \ + do \ + { \ + } while (0) +#endif + +typedef enum +{ + EL_OK = 0, + + EL_EIO, + EL_ENOMEM, + + EL_NOTELF, + EL_WRONGBITS, + EL_WRONGENDIAN, + EL_WRONGARCH, + EL_WRONGOS, + EL_NOTEXEC, + EL_NODYN, + EL_BADREL, + +} el_status; + +typedef struct el_ctx +{ + bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset); + + /* base_load_* -> address we are actually going to load at + */ + Elf_Addr + base_load_paddr, + base_load_vaddr; + + /* size in memory of binary */ + Elf_Addr memsz; + + /* required alignment */ + Elf_Addr align; + + /* ELF header */ + Elf_Ehdr ehdr; + + // Section Header Str Table + Elf_Shdr shstr; + Elf_Shdr symtab; + + /* Offset of dynamic table (0 if not ET_DYN) */ + Elf_Off dynoff; + /* Size of dynamic table (0 if not ET_DYN) */ + Elf_Addr dynsize; +} el_ctx; + +el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset); + +el_status el_init(el_ctx *ctx); +typedef void *(*el_alloc_cb)( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size); + +el_status el_load(el_ctx *ctx, el_alloc_cb alloccb); + +/* find the next phdr of type \p type, starting at \p *i. + * On success, returns EL_OK with *i set to the phdr number, and the phdr loaded + * in *phdr. + * + * If the end of the phdrs table was reached, *i is set to -1 and the contents + * of *phdr are undefined + */ +el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i); + +/* Relocate the loaded executable */ +el_status el_relocate(el_ctx *ctx); + +/* find a dynamic table entry + * returns the entry on success, dyn->d_tag = DT_NULL on failure + */ +el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type); + +typedef struct +{ + Elf_Off tableoff; + Elf_Addr tablesize; + Elf_Addr entrysize; +} el_relocinfo; + +/* find all information regarding relocations of a specific type. + * + * pass DT_REL or DT_RELA for type + * sets ri->entrysize = 0 if not found + */ +el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type); + +#endif diff --git a/ipl/elfloader/elfreloc_aarch64.c b/ipl/elfloader/elfreloc_aarch64.c new file mode 100644 index 0000000..76996e0 --- /dev/null +++ b/ipl/elfloader/elfreloc_aarch64.c @@ -0,0 +1,83 @@ +/* Copyright © 2014, Owen Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "elfload.h" + +#if defined(__aarch64__) + +#define R_AARCH64_NONE 0 +#define R_AARCH64_RELATIVE 1027 + +el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel) +{ + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); + uint32_t type = ELF_R_TYPE(rel->r_info); + uint32_t sym = ELF_R_SYM(rel->r_info); + + switch (type) + { + case R_AARCH64_NONE: + EL_DEBUG("R_AARCH64_NONE\n"); + break; + case R_AARCH64_RELATIVE: + if (sym) + { + EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); + return EL_BADREL; + } + + EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); + *p = rel->r_addend + ctx->base_load_vaddr; + break; + + default: + EL_DEBUG("Bad relocation %u\n", type); + return EL_BADREL; + } + + return EL_OK; +} + +el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) +{ + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); + uint32_t type = ELF_R_TYPE(rel->r_info); + uint32_t sym = ELF_R_SYM(rel->r_info); + + switch (type) + { + case R_AARCH64_NONE: + EL_DEBUG("R_AARCH64_NONE\n"); + break; + case R_AARCH64_RELATIVE: + if (sym) + { + EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n"); + return EL_BADREL; + } + + EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p); + *p += ctx->base_load_vaddr; + break; + + default: + EL_DEBUG("Bad relocation %u\n", type); + return EL_BADREL; + } + + return EL_OK; +} + +#endif diff --git a/ipl/elfloader/elfreloc_arm.c b/ipl/elfloader/elfreloc_arm.c new file mode 100644 index 0000000..51c7d6b --- /dev/null +++ b/ipl/elfloader/elfreloc_arm.c @@ -0,0 +1,66 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. M4xw + * ---------------------------------------------------------------------------- + */ + +#include "elfload.h" + +#if defined(__arm__) + +// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf +#define R_ARM_NONE 0 +#define R_ARM_ABS32 2 +#define R_ARM_RELATIVE 23 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_GLOB_DAT 21 + +el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel) +{ + uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset + uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type + uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr + +#if 0 // For later symbol usage + Elf32_Sym *elfSym; + const char *symbolName; + + // We resolve relocs from the originating elf-image + elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym; + int strtab_offset = ctx->shstr.sh_offset; + char *strtab = (char *)buffteg + strtab_offset; + symbolName = strtab + elfSym->st_name; + //EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value); +#endif + + switch (type) + { + case R_ARM_NONE: + EL_DEBUG("R_ARM_NONE\n"); + break; + case R_ARM_JUMP_SLOT: + case R_ARM_ABS32: + case R_ARM_GLOB_DAT: + // Stubbed for later purpose + //*p += elfSym->st_value; // + vaddr from sec + //*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now + break; + case R_ARM_RELATIVE: // Needed for PIE + if (sym) + { + return EL_BADREL; + } + *p += ctx->base_load_vaddr; + break; + + default: + return EL_BADREL; + } + + return EL_OK; +} + +#endif diff --git a/ipl/gfx.c b/ipl/gfx.c index 5ba87fd..8a0b810 100755 --- a/ipl/gfx.c +++ b/ipl/gfx.c @@ -356,6 +356,8 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...) case 'd': _gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt); break; + case 'p': + case 'P': case 'x': case 'X': _gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt); diff --git a/ipl/gfx.h b/ipl/gfx.h index 9c32d23..abd4db4 100755 --- a/ipl/gfx.h +++ b/ipl/gfx.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (C) 2018 CTCaer + * Copyright (C) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,29 +19,7 @@ #ifndef _GFX_H_ #define _GFX_H_ -#include "types.h" - -typedef struct _gfx_ctxt_t -{ - u32 *fb; - u32 width; - u32 height; - u32 stride; -} gfx_ctxt_t; - -typedef struct _gfx_con_t -{ - gfx_ctxt_t *gfx_ctxt; - u32 fntsz; - u32 x; - u32 y; - u32 savedx; - u32 savedy; - u32 fgcol; - int fillbg; - u32 bgcol; - int mute; -} gfx_con_t; +#include "../common/common_gfx.h" void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride); void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color); diff --git a/ipl/heap.c b/ipl/heap.c index dd2818b..db96ef3 100755 --- a/ipl/heap.c +++ b/ipl/heap.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,20 +17,7 @@ #include #include "heap.h" - -typedef struct _hnode -{ - int used; - u32 size; - struct _hnode *prev; - struct _hnode *next; -} hnode_t; - -typedef struct _heap -{ - u32 start; - hnode_t *first; -} heap_t; +#include "../common/common_heap.h" static void _heap_create(heap_t *heap, u32 start) { @@ -110,7 +98,7 @@ static void _heap_free(heap_t *heap, u32 addr) } } -static heap_t _heap; +heap_t _heap; void heap_init(u32 base) { @@ -122,6 +110,11 @@ void *malloc(u32 size) return (void *)_heap_alloc(&_heap, size, 0x10); } +void *memalign(u32 align, u32 size) +{ + return (void *)_heap_alloc(&_heap, size, align); +} + void *calloc(u32 num, u32 size) { void *res = (void *)_heap_alloc(&_heap, num * size, 0x10); diff --git a/ipl/heap.h b/ipl/heap.h index 08c2c0e..37fcc2a 100755 --- a/ipl/heap.h +++ b/ipl/heap.h @@ -23,5 +23,6 @@ void heap_init(u32 base); void *malloc(u32 size); void *calloc(u32 num, u32 size); void free(void *buf); +void *memalign(u32 align, u32 size); #endif diff --git a/ipl/main.c b/ipl/main.c index bd21575..b8cac7e 100755 --- a/ipl/main.c +++ b/ipl/main.c @@ -4,6 +4,7 @@ * Copyright (c) 2018 Rajko Stojadinovic * Copyright (c) 2018 CTCaer * Copyright (c) 2018 Reisyukaku + * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -57,6 +58,13 @@ #include "bq24193.h" #include "config.h" +#include "elfloader/elfload.h" +#include "../common/common_module.h" + +// TODO: Make it not suck +FIL globalElfFile; +void *elfBuff; + //TODO: ugly. gfx_ctxt_t gfx_ctxt; gfx_con_t gfx_con; @@ -1719,6 +1727,113 @@ out: btn_wait(); } +void mainApplicationCb(const char *test) +{ + gfx_printf(&gfx_con, "\n%s\n\n", test); + //btn_wait(); + + return; +} + +extern heap_t _heap; +static void call_elf_ep(moduleEntrypoint_t entrypoint) +{ + pmoduleConfiguration_t moduleConfig = (pmoduleConfiguration_t)malloc(sizeof(struct moduleConfiguration_t)); + moduleConfig->gfxCon = &gfx_con; + moduleConfig->gfxCtx = &gfx_ctxt; + moduleConfig->memcpy = (memcpy_t)&memcpy; + moduleConfig->memset = (memset_t)&memset; + moduleConfig->sharedHeap = &_heap; + + entrypoint(mainApplicationCb, moduleConfig); +} + +static void *elfAllocationCallback( + el_ctx *ctx, + Elf_Addr phys, + Elf_Addr virt, + Elf_Addr size) +{ + (void)ctx; + (void)phys; + (void)size; + return (void *)virt; +} + +void *buffteg = NULL; +static bool elfReadCallback(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset) +{ + (void)ctx; + + memcpy(dest, buffteg + offset, numberBytes); + + return true; +} + +// TODO: ??? Add more modules! +void launch_elf() +{ + gfx_clear_grey(&gfx_ctxt, 0x1B); + gfx_con_setpos(&gfx_con, 0, 0); + + if (sd_mount()) + { + gfx_printf(&gfx_con, "Attempting to execute: %s\n", "module_sample.so"); + + buffteg = sd_file_read("module_sample.so"); + + sd_unmount(); + + el_ctx ctx; + ctx.pread = elfReadCallback; + + if (el_init(&ctx)) + { + gfx_printf(&gfx_con, "%s\n", "Cant init ELF context"); + goto elfLoadFinalOut; + } + + elfBuff = memalign(ctx.align, ctx.memsz); + if (!elfBuff) + { + gfx_printf(&gfx_con, "%s\n", "Cant alloc memory"); + goto elfLoadFinalOut; + } + + ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuff; + if (el_load(&ctx, elfAllocationCallback)) + { + gfx_printf(&gfx_con, "%s\n", "el_load"); + goto elfFreeOut; + } + + if (el_relocate(&ctx)) + { + gfx_printf(&gfx_con, "%s\n", "el_relocate"); + goto elfFreeOut; + } + + uintptr_t epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuff; + moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr; + + call_elf_ep(ep); + + elfFreeOut: + free(elfBuff); + elfBuff = NULL; + } + else + { + gfx_printf(&gfx_con, "%s\n", "Cant mount SD"); + goto elfLoadFinalOut; + } + +elfLoadFinalOut: + btn_wait(); + + return; +} + void launch_firmware() { u8 max_entries = 61; @@ -2425,7 +2540,10 @@ void about() " - bcl-1.2.0,\n" " Copyright (C) 2003-2006, Marcus Geelnard\n\n" " - Atmosphere (SE sha256, prc id patches),\n" - " Copyright (C) 2018, Atmosphere-NX\n" + " Copyright (C) 2018, Atmosphere-NX\n\n" + " - elfload,\n" + " Copyright (C) 2014, Owen Shepherd\n" + " Copyright (C) 2018, M4xw\n" " ___________________________________________\n\n"; static const char octopus[] = " %k___\n" @@ -2577,6 +2695,7 @@ menu_t menu_tools = { ment_t ment_top[] = { MDEF_HANDLER("Launch firmware", launch_firmware), + MDEF_HANDLER("Launch ELF", launch_elf), MDEF_MENU("Launch options", &menu_options), MDEF_CAPTION("---------------", 0xFF444444), MDEF_MENU("Tools", &menu_tools), diff --git a/modules/sample/Makefile b/modules/sample/Makefile new file mode 100644 index 0000000..87cffa7 --- /dev/null +++ b/modules/sample/Makefile @@ -0,0 +1,31 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/base_rules + +TARGET := module_sample +BUILD := ../../build_ipl +OUTPUT := ../../output + +OBJS = $(addprefix $(BUILD)/,\ + module_sample.o \ +) + +LD = $(DEVKITPRO)/devkitARM/bin/arm-none-eabi-ld +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork +CUSTOMDEFINES := -D__arm__ -DARM +CFLAGS = $(ARCH) -O2 -nostdlib -std=gnu11 -fpie -Wall $(CUSTOMDEFINES) +LDFLAGS = $(ARCH) -nostartfiles -lgcc + +.PHONY: clean all + +all: $(TARGET).so +$(BUILD)/%.o: ./%.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).so: $(BUILD)/$(TARGET).o + $(LD) $(LDLAGS) -pie -entry _pluginInit $(BUILD)/$(TARGET).o -o $(OUTPUT)/$(TARGET).so + +clean: + @rm -rf $(OUTPUT)/$(TARGET).so diff --git a/modules/sample/module_sample.c b/modules/sample/module_sample.c new file mode 100644 index 0000000..038f44b --- /dev/null +++ b/modules/sample/module_sample.c @@ -0,0 +1,10 @@ +/* Sample Hekate Module + 2018 - M4xw +*/ + +#include "../../common/common_module.h" + +void _pluginInit(cbMainModule_t cb, pmoduleConfiguration_t mc) +{ + cb("Hello World!"); +}