| /* |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file "COPYING" in the main directory of this archive |
| * for more details. |
| * |
| * Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com |
| */ |
| #ifdef __hpux |
| /* prevent inclusion of Linux types.h */ |
| # define _LINUX_TYPES_H |
| typedef unsigned long long uint64_t; |
| #endif |
| #include "common.h" |
| #include "load.h" |
| |
| #ifndef __hpux |
| # include <stdint.h> |
| #endif |
| #include <stdio.h> |
| #include <linux/elf.h> |
| |
| /* check that the address is zeros in the top 32 bits, then return |
| * the bottom 32 bits |
| */ |
| static uint32_t |
| addr32(uint64_t a) |
| { |
| const int mask32 = 0xffffffff; |
| const int mask16 = 0xffff; |
| a = __be64_to_cpu(a); |
| if (0) printf("checkaddr32(%04x:%04x:%04x:%04x)\r\n", |
| (uint32_t)(a >> (16 * 3)) & mask16, |
| (uint32_t)(a >> (16 * 2)) & mask16, |
| (uint32_t)(a >> (16 * 1)) & mask16, |
| (uint32_t)(a >> (16 * 0)) & mask16); |
| if ((a & ~mask32) != 0) |
| { |
| printf("checkaddr32(%04x:%04x:%04x:%04x) not valid 32 bit\n", |
| (uint32_t)(a >> (16 * 3)) & mask16, |
| (uint32_t)(a >> (16 * 2)) & mask16, |
| (uint32_t)(a >> (16 * 1)) & mask16, |
| (uint32_t)(a >> (16 * 0)) & mask16); |
| while(1); |
| } |
| |
| return (uint32_t)(a & mask32); |
| } |
| |
| int prepare_ELF64_loadable(int fd, struct loadable *loadable, int *wide) |
| { |
| struct elf64_hdr eh; |
| uint32_t last = 0; |
| int i; |
| |
| *wide = 1; |
| |
| STRUCTREAD(fd, eh, 0); |
| |
| if (eh.e_ident[EI_MAG0] != ELFMAG0 || |
| eh.e_ident[EI_MAG1] != ELFMAG1 || |
| eh.e_ident[EI_MAG2] != ELFMAG2 || |
| eh.e_ident[EI_MAG3] != ELFMAG3 || |
| eh.e_ident[EI_CLASS] != ELFCLASS64 || |
| __be16_to_cpu(eh.e_type) != ET_EXEC) |
| { |
| return PREPARE_CONTINUE; |
| } |
| |
| if (__be16_to_cpu(eh.e_machine) != EM_PARISC) |
| { |
| printf("Fatal - ELF, but not for PARISC\n"); |
| return PREPARE_FATAL; |
| } |
| |
| printf("ELF64 executable\n"); |
| |
| /* We like this kind of ELF... */ |
| eh.e_phnum = __be16_to_cpu(eh.e_phnum); |
| for (i = 0; i < eh.e_phnum; i++) |
| { |
| struct elf64_phdr ep; |
| struct loadsegment *seg; |
| uint32_t start, end; |
| |
| STRUCTREAD(fd, ep, addr32(eh.e_phoff) + i * sizeof ep); |
| if (__be32_to_cpu(ep.p_type) != PT_LOAD) |
| continue; |
| |
| seg = &loadable->segment[loadable->n++]; |
| |
| /* vaddr or paddr? HP-UX kernel elf seems to use vaddr */ |
| start = addr32(ep.p_vaddr); |
| if (loadable->n == 1 || start < loadable->first) |
| { |
| loadable->first = start; |
| } |
| end = addr32(ep.p_vaddr) + addr32(ep.p_filesz); |
| if (end > last) |
| last = end; |
| |
| seg->offset = addr32(ep.p_offset); |
| |
| if (loadable->n == 1 || seg->offset < loadable->offset0) |
| { |
| loadable->offset0 = seg->offset; |
| } |
| seg->length = addr32(ep.p_filesz); |
| seg->mem = start; |
| seg->zeros = addr32(ep.p_memsz) - addr32(ep.p_filesz); |
| } |
| |
| loadable->size = last - loadable->first; |
| /* is entry a virtual or physical address? */ |
| loadable->entry = addr32(eh.e_entry); |
| |
| return PREPARE_OK; |
| } |