jehanne/sys/src/kern/port/elf64.c

483 lines
15 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "getput.h"
typedef struct Elf64_Ehdr Elf64_Ehdr;
typedef struct Elf64_Phdr Elf64_Phdr;
enum {
EI_MAG0 = 0, // File identification
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4, // File class
ELFCLASS32 = 1, // 32-bit objects
ELFCLASS64 = 2, // 64-bit objects
EI_DATA = 5, // Data encoding
ELFDATA2LSB = 1, // Object file data structures are littleendian
ELFDATA2MSB = 2, // Object file data structures are bigendian
EI_VERSION = 6, // File version
EI_OSABI = 7, // OS/ABI identification
ELFOSABI_SYSV = 0, // System V ABI
ELFOSABI_HPUX = 1,
EI_ABIVERSION = 8, // ABI version
EI_PAD = 9, // Start of padding bytes
EI_NIDENT = 16, // Size of e_ident[]
ET_NONE = 0, // No file type
ET_REL = 1, // Relocatable object file
ET_EXEC = 2, // Executable file
ET_DYN = 3, // Shared object file
ET_CORE = 4, // Core file
PT_NULL = 0, // Unused entry
PT_LOAD = 1, // Loadable segment
PT_DYNAMIC = 2, // Dynamic linking tables
PT_INTERP = 3, // Program interpreter path name
PT_NOTE = 4, // Note sections
PT_SHLIB = 5, // Reserved
PT_PHDR = 6, // Program header table
EM_NONE = 0, // No
EM_M32 = 1, // AT&T WE
EM_SPARC = 2, //
EM_386 = 3, // Intel
EM_68K = 4, // Motorola
EM_88K = 5, // Motorola
EM_IAMCU = 6, // Intel
EM_860 = 7, // Intel
EM_MIPS = 8, // MIPS I
EM_S370 = 9, // IBM System/370
EM_MIPS_RS3_LE = 10, // MIPS RS3000
// reserved
EM_PARISC = 15, // Hewlett-Packard
// reserved
EM_VPP500 = 17, // Fujitsu
EM_SPARC32PLUS = 18, // Enhanced instruction set
EM_960 = 19, // Intel
EM_PPC = 20, //
EM_PPC64 = 21, // 64-bit
EM_S390 = 22, // IBM System/390
EM_SPU = 23, // IBM
// reserved
EM_V800 = 36, // NEC
EM_FR20 = 37, // Fujitsu
EM_RH32 = 38, // TRW
EM_RCE = 39, // Motorola
EM_ARM = 40, // ARM 32-bit architecture
EM_ALPHA = 41, // Digital
EM_SH = 42, // Hitachi
EM_SPARCV9 = 43, // SPARC Version
EM_TRICORE = 44, // Siemens TriCore embedded
EM_ARC = 45, // Argonaut RISC Core, Argonaut Technologies
EM_H8_300 = 46, // Hitachi
EM_H8_300H = 47, // Hitachi
EM_H8S = 48, // Hitachi
EM_H8_500 = 49, // Hitachi
EM_IA_64 = 50, // Intel IA-64 processor
EM_MIPS_X = 51, // Stanford
EM_COLDFIRE = 52, // Motorola
EM_68HC12 = 53, // Motorola
EM_MMA = 54, // Fujitsu MMA Multimedia
EM_PCP = 55, // Siemens
EM_NCPU = 56, // Sony nCPU embedded RISC
EM_NDR1 = 57, // Denso NDR1
EM_STARCORE = 58, // Motorola Star*Core
EM_ME16 = 59, // Toyota ME16
EM_ST100 = 60, // STMicroelectronics ST100
EM_TINYJ = 61, // Advanced Logic Corp. TinyJ embedded processor
EM_X86_64 = 62, // AMD x86-64
EM_PDSP = 63, // Sony DSP
EM_PDP10 = 64, // Digital Equipment Corp.
EM_PDP11 = 65, // Digital Equipment Corp.
EM_FX66 = 66, // Siemens FX66
EM_ST9PLUS = 67, // STMicroelectronics ST9+ 8/16 bit
EM_ST7 = 68, // STMicroelectronics ST7 8-bit
EM_68HC16 = 69, // Motorola MC68HC16
EM_68HC11 = 70, // Motorola MC68HC11
EM_68HC08 = 71, // Motorola MC68HC08
EM_68HC05 = 72, // Motorola MC68HC05
EM_SVX = 73, // Silicon Graphics
EM_ST19 = 74, // STMicroelectronics ST19 8-bit
EM_VAX = 75, // Digital
EM_CRIS = 76, // Axis Communications 32-bit embedded
EM_JAVELIN = 77, // Infineon Technologies 32-bit embedded
EM_FIREPATH = 78, // Element 14 64-bit DSP
EM_ZSP = 79, // LSI Logic 16-bit DSP
EM_MMIX = 80, // Donald Knuth's educational 64-bit
EM_HUANY = 81, // Harvard University machine-independent object
EM_PRISM = 82, // SiTera
EM_AVR = 83, // Atmel AVR 8-bit
EM_FR30 = 84, // Fujitsu
EM_D10V = 85, // Mitsubishi
EM_D30V = 86, // Mitsubishi
EM_V850 = 87, // NEC
EM_M32R = 88, // Mitsubishi
EM_MN10300 = 89, // Matsushita
EM_MN10200 = 90, // Matsushita
EM_PJ = 91, //
EM_OPENRISC = 92, // OpenRISC 32-bit embedded
EM_ARC_COMPACT = 93, // ARC International ARCompact processor (old spelling/synonym:
EM_XTENSA = 94, // Tensilica Xtensa
EM_VIDEOCORE = 95, // Alphamosaic VideoCore
EM_TMM_GPP = 96, // Thompson Multimedia General Purpose
EM_NS32K = 97, // National Semiconductor 32000
EM_TPC = 98, // Tenor Network TPC
EM_SNP1K = 99, // Trebia SNP 1000
EM_ST200 = 100, // STMicroelectronics (www.st.com) ST200
EM_IP2K = 101, // Ubicom IP2xxx microcontroller
EM_MAX = 102, // MAX
EM_CR = 103, // National Semiconductor CompactRISC
EM_F2MC16 = 104, // Fujitsu
EM_MSP430 = 105, // Texas Instruments embedded microcontroller
EM_BLACKFIN = 106, // Analog Devices Blackfin (DSP)
EM_SE_C33 = 107, // S1C33 Family of Seiko Epson
EM_SEP = 108, // Sharp embedded
EM_ARCA = 109, // Arca RISC
EM_UNICORE = 110, // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking
EM_EXCESS = 111, // eXcess: 16/32/64-bit configurable embedded
EM_DXP = 112, // Icera Semiconductor Inc. Deep Execution
EM_ALTERA_NIOS2 = 113, // Altera Nios II soft-core
EM_CRX = 114, // National Semiconductor CompactRISC CRX
EM_XGATE = 115, // Motorola XGATE embedded
EM_C166 = 116, // Infineon C16x/XC16x
EM_M16C = 117, // Renesas M16C series
EM_DSPIC30F = 118, // Microchip Technology dsPIC30F Digital Signal
EM_CE = 119, // Freescale Communication Engine RISC
EM_M32C = 120, // Renesas M32C series
// reserved
EM_TSK3000 = 131, // Altium TSK3000
EM_RS08 = 132, // Freescale RS08 embedded
EM_SHARC = 133, // Analog Devices SHARC family of 32-bit DSP
EM_ECOG2 = 134, // Cyan Technology eCOG2
EM_SCORE7 = 135, // Sunplus S+core7 RISC
EM_DSP24 = 136, // New Japan Radio (NJR) 24-bit DSP
EM_VIDEOCORE3 = 137, // Broadcom VideoCore III
EM_LATTICEMICO32 = 138, // RISC processor for Lattice FPGA
EM_SE_C17 = 139, // Seiko Epson C17
EM_TI_C6000 = 140, // The Texas Instruments TMS320C6000 DSP
EM_TI_C2000 = 141, // The Texas Instruments TMS320C2000 DSP
EM_TI_C5500 = 142, // The Texas Instruments TMS320C55x DSP
EM_TI_ARP32 = 143, // Texas Instruments Application Specific RISC Processor, 32bit
EM_TI_PRU = 144, // Texas Instruments Programmable Realtime
// reserved
EM_MMDSP_PLUS = 160, // STMicroelectronics 64bit VLIW Data Signal
EM_CYPRESS_M8C = 161, // Cypress M8C
EM_R32C = 162, // Renesas R32C series
EM_TRIMEDIA = 163, // NXP Semiconductors TriMedia architecture
EM_QDSP6 = 164, // QUALCOMM DSP6
EM_8051 = 165, // Intel 8051 and
EM_STXP7X = 166, // STMicroelectronics STxP7x family of configurable and extensible RISC
EM_NDS32 = 167, // Andes Technology compact code size embedded RISC processor
EM_ECOG1 = 168, // Cyan Technology eCOG1X
EM_ECOG1X = 168, // Cyan Technology eCOG1X
EM_MAXQ30 = 169, // Dallas Semiconductor MAXQ30 Core
EM_XIMO16 = 170, // New Japan Radio (NJR) 16-bit DSP
EM_MANIK = 171, // M2000 Reconfigurable RISC
EM_CRAYNV2 = 172, // Cray Inc. NV2 vector
EM_RX = 173, // Renesas RX
EM_METAG = 174, // Imagination Technologies META processor
EM_MCST_ELBRUS = 175, // MCST Elbrus general purpose hardware
EM_ECOG16 = 176, // Cyan Technology eCOG16
EM_CR16 = 177, // National Semiconductor CompactRISC CR16 16-bit
EM_ETPU = 178, // Freescale Extended Time Processing
EM_SLE9X = 179, // Infineon Technologies SLE9X
EM_L10M = 180, // Intel
EM_K10M = 181, // Intel
// reserved(Intel)
EM_AARCH64 = 183, // ARM 64-bit architecture
// reserved(ARM)
EM_AVR32 = 185, // Atmel Corporation 32-bit microprocessor
EM_STM8 = 186, // STMicroeletronics STM8 8-bit
EM_TILE64 = 187, // Tilera TILE64 multicore architecture
EM_TILEPRO = 188, // Tilera TILEPro multicore architecture
EM_MICROBLAZE = 189, // Xilinx MicroBlaze 32-bit RISC soft processor
EM_CUDA = 190, // NVIDIA CUDA
EM_TILEGX = 191, // Tilera TILE-Gx multicore architecture
EM_CLOUDSHIELD = 192, // CloudShield architecture
EM_COREA_1ST = 193, // KIPO-KAIST Core-A 1st generation processor
EM_COREA_2ND = 194, // KIPO-KAIST Core-A 2nd generation processor
EM_ARC_COMPACT2 = 195, // Synopsys ARCompact
EM_OPEN8 = 196, // Open8 8-bit RISC soft processor
EM_RL78 = 197, // Renesas RL78
EM_VIDEOCORE5 = 198, // Broadcom VideoCore V
EM_78KOR = 199, // Renesas 78KOR
EM_56800EX = 200, // Freescale 56800EX Digital Signal Controller
EM_BA1 = 201, // Beyond BA1 CPU
EM_BA2 = 202, // Beyond BA2 CPU
EM_XCORE = 203, // XMOS xCORE processor
EM_MCHP_PIC = 204, // Microchip 8-bit PIC(r)
// reserved(Intel)
EM_KM32 = 210, // KM211 KM32 32-bit
EM_KMX32 = 211, // KM211 KMX32 32-bit
EM_KMX16 = 212, // KM211 KMX16 16-bit
EM_KMX8 = 213, // KM211 KMX8 8-bit
EM_KVARC = 214, // KM211 KVARC
EM_CDP = 215, // Paneve CDP architecture
EM_COGE = 216, // Cognitive Smart Memory
EM_COOL = 217, // Bluechip Systems
EM_NORC = 218, // Nanoradio Optimized
EM_CSR_KALIMBA = 219, // CSR Kalimba architecture
EM_Z80 = 220, // Zilog
EM_VISIUM = 221, // Controls and Data Services VISIUMcore
EM_FT32 = 222, // FTDI Chip FT32 high performance 32-bit RISC
EM_MOXIE = 223, // Moxie processor
EM_AMDGPU = 224, // AMD GPU
EM_RISCV = 243, // Berkeley RISC-V
PF_X = 0x1, // Execute permission
PF_W = 0x2, // Write permission
PF_R = 0x4, // Read permission
};
struct Elf64_Ehdr {
uint8_t e_ident[16]; /* ELF identification */
uint8_t e_type[2]; /* Object file type */
uint8_t e_machine[2]; /* Machine type */
uint8_t e_version[4]; /* Object file version */
uint8_t e_entry[8]; /* Entry point address */
uint8_t e_phoff[8]; /* Program header offset */
uint8_t e_shoff[8]; /* Section header offset */
uint8_t e_flags[4]; /* Processor-specific flags */
uint8_t e_ehsize[2]; /* ELF header size */
uint8_t e_phentsize[2]; /* Size of program header entry */
uint8_t e_phnum[2]; /* Number of program header entries */
uint8_t e_shentsize[2]; /* Size of section header entry */
uint8_t e_shnum[2]; /* Number of section header entries */
uint8_t e_shstrndx[2]; /* Section name string table index */
};
struct Elf64_Phdr {
uint8_t p_type[4]; /* Type of segment */
uint8_t p_flags[4]; /* Segment attributes */
uint8_t p_offset[8]; /* Offset in file */
uint8_t p_vaddr[8]; /* Virtual address in memory */
uint8_t p_paddr[8]; /* Reserved */
uint8_t p_filesz[8]; /* Size of segment in file */
uint8_t p_memsz[8]; /* Size of segment in memory */
uint8_t p_align[8]; /* Alignment of segment */
};
static struct {
char *mach;
int e_machine;
} elfmachs[] = {
{"amd64", EM_X86_64},
{"arm64", EM_AARCH64},
{"power64", EM_PPC64},
};
static int
ispow2(uintptr_t a)
{
return ((a != 0) && (a & (a-1)) == 0);
}
static int
overlap(uintptr_t a0, uintptr_t aend, uintptr_t b0, uintptr_t bend)
{
uint64_t max0, minend;
max0 = a0 > b0 ? a0 : b0;
minend = aend < bend ? aend : bend;
return max0 < minend;
}
/*
* return the number of ldsegs in rp
*/
int
elf64ldseg(Chan *c, uintptr_t *entryp, Ldseg **rp, char *mach, uint32_t minpgsz)
{
Elf64_Ehdr ehdr;
uint16_t (*get16)(uint8_t *);
uint32_t (*get32)(uint8_t *);
uint64_t (*get64)(uint8_t *);
uint8_t *phbuf, *phend;
uint8_t *fp;
Ldseg *ldseg;
uint64_t entry;
int i, j, si;
entry = 0;
phbuf = nil;
ldseg = nil;
si = 0;
if(waserror()){
if(ldseg != nil)
jehanne_free(ldseg);
if(phbuf != nil)
jehanne_free(phbuf);
nexterror();
}
if(c->dev->read(c, &ehdr, sizeof ehdr, 0) != sizeof ehdr){
// pprint("elf64ldseg: too short for header\n");
goto done; // too short to be elf but could be something else
}
fp = ehdr.e_ident;
if(fp[EI_MAG0] == '\x7f' && fp[EI_MAG1] == 'E' && fp[EI_MAG2] == 'L' && fp[EI_MAG3] == 'F'){
if(fp[EI_DATA] == ELFDATA2LSB){
get16 = get16le;
get32 = get32le;
get64 = get64le;
} else if(fp[EI_DATA] == ELFDATA2MSB){
get16 = get16be;
get32 = get32be;
get64 = get64be;
} else {
error(Ebadexec);
}
if(fp[EI_CLASS] == ELFCLASS64){
int64_t phoff;
uint32_t phnum, phentsize;
uint16_t e_machine;
e_machine = get16(ehdr.e_machine);
if(mach != nil){
for(i = 0; i < nelem(elfmachs); i++)
if(elfmachs[i].e_machine == e_machine && !jehanne_strcmp(mach, elfmachs[i].mach))
break;
if(i == nelem(elfmachs)){
pprint("elf64ldseg: e_machine %d incorrect for host %s\n", e_machine, mach);
error(Ebadexec);
}
}
entry = get64(ehdr.e_entry);
phoff = get16(ehdr.e_phoff);
phnum = get16(ehdr.e_phnum);
phentsize = get16(ehdr.e_phentsize);
if(phentsize*phnum > minpgsz){
pprint("elf64ldseg: phentsize %d phnum %d exceeds page size %d\n", phentsize, phnum, minpgsz);
error(Ebadexec);
}
phbuf = jehanne_malloc(phentsize*phnum);
if(phbuf == nil){
pprint("elf64ldseg: malloc fail\n");
error(Ebadexec);
}
if(c->dev->read(c, phbuf, phentsize*phnum, phoff) != phentsize*phnum){
pprint("elf64ldseg: read program header fail\n");
error(Ebadexec);
}
si = 0;
phend = phbuf + phentsize*phnum;
for(fp = phbuf; fp < phend; fp += phentsize){
Elf64_Phdr *phdr;
phdr = (Elf64_Phdr*)fp;
if(get32(phdr->p_type) == PT_LOAD)
si++;
}
ldseg = jehanne_malloc(si * sizeof ldseg[0]);
if(ldseg == nil){
pprint("elf64ldseg: malloc fail\n");
error(Ebadexec);
}
si = 0;
for(fp = phbuf; fp < phend; fp += phentsize){
Elf64_Phdr *phdr;
phdr = (Elf64_Phdr*)fp;
if(get32(phdr->p_type) == PT_LOAD){
uint64_t offset, vaddr, align, filesz, memsz;
uint32_t flags;
flags = get32(phdr->p_flags); /* Segment attributes */
offset = get64(phdr->p_offset); /* Offset in file */
vaddr = get64(phdr->p_vaddr); /* Virtual address in memory */
filesz = get64(phdr->p_filesz); /* Size of segment in file */
memsz = get64(phdr->p_memsz); /* Size of segment in memory */
align = get64(phdr->p_align); /* Alignment of segment */
ldseg[si].type = SgLoad;
if((flags & PF_R) != 0)
ldseg[si].permissions |= SgRead;
if((flags & PF_W) != 0)
ldseg[si].permissions |= SgWrite;
if((flags & PF_X) != 0)
ldseg[si].permissions |= SgExecute;
if(memsz < filesz){
pprint("elf64ldseg: memsz %d < filesz %d\n", memsz, filesz);
error(Ebadexec);
}
if(!ispow2(align)){
pprint("elf64ldseg: align 0x%x not a power of 2\n", align);
error(Ebadexec);
}
if(align < minpgsz){
pprint("elf64ldseg: align 0x%x < minpgsz 0x%x\n", align, minpgsz);
error(Ebadexec);
}
if(offset & (align-1) != vaddr & (align-1)){
pprint("elf64ldseg: va offset 0x%x != file offset 0x%x (align 0x%x)\n",
offset & (align-1),
vaddr & (align-1),
align
);
error(Ebadexec);
}
ldseg[si].pgsz = align;
ldseg[si].memsz = memsz;
ldseg[si].filesz = filesz;
ldseg[si].pg0fileoff = offset & ~(align-1);
ldseg[si].pg0vaddr = vaddr & ~(align-1);
ldseg[si].pg0off = offset & (align-1);
si++;
}
}
for(i = 0; i < si; i++){
for(j = 0; j < si; j++){
if(i != j){
Ldseg *lda, *ldb;
lda = ldseg+i;
ldb = ldseg+j;
if(overlap(
lda->pg0vaddr, lda->pg0vaddr + lda->pg0off + lda->memsz,
ldb->pg0vaddr, ldb->pg0vaddr + ldb->pg0off + ldb->memsz
)){
pprint("elf64ldseg: load segs %p:%p and %p:%p ovelap\n",
lda->pg0vaddr, lda->pg0vaddr + lda->pg0off + lda->memsz,
ldb->pg0vaddr, ldb->pg0vaddr + ldb->pg0off + ldb->memsz
);
error(Ebadexec);
}
}
}
}
} else {
pprint("elf64ldseg: not elfclass64\n");
error(Ebadexec);
}
}
done:
if(phbuf != nil)
jehanne_free(phbuf);
if(rp != nil){
*rp = ldseg;
} else if(ldseg != nil){
jehanne_free(ldseg);
}
if(entryp != nil)
*entryp = entry;
poperror();
return si;
}