Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

firmware: add simple ELF loader for static binaries

This is a small & simple ELF loader which just copies
program segments from disk to memory. It only supports
static binaries right now.

Change-Id: I8944feb5b9dafcc5c56e12383aed25e2718ad7ea

authored by

Aidan MacDonald and committed by
Solomon Peachy
a610998e 21ba79d4

+466
+4
firmware/SOURCES
··· 58 58 lc-rock.c 59 59 #endif 60 60 61 + #if defined(HAVE_ELF) 62 + elf_loader.c 63 + #endif 64 + 61 65 #if defined(HAVE_BOOTDATA) || defined(HAVE_MULTIBOOT) 62 66 common/multiboot.c 63 67 #ifndef BOOTLOADER
+175
firmware/elf_loader.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2026 Aidan MacDonald 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * as published by the Free Software Foundation; either version 2 15 + * of the License, or (at your option) any later version. 16 + * 17 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 + * KIND, either express or implied. 19 + * 20 + ****************************************************************************/ 21 + #include "elf_loader.h" 22 + #include "elf-target.h" 23 + #include "file.h" 24 + 25 + #if defined(ROCKBOX_LITTLE_ENDIAN) 26 + # define NATIVE_ELF_DATA ELFDATA2LSB 27 + #elif defined(ROCKBOX_BIG_ENDIAN) 28 + # define NATIVE_ELF_DATA ELFDATA2MSB 29 + #else 30 + # error "Unknown endianness!" 31 + #endif 32 + 33 + _Static_assert(TARGET_ELF_DATA == NATIVE_ELF_DATA, 34 + "ELF binaries with foreign endianness not supported"); 35 + 36 + static int elf_validate_header(const struct elf_header *header) 37 + { 38 + if (header->ei_magic[0] != ELFMAG0 || 39 + header->ei_magic[1] != ELFMAG1 || 40 + header->ei_magic[2] != ELFMAG2 || 41 + header->ei_magic[3] != ELFMAG3) 42 + return ELF_ERR_BADMAGIC; 43 + 44 + if (header->ei_class != TARGET_ELF_CLASS || 45 + header->ei_data != TARGET_ELF_DATA) 46 + return ELF_ERR_UNSUPP_ARCH; 47 + 48 + if (header->ei_version != EV_CURRENT || 49 + header->e_version != EV_CURRENT) 50 + return ELF_ERR_UNSUPP_VERSION; 51 + 52 + if (header->ei_osabi != TARGET_ELF_OSABI || 53 + header->ei_abiversion != TARGET_ELF_ABIVERSION) 54 + return ELF_ERR_UNSUPP_OS; 55 + 56 + if (header->e_type != ET_EXEC) 57 + return ELF_ERR_UNSUPP_TYPE; 58 + 59 + if (header->e_machine != TARGET_ELF_MACHINE) 60 + return ELF_ERR_UNSUPP_ARCH; 61 + 62 + if (header->e_phoff == 0) 63 + return ELF_ERR_EMPTY; 64 + 65 + if (header->e_phentsize < sizeof(struct elf_phdr)) 66 + return ELF_ERR_UNSUPP_PHSIZE; 67 + 68 + if (header->e_phnum == PN_XNUM) 69 + return ELF_ERR_TOO_MANY_PHDRS; 70 + 71 + return ELF_OK; 72 + } 73 + 74 + static int elf_validate_phdr(const struct elf_phdr *phdr, 75 + const struct elf_load_context *ctx) 76 + { 77 + if (phdr->p_type != PT_LOAD) 78 + return ELF_ERR_UNSUPP_PHDR; 79 + 80 + if (phdr->p_filesz > phdr->p_memsz) 81 + return ELF_ERR_INVALID_PHDR; 82 + 83 + /* Ignore headers which occupy zero memory */ 84 + if (phdr->p_memsz == 0) 85 + return 0; 86 + 87 + for (size_t i = 0; i < ctx->num_mmap; ++i) 88 + { 89 + const struct elf_memory_map *entry = &ctx->mmap[i]; 90 + if (phdr->p_vaddr >= entry->addr && 91 + phdr->p_vaddr < entry->addr + entry->size && 92 + phdr->p_memsz <= entry->size) 93 + { 94 + if ((phdr->p_flags & entry->flags) != phdr->p_flags) 95 + return ELF_ERR_MEM_INCOMPAT_FLAGS; 96 + 97 + return ELF_OK; 98 + } 99 + } 100 + 101 + return ELF_ERR_MEM_UNMAPPED; 102 + } 103 + 104 + int elf_loadfd(int fd, 105 + const struct elf_load_context *ctx, 106 + void **entrypoint) 107 + { 108 + struct elf_header ehdr; 109 + struct elf_phdr phdr; 110 + ssize_t nread; 111 + int err; 112 + 113 + nread = read(fd, &ehdr, sizeof(ehdr)); 114 + if (nread != (ssize_t)sizeof(ehdr)) 115 + return ELF_ERR_IO; 116 + 117 + err = elf_validate_header(&ehdr); 118 + if (err != ELF_OK) 119 + return err; 120 + 121 + /* 122 + * Iterate over program headers, copying segments to memory 123 + */ 124 + for (size_t ph_index = 0; ph_index < ehdr.e_phnum; ++ph_index) 125 + { 126 + off_t ph_off = ehdr.e_phoff + (ph_index * ehdr.e_phentsize); 127 + if (lseek(fd, ph_off, SEEK_SET) == (off_t)-1) 128 + return ELF_ERR_IO; 129 + 130 + nread = read(fd, &phdr, sizeof(phdr)); 131 + if (nread != (ssize_t)sizeof(phdr)) 132 + return ELF_ERR_IO; 133 + 134 + err = elf_validate_phdr(&phdr, ctx); 135 + if (err) 136 + return err; 137 + 138 + /* Load file data to memory if needed */ 139 + if (phdr.p_filesz > 0) 140 + { 141 + if (lseek(fd, phdr.p_offset, SEEK_SET) == (off_t)-1) 142 + return ELF_ERR_IO; 143 + 144 + nread = read(fd, (void *)phdr.p_vaddr, phdr.p_filesz); 145 + if (nread < 0 || (uint32_t)nread != phdr.p_filesz) 146 + return ELF_ERR_IO; 147 + } 148 + 149 + /* Zero out any memory not backed by file data */ 150 + if (phdr.p_memsz > phdr.p_filesz) 151 + { 152 + void *addr = (void *)phdr.p_vaddr + phdr.p_filesz; 153 + size_t size = phdr.p_memsz - phdr.p_filesz; 154 + 155 + memset(addr, 0, size); 156 + } 157 + } 158 + 159 + *entrypoint = (void *)ehdr.e_entry; 160 + return ELF_OK; 161 + } 162 + 163 + int elf_loadpath(const char *filename, 164 + const struct elf_load_context *ctx, 165 + void **entrypoint) 166 + { 167 + int fd = open(filename, O_RDONLY); 168 + if (fd < 0) 169 + return ELF_ERR_FILE_NOT_FOUND; 170 + 171 + int err = elf_loadfd(fd, ctx, entrypoint); 172 + 173 + close(fd); 174 + return err; 175 + }
+50
firmware/include/elf-target.h
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2026 Aidan MacDonald 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * as published by the Free Software Foundation; either version 2 15 + * of the License, or (at your option) any later version. 16 + * 17 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 + * KIND, either express or implied. 19 + * 20 + ****************************************************************************/ 21 + #ifndef __ELF_TARGET_H__ 22 + #define __ELF_TARGET_H__ 23 + 24 + #include "elf.h" 25 + #include "config.h" 26 + 27 + #define TARGET_ELF_CLASS ELFCLASS32 28 + #define TARGET_ELF_OSABI ELFOSABI_SYSV 29 + #define TARGET_ELF_ABIVERSION 0 30 + #define elf_phdr elf32_phdr 31 + 32 + #if defined(CPU_ARM) 33 + # define TARGET_ELF_MACHINE EM_ARM 34 + #elif defined(CPU_MIPS) 35 + # define TARGET_ELF_MACHINE EM_MIPS 36 + #elif defined(CPU_COLDFIRE) 37 + # define TARGET_ELF_MACHINE EM_68K 38 + #else 39 + # error "Unknown CPU architecture!" 40 + #endif 41 + 42 + #if defined(ROCKBOX_LITTLE_ENDIAN) 43 + # define TARGET_ELF_DATA ELFDATA2LSB 44 + #elif defined(ROCKBOX_BIG_ENDIAN) 45 + # define TARGET_ELF_DATA ELFDATA2MSB 46 + #else 47 + # error "Unknown endianness!" 48 + #endif 49 + 50 + #endif /* __ELF_TARGET_H__ */
+143
firmware/include/elf.h
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2026 Aidan MacDonald 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * as published by the Free Software Foundation; either version 2 15 + * of the License, or (at your option) any later version. 16 + * 17 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 + * KIND, either express or implied. 19 + * 20 + ****************************************************************************/ 21 + #ifndef __ELF_H__ 22 + #define __ELF_H__ 23 + 24 + #include <stdint.h> 25 + 26 + /* Field offsets in the e_ident array */ 27 + #define EI_MAG0 0 28 + #define EI_MAG1 1 29 + #define EI_MAG2 2 30 + #define EI_MAG3 3 31 + #define EI_CLASS 4 32 + #define EI_DATA 5 33 + #define EI_VERSION 6 34 + #define EI_OSABI 7 35 + #define EI_ABIVERSION 8 36 + #define EI_PAD 9 37 + #define EI_NIDENT 16 38 + 39 + /* Values for ei_magic */ 40 + #define ELFMAG0 0x7f 41 + #define ELFMAG1 'E' 42 + #define ELFMAG2 'L' 43 + #define ELFMAG3 'F' 44 + 45 + /* Values for ei_class */ 46 + #define ELFCLASSNONE 0 47 + #define ELFCLASS32 1 48 + #define ELFCLASS64 2 49 + 50 + /* Values for ei_data */ 51 + #define ELFDATANONE 0 52 + #define ELFDATA2LSB 1 53 + #define ELFDATA2MSB 2 54 + 55 + /* Values for ei_version and e_version */ 56 + #define EV_NONE 0 57 + #define EV_CURRENT 1 58 + 59 + /* Values for ei_osabi */ 60 + #define ELFOSABI_NONE ELFOSABI_SYSV 61 + #define ELFOSABI_SYSV 0 62 + 63 + /* Values for e_type */ 64 + #define ET_NONE 0 65 + #define ET_REL 1 66 + #define ET_EXEC 2 67 + #define ET_DYN 3 68 + #define ET_CORE 4 69 + 70 + /* Values for e_machine */ 71 + #define EM_NONE 0 72 + #define EM_68K 4 73 + #define EM_MIPS 8 74 + #define EM_ARM 40 75 + 76 + /* 77 + * Special value for e_phnum when the real number of 78 + * program headers is too large. 79 + */ 80 + #define PN_XNUM 0xFFFFu 81 + 82 + /* ELF basic types */ 83 + typedef uint32_t elf_addr_t; 84 + typedef uint32_t elf_off_t; 85 + 86 + /* ELF file header */ 87 + struct elf_header 88 + { 89 + union { 90 + uint8_t e_ident[EI_NIDENT]; 91 + struct { 92 + uint8_t ei_magic[4]; 93 + uint8_t ei_class; 94 + uint8_t ei_data; 95 + uint8_t ei_version; 96 + uint8_t ei_osabi; 97 + uint8_t ei_abiversion; 98 + }; 99 + }; 100 + 101 + uint16_t e_type; 102 + uint16_t e_machine; 103 + uint32_t e_version; 104 + elf_addr_t e_entry; 105 + elf_off_t e_phoff; 106 + elf_off_t e_shoff; 107 + uint32_t e_flags; 108 + uint16_t e_ehsize; 109 + uint16_t e_phentsize; 110 + uint16_t e_phnum; 111 + uint16_t e_shentsize; 112 + uint16_t e_shnum; 113 + uint16_t e_shstrndx; 114 + }; 115 + 116 + /* Values for p_type */ 117 + #define PT_NULL 0 118 + #define PT_LOAD 1 119 + #define PT_DYNAMIC 2 120 + #define PT_INTERP 3 121 + #define PT_NOTE 4 122 + #define PT_SHLIB 5 123 + #define PT_PHDR 6 124 + 125 + /* Values for p_flags */ 126 + #define PF_X (1 << 0) /* Segment is executable */ 127 + #define PF_W (1 << 1) /* Segment is writable */ 128 + #define PF_R (1 << 2) /* Segment is readable */ 129 + 130 + /* ELF 32-bit program header */ 131 + struct elf32_phdr 132 + { 133 + uint32_t p_type; 134 + elf_off_t p_offset; 135 + elf_addr_t p_vaddr; 136 + elf_addr_t p_paddr; 137 + uint32_t p_filesz; 138 + uint32_t p_memsz; 139 + uint32_t p_flags; 140 + uint32_t p_align; 141 + }; 142 + 143 + #endif /* __ELF_H__ */
+94
firmware/include/elf_loader.h
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2026 Aidan MacDonald 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * as published by the Free Software Foundation; either version 2 15 + * of the License, or (at your option) any later version. 16 + * 17 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 + * KIND, either express or implied. 19 + * 20 + ****************************************************************************/ 21 + #ifndef __ELF_LOADER_H__ 22 + #define __ELF_LOADER_H__ 23 + 24 + /* 25 + * Primitive ELF loader -- allows loading an ELF binary from 26 + * a file descriptor into RAM. Only static binaries linked at 27 + * a fixed address are supported. 28 + * 29 + * The caller supplies a memory map which limits where the 30 + * ELF file can be loaded; if a program header requests any 31 + * memory outside of this mapping, loading will fail. There 32 + * is no support for relocation, PIC code, or any form of 33 + * dynamic linking. 34 + * 35 + * The loader can return the entry point of the ELF binary. 36 + * It does not support arbitrary symbol lookups. 37 + */ 38 + 39 + #include <stdint.h> 40 + #include <stddef.h> 41 + 42 + enum elf_error 43 + { 44 + ELF_OK, 45 + ELF_ERR_FILE_NOT_FOUND, 46 + ELF_ERR_IO, 47 + ELF_ERR_EMPTY, 48 + ELF_ERR_BADMAGIC, 49 + ELF_ERR_UNSUPP_ARCH, 50 + ELF_ERR_UNSUPP_OS, 51 + ELF_ERR_UNSUPP_VERSION, 52 + ELF_ERR_UNSUPP_TYPE, 53 + ELF_ERR_UNSUPP_FORMAT, 54 + ELF_ERR_UNSUPP_PHSIZE, 55 + ELF_ERR_TOO_MANY_PHDRS, 56 + ELF_ERR_UNSUPP_PHDR, 57 + ELF_ERR_INVALID_PHDR, 58 + ELF_ERR_MEM_INCOMPAT_FLAGS, 59 + ELF_ERR_MEM_UNMAPPED, 60 + }; 61 + 62 + /* 63 + * Describes an entry in the virtual memory map specified 64 + * when loading an ELF file. 65 + * 66 + * ELF segments must fit completely within a single entry 67 + * in the memory map. Segments crossing multiple mappings 68 + * are rejected even if the mappings are contiguous. 69 + * 70 + * A segment may also be rejected if it has flags (R/W/X) 71 + * not present in the corresponding memory map entry. 72 + */ 73 + struct elf_memory_map 74 + { 75 + uintptr_t addr; 76 + size_t size; 77 + uint32_t flags; 78 + }; 79 + 80 + struct elf_load_context 81 + { 82 + const struct elf_memory_map *mmap; 83 + size_t num_mmap; 84 + }; 85 + 86 + int elf_loadfd(int fd, 87 + const struct elf_load_context *ctx, 88 + void **entrypoint); 89 + 90 + int elf_loadpath(const char *filename, 91 + const struct elf_load_context *ctx, 92 + void **entrypoint); 93 + 94 + #endif /* __ELF_LOADER_H__ */