Reworked libelf to support relocation

Split elf.c into elf32.c and elf64.c for better readability. Added relocation
code to libelf for 64-bit ELF images, modified the Paflof Makefile to link
the executable with relocation information and load Paflof now to the upper
end of the memory.

Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
This commit is contained in:
Thomas Huth 2011-07-01 11:22:21 +02:00
parent 2e2e4cae37
commit 7a3606eeb9
10 changed files with 791 additions and 178 deletions

View File

@ -264,7 +264,9 @@ early_c_entry(uint64_t start_addr)
load_file(0x100, "xvect", 0, romfs_base);
load_file(SLAVELOOP_LOADBASE, "stageS", 0, romfs_base);
c_romfs_lookup("ofw_main", romfs_base, &fileInfo);
load_elf_file((void *) fileInfo.addr_data, &ofw_addr);
elf_load_file((void *) fileInfo.addr_data, &ofw_addr,
NULL, flush_cache);
ofw_start =
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
&ofw_addr;
@ -279,6 +281,7 @@ early_c_entry(uint64_t start_addr)
* non-ePAPR-compliant firmware
* r7 = implementation dependent
*/
asm volatile("isync; sync;" : : : "memory");
ofw_start(0, romfs_base, 0, 0, 0);
// never return
}

View File

@ -124,7 +124,7 @@ void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
struct romfs_lookup_t fileInfo;
void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
uint64_t *boot_info;
uint64_t romfs_base;
uint64_t romfs_base, paflof_base;
// romfs header values
struct stH *header = (struct stH *) (start_addr + 0x28);
uint64_t flashlen = 0;
@ -133,9 +133,15 @@ void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
flashlen = header->flashlen;
romfs_base = 0x10000000 - 0x400000;
if (romfs_base)
memcpy((char *)romfs_base, 0, 0x400000);
if (fdt_addr == 0) {
puts("ERROR: Flatten device tree available!");
}
/* Hack: Determine base for "ROM filesystem" in memory...
* QEMU loads the FDT at the top of the available RAM, so we place
* the ROMFS just underneath. */
romfs_base = (fdt_addr - 0x410000) & ~0xffffLL;
memcpy((char *)romfs_base, 0, 0x400000);
exception_stack_frame = 0;
@ -157,12 +163,21 @@ void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
DEBUG(" [ofw_main size data 0x%lx]\n", fileInfo.size_data);
DEBUG(" [ofw_main flags 0x%lx]\n", fileInfo.flags);
DEBUG(" [hdr: 0x%08lx 0x%08lx]\n [ 0x%08lx 0x%08lx]\n",
((uint64_t *)fileInfo.addr_header)[0],
((uint64_t *)fileInfo.addr_header)[0],
((uint64_t *)fileInfo.addr_header)[1],
((uint64_t *)fileInfo.addr_header)[2],
((uint64_t *)fileInfo.addr_header)[3]);
rc = load_elf_file((void *)fileInfo.addr_data, ofw_addr);
/* Assume that paflof need ca. 16 MiB RAM right now..
* TODO: Use value from ELF file instead */
paflof_base = romfs_base - 0x1000000 + 0x100;
if ((int64_t)paflof_base <= 0LL) {
puts("ERROR: Not enough memory for Open Firmware");
}
rc = elf_load_file_to_addr((void *)fileInfo.addr_data, (void*)paflof_base,
ofw_addr, NULL, flush_cache);
DEBUG(" [load_elf_file returned %d]\n", rc);
ofw_start =
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
&ofw_addr;

View File

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
@ -10,9 +10,79 @@
* IBM Corporation - initial implementation
*****************************************************************************/
/*
* ELF loader library
*/
#ifndef __LIBELF_H
#define __LIBELF_H
int load_elf_file(unsigned long *, unsigned long *);
#include <stdint.h>
/* ELF object file types */
#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 */
/* Generic ELF header */
struct ehdr {
uint32_t ei_ident;
uint8_t ei_class;
uint8_t ei_data;
uint8_t ei_version;
uint8_t ei_pad[9];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
};
/* Section types (sh_type) */
#define SHT_NULL 0 /* Unused section header */
#define SHT_PROGBITS 1 /* Information defined by the program */
#define SHT_SYMTAB 2 /* Linker symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* "Rela" type relocation entries */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking tables */
#define SHT_NOTE 7 /* Note information */
#define SHT_NOBITS 8 /* Uninitialized space */
#define SHT_REL 9 /* "Rel" type relocation entries */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Dynamic loader symbol table */
/* Section attributs (sh_flags) */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
/* Segment types (p_type) */
#define PT_NULL 0 /* Unused entry */
#define PT_LOAD 1 /* Loadable segment */
#define PT_DYNAMIC 2 /* Dynamic linking tables */
#define PT_INTERP 3 /* Program interpreter path name */
#define PT_NOTE 4 /* Note sections */
int elf_load_file(void *file_addr, unsigned long *entry,
int (*pre_load)(void*, long),
void (*post_load)(void*, long));
int elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry,
int (*pre_load)(void*, long),
void (*post_load)(void*, long));
unsigned int elf_load_segments32(void *file_addr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long));
unsigned long elf_load_segments64(void *file_addr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long));
long elf_get_base_addr(void *file_addr);
long elf_get_base_addr32(void *file_addr);
long elf_get_base_addr64(void *file_addr);
void elf_relocate64(void *file_addr, signed long offset);
#endif /* __LIBELF_H */

View File

@ -1,5 +1,5 @@
# *****************************************************************************
# * Copyright (c) 2004, 2008 IBM Corporation
# * Copyright (c) 2004, 2011 IBM Corporation
# * All rights reserved.
# * This program and the accompanying materials
# * are made available under the terms of the BSD License
@ -21,7 +21,7 @@ TARGET = ../libelf.a
all: $(TARGET)
SRCS = elf.c
SRCS = elf.c elf32.c elf64.c
OBJS = $(SRCS:%.c=%.o)

View File

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
@ -10,161 +10,14 @@
* IBM Corporation - initial implementation
*****************************************************************************/
/* this is elf.fs rewritten in C */
/*
* ELF loader
*/
#include <string.h>
#include <cpu.h>
#include <cache.h>
#include <libelf.h>
struct ehdr {
unsigned int ei_ident;
unsigned char ei_class;
unsigned char ei_data;
unsigned char ei_version;
unsigned char ei_pad[9];
unsigned short e_type;
unsigned short e_machine;
unsigned int e_version;
unsigned int e_entry;
unsigned int e_phoff;
unsigned int e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shstrndx;
};
struct phdr {
unsigned int p_type;
unsigned int p_offset;
unsigned int p_vaddr;
unsigned int p_paddr;
unsigned int p_filesz;
unsigned int p_memsz;
unsigned int p_flags;
unsigned int p_align;
};
struct ehdr64 {
unsigned int ei_ident;
unsigned char ei_class;
unsigned char ei_data;
unsigned char ei_version;
unsigned char ei_pad[9];
unsigned short e_type;
unsigned short e_machine;
unsigned int e_version;
unsigned long e_entry;
unsigned long e_phoff;
unsigned long e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shstrndx;
};
struct phdr64 {
unsigned int p_type;
unsigned int p_flags;
unsigned long p_offset;
unsigned long p_vaddr;
unsigned long p_paddr;
unsigned long p_filesz;
unsigned long p_memsz;
unsigned long p_align;
};
#define VOID(x) (void *)((unsigned long)x)
static void
load_segment(unsigned long *file_addr, struct phdr *phdr)
{
unsigned long src = phdr->p_offset + (unsigned long) file_addr;
/* copy into storage */
memmove(VOID(phdr->p_vaddr), VOID(src), phdr->p_filesz);
/* clear bss */
memset(VOID(phdr->p_vaddr + phdr->p_filesz), 0,
phdr->p_memsz - phdr->p_filesz);
if (phdr->p_memsz) {
flush_cache(VOID(phdr->p_vaddr), phdr->p_memsz);
}
}
static unsigned int
load_segments(unsigned long *file_addr)
{
struct ehdr *ehdr = (struct ehdr *) file_addr;
/* Calculate program header address */
struct phdr *phdr =
(struct phdr *) (((unsigned char *) file_addr) + ehdr->e_phoff);
int i;
/* loop e_phnum times */
for (i = 0; i <= ehdr->e_phnum; i++) {
/* PT_LOAD ? */
if (phdr->p_type == 1) {
/* copy segment */
load_segment(file_addr, phdr);
}
/* step to next header */
phdr =
(struct phdr *) (((unsigned char *) phdr) +
ehdr->e_phentsize);
}
return ehdr->e_entry;
}
static void
load_segment64(unsigned long *file_addr, struct phdr64 *phdr64)
{
unsigned long src = phdr64->p_offset + (unsigned long) file_addr;
/* copy into storage */
memmove(VOID(phdr64->p_vaddr), VOID(src), phdr64->p_filesz);
/* clear bss */
memset(VOID(phdr64->p_vaddr + phdr64->p_filesz), 0,
phdr64->p_memsz - phdr64->p_filesz);
if (phdr64->p_memsz) {
flush_cache(VOID(phdr64->p_vaddr), phdr64->p_memsz);
}
}
static unsigned long
load_segments64(unsigned long *file_addr)
{
struct ehdr64 *ehdr64 = (struct ehdr64 *) file_addr;
/* Calculate program header address */
struct phdr64 *phdr64 =
(struct phdr64 *) (((unsigned char *) file_addr) + ehdr64->e_phoff);
int i;
/* loop e_phnum times */
for (i = 0; i <= ehdr64->e_phnum; i++) {
/* PT_LOAD ? */
if (phdr64->p_type == 1) {
/* copy segment */
load_segment64(file_addr, phdr64);
}
/* step to next header */
phdr64 =
(struct phdr64 *) (((unsigned char *) phdr64) +
ehdr64->e_phentsize);
}
return ehdr64->e_entry;
}
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be32(x) (x)
#else
#define cpu_to_be32(x) bswap_32(x)
#endif
#include <byteorder.h>
/**
* elf_check_file tests if the file at file_addr is
@ -185,7 +38,7 @@ elf_check_file(unsigned long *file_addr)
return -1;
/* endian check */
#if __BYTE_ORDER == __BIG_ENDIAN
#ifdef __BIG_ENDIAN__
if (ehdr->ei_data != 2)
/* not a big endian image */
#else
@ -194,8 +47,9 @@ elf_check_file(unsigned long *file_addr)
#endif
return -2;
/* check if it is an ELF executable */
if (ehdr->e_type != 2)
/* check if it is an ELF executable ... and also
* allow DYN files, since this is specified by ePAPR */
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
return -3;
/* check if it is a PPC ELF executable */
@ -214,21 +68,98 @@ elf_check_file(unsigned long *file_addr)
* @param file_addr pointer to the start of the elf file
* @param entry pointer where the ELF loader will store
* the entry point
* @param pre_load handler that is called before copying a segment
* @param post_load handler that is called after copying a segment
* @return 1 for a 32 bit file
* 2 for a 64 bit file
* anything else means an error during load
*/
int
load_elf_file(unsigned long *file_addr, unsigned long *entry)
elf_load_file(void *file_addr, unsigned long *entry,
int (*pre_load)(void*, long),
void (*post_load)(void*, long))
{
int type = elf_check_file(file_addr);
switch (type) {
case 1:
*entry = load_segments(file_addr);
*entry = elf_load_segments32(file_addr, 0, pre_load, post_load);
break;
case 2:
*entry = load_segments64(file_addr);
*entry = elf_load_segments64(file_addr, 0, pre_load, post_load);
break;
}
return type;
}
/**
* load_elf_file_to_addr loads an ELF file to given address.
* This is useful for 64-bit vmlinux images that use the virtual entry
* point address in their headers, and thereby need a special treatment.
*
* @param file_addr pointer to the start of the elf file
* @param entry pointer where the ELF loader will store
* the entry point
* @param pre_load handler that is called before copying a segment
* @param post_load handler that is called after copying a segment
* @return 1 for a 32 bit file
* 2 for a 64 bit file
* anything else means an error during load
*/
int
elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry,
int (*pre_load)(void*, long),
void (*post_load)(void*, long))
{
int type;
long offset;
type = elf_check_file(file_addr);
switch (type) {
case 1:
/* Parse 32-bit image */
offset = (long)addr - elf_get_base_addr32(file_addr);
*entry = elf_load_segments32(file_addr, offset, pre_load,
post_load) + offset;
// TODO: elf_relocate32(...)
break;
case 2:
/* Parse 64-bit image */
offset = (long)addr - elf_get_base_addr64(file_addr);
*entry = elf_load_segments64(file_addr, offset, pre_load,
post_load) + offset;
elf_relocate64(file_addr, offset);
break;
}
return type;
}
/**
* Get the base load address of the ELF image
* @return The base address or -1 for error
*/
long
elf_get_base_addr(void *file_addr)
{
int type;
type = elf_check_file(file_addr);
switch (type) {
case 1:
/* Return 32-bit image base address */
return elf_get_base_addr32(file_addr);
break;
case 2:
/* Return 64-bit image base address */
return elf_get_base_addr64(file_addr);
break;
}
return -1;
}

144
lib/libelf/elf32.c Normal file
View File

@ -0,0 +1,144 @@
/******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
*
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
/*
* 32-bit ELF loader
*/
#include <string.h>
#include <libelf.h>
struct ehdr32 {
uint32_t ei_ident;
uint8_t ei_class;
uint8_t ei_data;
uint8_t ei_version;
uint8_t ei_pad[9];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry;
uint32_t e_phoff;
uint32_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
};
struct phdr32 {
uint32_t p_type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
};
static struct phdr32*
get_phdr32(void *file_addr)
{
return (struct phdr32 *) (((unsigned char *)file_addr)
+ ((struct ehdr32 *)file_addr)->e_phoff);
}
static void
load_segment(void *file_addr, struct phdr32 *phdr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long))
{
unsigned long src = phdr->p_offset + (unsigned long) file_addr;
unsigned long destaddr;
destaddr = (unsigned long)phdr->p_paddr;
destaddr = destaddr + offset;
/* check if we're allowed to copy */
if (pre_load != NULL) {
if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
return;
}
/* copy into storage */
memmove((void *)destaddr, (void *)src, phdr->p_filesz);
/* clear bss */
memset((void *)(destaddr + phdr->p_filesz), 0,
phdr->p_memsz - phdr->p_filesz);
if (phdr->p_memsz && post_load) {
post_load((void*)destaddr, phdr->p_memsz);
}
}
unsigned int
elf_load_segments32(void *file_addr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long))
{
struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
/* Calculate program header address */
struct phdr32 *phdr = get_phdr32(file_addr);
int i;
signed int virt2phys = 0; /* Offset between virtual and physical */
/* loop e_phnum times */
for (i = 0; i <= ehdr->e_phnum; i++) {
/* PT_LOAD ? */
if (phdr->p_type == 1) {
if (!virt2phys) {
virt2phys = phdr->p_paddr - phdr->p_vaddr;
}
/* copy segment */
load_segment(file_addr, phdr, offset, pre_load,
post_load);
}
/* step to next header */
phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
}
/* Entry point is always a virtual address, so translate it
* to physical before returning it */
return ehdr->e_entry + virt2phys;
}
/**
* Return the base address for loading (i.e. the address of the first PT_LOAD
* segment)
* @param file_addr pointer to the ELF file in memory
* @return the base address
*/
long
elf_get_base_addr32(void *file_addr)
{
struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
struct phdr32 *phdr = get_phdr32(file_addr);
int i;
/* loop e_phnum times */
for (i = 0; i <= ehdr->e_phnum; i++) {
/* PT_LOAD ? */
if (phdr->p_type == 1) {
return phdr->p_paddr;
}
/* step to next header */
phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
}
return 0;
}

422
lib/libelf/elf64.c Normal file
View File

@ -0,0 +1,422 @@
/******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
*
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
/*
* 64-bit ELF loader for PowerPC.
* See the "64-bit PowerPC ELF Application Binary Interface Supplement" and
* the "ELF-64 Object File Format" documentation for details.
*/
#include <string.h>
#include <stdio.h>
#include <libelf.h>
struct ehdr64
{
uint32_t ei_ident;
uint8_t ei_class;
uint8_t ei_data;
uint8_t ei_version;
uint8_t ei_pad[9];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint64_t e_entry;
uint64_t e_phoff;
uint64_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
};
struct phdr64
{
uint32_t p_type;
uint32_t p_flags;
uint64_t p_offset;
uint64_t p_vaddr;
uint64_t p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align;
};
struct shdr64
{
uint32_t sh_name; /* Section name */
uint32_t sh_type; /* Section type */
uint64_t sh_flags; /* Section attributes */
uint64_t sh_addr; /* Virtual address in memory */
uint64_t sh_offset; /* Offset in file */
uint64_t sh_size; /* Size of section */
uint32_t sh_link; /* Link to other section */
uint32_t sh_info; /* Miscellaneous information */
uint64_t sh_addralign; /* Address alignment boundary */
uint64_t sh_entsize; /* Size of entries, if section has table */
};
struct rela /* RelA relocation table entry */
{
uint64_t r_offset; /* Address of reference */
uint64_t r_info; /* Symbol index and type of relocation */
int64_t r_addend; /* Constant part of expression */
};
struct sym64
{
uint32_t st_name; /* Symbol name */
uint8_t st_info; /* Type and Binding attributes */
uint8_t st_other; /* Reserved */
uint16_t st_shndx; /* Section table index */
uint64_t st_value; /* Symbol value */
uint64_t st_size; /* Size of object (e.g., common) */
};
/* For relocations */
#define ELF_R_SYM(i) ((i)>>32)
#define ELF_R_TYPE(i) ((uint32_t)(i) & 0xFFFFFFFF)
#define ELF_R_INFO(s,t) ((((uint64_t) (s)) << 32) + (t))
/*
* Relocation types for PowerPC64.
*/
#define R_PPC64_NONE 0
#define R_PPC64_ADDR32 1
#define R_PPC64_ADDR24 2
#define R_PPC64_ADDR16 3
#define R_PPC64_ADDR16_LO 4
#define R_PPC64_ADDR16_HI 5
#define R_PPC64_ADDR16_HA 6
#define R_PPC64_ADDR14 7
#define R_PPC64_ADDR14_BRTAKEN 8
#define R_PPC64_ADDR14_BRNTAKEN 9
#define R_PPC64_REL24 10
#define R_PPC64_REL14 11
#define R_PPC64_REL14_BRTAKEN 12
#define R_PPC64_REL14_BRNTAKEN 13
#define R_PPC64_GOT16 14
#define R_PPC64_GOT16_LO 15
#define R_PPC64_GOT16_HI 16
#define R_PPC64_GOT16_HA 17
#define R_PPC64_COPY 19
#define R_PPC64_GLOB_DAT 20
#define R_PPC64_JMP_SLOT 21
#define R_PPC64_RELATIVE 22
#define R_PPC64_UADDR32 24
#define R_PPC64_UADDR16 25
#define R_PPC64_REL32 26
#define R_PPC64_PLT32 27
#define R_PPC64_PLTREL32 28
#define R_PPC64_PLT16_LO 29
#define R_PPC64_PLT16_HI 30
#define R_PPC64_PLT16_HA 31
#define R_PPC64_SECTOFF 33
#define R_PPC64_SECTOFF_LO 34
#define R_PPC64_SECTOFF_HI 35
#define R_PPC64_SECTOFF_HA 36
#define R_PPC64_ADDR30 37
#define R_PPC64_ADDR64 38
#define R_PPC64_ADDR16_HIGHER 39
#define R_PPC64_ADDR16_HIGHERA 40
#define R_PPC64_ADDR16_HIGHEST 41
#define R_PPC64_ADDR16_HIGHESTA 42
#define R_PPC64_UADDR64 43
#define R_PPC64_REL64 44
#define R_PPC64_PLT64 45
#define R_PPC64_PLTREL64 46
#define R_PPC64_TOC16 47
#define R_PPC64_TOC16_LO 48
#define R_PPC64_TOC16_HI 49
#define R_PPC64_TOC16_HA 50
#define R_PPC64_TOC 51
#define R_PPC64_PLTGOT16 52
#define R_PPC64_PLTGOT16_LO 53
#define R_PPC64_PLTGOT16_HI 54
#define R_PPC64_PLTGOT16_HA 55
#define R_PPC64_ADDR16_DS 56
#define R_PPC64_ADDR16_LO_DS 57
#define R_PPC64_GOT16_DS 58
#define R_PPC64_GOT16_LO_DS 59
#define R_PPC64_PLT16_LO_DS 60
#define R_PPC64_SECTOFF_DS 61
#define R_PPC64_SECTOFF_LO_DS 62
#define R_PPC64_TOC16_DS 63
#define R_PPC64_TOC16_LO_DS 64
#define R_PPC64_PLTGOT16_DS 65
#define R_PPC64_PLTGOT16_LO_DS 66
#define R_PPC64_TLS 67
#define R_PPC64_DTPMOD64 68
#define R_PPC64_TPREL16 69
#define R_PPC64_TPREL16_LO 60
#define R_PPC64_TPREL16_HI 71
#define R_PPC64_TPREL16_HA 72
#define R_PPC64_TPREL64 73
#define R_PPC64_DTPREL16 74
#define R_PPC64_DTPREL16_LO 75
#define R_PPC64_DTPREL16_HI 76
#define R_PPC64_DTPREL16_HA 77
#define R_PPC64_DTPREL64 78
#define R_PPC64_GOT_TLSGD16 79
#define R_PPC64_GOT_TLSGD16_LO 80
#define R_PPC64_GOT_TLSGD16_HI 81
#define R_PPC64_GOT_TLSGD16_HA 82
#define R_PPC64_GOT_TLSLD16 83
#define R_PPC64_GOT_TLSLD16_LO 84
#define R_PPC64_GOT_TLSLD16_HI 85
#define R_PPC64_GOT_TLSLD16_HA 86
#define R_PPC64_GOT_TPREL16_DS 87
#define R_PPC64_GOT_TPREL16_LO_ DS 88
#define R_PPC64_GOT_TPREL16_HI 89
#define R_PPC64_GOT_TPREL16_HA 90
#define R_PPC64_GOT_DTPREL16_DS 91
#define R_PPC64_GOT_DTPREL16_LO_DS 92
#define R_PPC64_GOT_DTPREL16_HI 93
#define R_PPC64_GOT_DTPREL16_HA 94
#define R_PPC64_TPREL16_DS 95
#define R_PPC64_TPREL16_LO_DS 96
#define R_PPC64_TPREL16_HIGHER 97
#define R_PPC64_TPREL16_HIGHERA 98
#define R_PPC64_TPREL16_HIGHEST 99
#define R_PPC64_TPREL16_HIGHESTA 100
#define R_PPC64_DTPREL16_DS 101
#define R_PPC64_DTPREL16_LO_DS 102
#define R_PPC64_DTPREL16_HIGHER 103
#define R_PPC64_DTPREL16_HIGHERA 104
#define R_PPC64_DTPREL16_HIGHEST 105
#define R_PPC64_DTPREL16_HIGHESTA 106
static struct phdr64*
get_phdr64(unsigned long *file_addr)
{
return (struct phdr64 *) (((unsigned char *) file_addr)
+ ((struct ehdr64 *)file_addr)->e_phoff);
}
static void
load_segment64(unsigned long *file_addr, struct phdr64 *phdr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long))
{
unsigned long src = phdr->p_offset + (unsigned long) file_addr;
unsigned long destaddr;
destaddr = phdr->p_paddr + offset;
/* check if we're allowed to copy */
if (pre_load != NULL) {
if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
return;
}
/* copy into storage */
memmove((void*)destaddr, (void*)src, phdr->p_filesz);
/* clear bss */
memset((void*)(destaddr + phdr->p_filesz), 0,
phdr->p_memsz - phdr->p_filesz);
if (phdr->p_memsz && post_load != NULL) {
post_load((void*)destaddr, phdr->p_memsz);
}
}
unsigned long
elf_load_segments64(void *file_addr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long))
{
struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
/* Calculate program header address */
struct phdr64 *phdr = get_phdr64(file_addr);
int i;
signed long virt2phys = 0; /* Offset between virtual and physical */
/* loop e_phnum times */
for (i = 0; i <= ehdr->e_phnum; i++) {
/* PT_LOAD ? */
if (phdr->p_type == PT_LOAD) {
if (!virt2phys) {
virt2phys = phdr->p_paddr - phdr->p_vaddr;
}
/* copy segment */
load_segment64(file_addr, phdr, offset, pre_load, post_load);
}
/* step to next header */
phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
}
/* Entry point is always a virtual address, so translate it
* to physical before returning it */
return ehdr->e_entry + virt2phys;
}
/**
* Return the base address for loading (i.e. the address of the first PT_LOAD
* segment)
* @param file_addr pointer to the ELF file in memory
* @return the base address
*/
long
elf_get_base_addr64(void *file_addr)
{
struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
/* Calculate program header address */
struct phdr64 *phdr = get_phdr64(file_addr);
int i;
/* loop e_phnum times */
for (i = 0; i <= ehdr->e_phnum; i++) {
/* PT_LOAD ? */
if (phdr->p_type == PT_LOAD) {
/* Return base address */
return phdr->p_paddr;
}
/* step to next header */
phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
}
return 0;
}
/**
* Apply one relocation entry.
*/
static void
elf_apply_rela64(void *file_addr, signed long offset, struct rela *relaentry,
struct sym64 *symtabentry)
{
void *addr;
unsigned long s_a;
unsigned long base_addr;
base_addr = elf_get_base_addr64(file_addr);
/* Sanity check */
if (relaentry->r_offset < base_addr) {
printf("\nELF relocation out of bounds!\n");
return;
}
base_addr += offset;
/* Actual address where the relocation will be applied at. */
addr = (void*)(relaentry->r_offset + offset);
/* Symbol value (S) + Addend (A) */
s_a = symtabentry->st_value + offset + relaentry->r_addend;
switch (ELF_R_TYPE(relaentry->r_info)) {
case R_PPC64_ADDR32: /* S + A */
*(uint32_t *)addr = (uint32_t) s_a;
break;
case R_PPC64_ADDR64: /* S + A */
*(uint64_t *)addr = (uint64_t) s_a;
break;
case R_PPC64_TOC: /* .TOC */
*(uint64_t *)addr += offset;
break;
case R_PPC64_ADDR16_HIGHEST: /* #highest(S + A) */
*(uint16_t *)addr = ((s_a >> 48) & 0xffff);
break;
case R_PPC64_ADDR16_HIGHER: /* #higher(S + A) */
*(uint16_t *)addr = ((s_a >> 32) & 0xffff);
break;
case R_PPC64_ADDR16_HI: /* #hi(S + A) */
*(uint16_t *)addr = ((s_a >> 16) & 0xffff);
break;
case R_PPC64_ADDR16_LO: /* #lo(S + A) */
*(uint16_t *)addr = s_a & 0xffff;
break;
case R_PPC64_ADDR16_LO_DS:
*(uint16_t *)addr = (s_a & 0xfffc);
break;
case R_PPC64_ADDR16_HA: /* #ha(S + A) */
*(uint16_t *)addr = (((s_a >> 16) + ((s_a & 0x8000) ? 1 : 0))
& 0xffff);
break;
case R_PPC64_TOC16: /* half16* S + A - .TOC. */
case R_PPC64_TOC16_LO_DS:
case R_PPC64_TOC16_LO: /* #lo(S + A - .TOC.) */
case R_PPC64_TOC16_HI: /* #hi(S + A - .TOC.) */
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_DS: /* (S + A - .TOC) >> 2 */
case R_PPC64_REL14:
case R_PPC64_REL24: /* (S + A - P) >> 2 */
case R_PPC64_REL64: /* S + A - P */
// printf("\t\tignoring relocation type %i\n",
// ELF_R_TYPE(relaentry->r_info));
break;
default:
printf("ERROR: Unhandled relocation (A) type %i\n",
ELF_R_TYPE(relaentry->r_info));
}
}
/**
* Step through all relocation entries and apply them one by one.
*/
static void
elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx)
{
struct shdr64 *rela_shdr = &shdrs[idx];
struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info];
struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link];
struct rela *relaentry;
struct sym64 *symtabentry;
uint32_t symbolidx;
int i;
/* If the referenced section has not been allocated, then it has
* not been loaded and thus does not need to be relocated. */
if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC)
return;
for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) {
relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i);
symbolidx = ELF_R_SYM(relaentry->r_info);
symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx;
elf_apply_rela64(file_addr, offset, relaentry, symtabentry);
}
}
/**
* Apply ELF relocations
*/
void
elf_relocate64(void *file_addr, signed long offset)
{
struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
/* Calculate section header address */
struct shdr64 *shdrs = (struct shdr64 *)
(((unsigned char *) file_addr) + ehdr->e_shoff);
int i;
/* loop over all segments */
for (i = 0; i <= ehdr->e_shnum; i++) {
/* Skip if it is not a relocation segment */
if (shdrs[i].sh_type == SHT_RELA) {
elf_apply_all_rela64(file_addr, offset, shdrs, i);
}
}
}

View File

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
@ -9,13 +9,35 @@
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
int load_elf_file(unsigned long *file_addr, unsigned long *entry);
PRIM(LOADELF)
/*
* libelf Forth wrapper
*/
#include <libelf.h>
// : elf-load-file ( fileaddr -- entry type )
PRIM(ELF_X2d_LOAD_X2d_FILE)
{
void *file_addr = TOS.a;
int type;
unsigned long entry;
type = load_elf_file(file_addr, &entry);
type = elf_load_file(file_addr, &entry, elf_forth_claim, flush_cache);
TOS.u = entry;
PUSH; TOS.n = type;
}
MIRP
// : elf-load-file-to-addr ( fileaddr destaddr -- entry type )
PRIM(ELF_X2d_LOAD_X2d_FILE_X2d_TO_X2d_ADDR)
{
void *dest_addr = TOS.a; POP;
void *file_addr = TOS.a;
int type;
unsigned long entry;
type = elf_load_file_to_addr(file_addr, dest_addr, &entry,
elf_forth_claim, flush_cache);
TOS.u = entry;
PUSH; TOS.n = type;
}
MIRP

View File

@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
@ -9,4 +9,10 @@
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
cod(LOADELF)
/*
* libelf bindings for Forth - definitions
*/
cod(ELF-LOAD-FILE)
cod(ELF-LOAD-FILE-TO-ADDR)

View File

@ -32,7 +32,7 @@ CFLAGS = -DTARG=$(TARG) -static -Wall -W -std=gnu99 \
-fno-stack-protector
ASFLAGS = -Wa,-mpower4 -Wa,-mregnames $(FLAG) $(CPUARCHDEF)
LDFLAGS += -static -nostdlib
LDFLAGS += -static -nostdlib -Wl,-q,-n
ifneq ($(TARG),unix)
CFLAGS += -nostdinc -fno-builtin
@ -91,7 +91,7 @@ paflof: $(SLOFCMNDIR)/OF.lds $(SLOFCMNDIR)/ofw.o paflof.o $(SLOFCMNDIR)/entry.o
$(LLFWBRDDIR)/io_generic_lib.o $(LDFLAGS) $(SLOF_LIBS) -o $@
#save a copy of paflof before stripping
@cp $@ $@.unstripped
$(STRIP) -s $@
$(STRIP) --strip-unneeded $@
paflof.o: board.code dict.xt
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/paflof.c