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:
parent
2e2e4cae37
commit
7a3606eeb9
|
@ -264,7 +264,9 @@ early_c_entry(uint64_t start_addr)
|
||||||
load_file(0x100, "xvect", 0, romfs_base);
|
load_file(0x100, "xvect", 0, romfs_base);
|
||||||
load_file(SLAVELOOP_LOADBASE, "stageS", 0, romfs_base);
|
load_file(SLAVELOOP_LOADBASE, "stageS", 0, romfs_base);
|
||||||
c_romfs_lookup("ofw_main", romfs_base, &fileInfo);
|
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 =
|
ofw_start =
|
||||||
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
|
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
|
||||||
&ofw_addr;
|
&ofw_addr;
|
||||||
|
@ -279,6 +281,7 @@ early_c_entry(uint64_t start_addr)
|
||||||
* non-ePAPR-compliant firmware
|
* non-ePAPR-compliant firmware
|
||||||
* r7 = implementation dependent
|
* r7 = implementation dependent
|
||||||
*/
|
*/
|
||||||
|
asm volatile("isync; sync;" : : : "memory");
|
||||||
ofw_start(0, romfs_base, 0, 0, 0);
|
ofw_start(0, romfs_base, 0, 0, 0);
|
||||||
// never return
|
// never return
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
|
||||||
struct romfs_lookup_t fileInfo;
|
struct romfs_lookup_t fileInfo;
|
||||||
void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
uint64_t *boot_info;
|
uint64_t *boot_info;
|
||||||
uint64_t romfs_base;
|
uint64_t romfs_base, paflof_base;
|
||||||
// romfs header values
|
// romfs header values
|
||||||
struct stH *header = (struct stH *) (start_addr + 0x28);
|
struct stH *header = (struct stH *) (start_addr + 0x28);
|
||||||
uint64_t flashlen = 0;
|
uint64_t flashlen = 0;
|
||||||
|
@ -133,8 +133,14 @@ void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
|
||||||
|
|
||||||
flashlen = header->flashlen;
|
flashlen = header->flashlen;
|
||||||
|
|
||||||
romfs_base = 0x10000000 - 0x400000;
|
if (fdt_addr == 0) {
|
||||||
if (romfs_base)
|
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);
|
memcpy((char *)romfs_base, 0, 0x400000);
|
||||||
|
|
||||||
exception_stack_frame = 0;
|
exception_stack_frame = 0;
|
||||||
|
@ -161,8 +167,17 @@ void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
|
||||||
((uint64_t *)fileInfo.addr_header)[1],
|
((uint64_t *)fileInfo.addr_header)[1],
|
||||||
((uint64_t *)fileInfo.addr_header)[2],
|
((uint64_t *)fileInfo.addr_header)[2],
|
||||||
((uint64_t *)fileInfo.addr_header)[3]);
|
((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);
|
DEBUG(" [load_elf_file returned %d]\n", rc);
|
||||||
|
|
||||||
ofw_start =
|
ofw_start =
|
||||||
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
|
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
|
||||||
&ofw_addr;
|
&ofw_addr;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (c) 2004, 2008 IBM Corporation
|
* Copyright (c) 2004, 2011 IBM Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
* This program and the accompanying materials
|
* This program and the accompanying materials
|
||||||
* are made available under the terms of the BSD License
|
* are made available under the terms of the BSD License
|
||||||
|
@ -10,9 +10,79 @@
|
||||||
* IBM Corporation - initial implementation
|
* IBM Corporation - initial implementation
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ELF loader library
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef __LIBELF_H
|
#ifndef __LIBELF_H
|
||||||
#define __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 */
|
#endif /* __LIBELF_H */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# *****************************************************************************
|
# *****************************************************************************
|
||||||
# * Copyright (c) 2004, 2008 IBM Corporation
|
# * Copyright (c) 2004, 2011 IBM Corporation
|
||||||
# * All rights reserved.
|
# * All rights reserved.
|
||||||
# * This program and the accompanying materials
|
# * This program and the accompanying materials
|
||||||
# * are made available under the terms of the BSD License
|
# * are made available under the terms of the BSD License
|
||||||
|
@ -21,7 +21,7 @@ TARGET = ../libelf.a
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
SRCS = elf.c
|
SRCS = elf.c elf32.c elf64.c
|
||||||
|
|
||||||
OBJS = $(SRCS:%.c=%.o)
|
OBJS = $(SRCS:%.c=%.o)
|
||||||
|
|
||||||
|
|
249
lib/libelf/elf.c
249
lib/libelf/elf.c
|
@ -1,5 +1,5 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (c) 2004, 2008 IBM Corporation
|
* Copyright (c) 2004, 2011 IBM Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
* This program and the accompanying materials
|
* This program and the accompanying materials
|
||||||
* are made available under the terms of the BSD License
|
* are made available under the terms of the BSD License
|
||||||
|
@ -10,161 +10,14 @@
|
||||||
* IBM Corporation - initial implementation
|
* IBM Corporation - initial implementation
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/* this is elf.fs rewritten in C */
|
/*
|
||||||
|
* ELF loader
|
||||||
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cpu.h>
|
#include <cache.h>
|
||||||
#include <libelf.h>
|
#include <libelf.h>
|
||||||
|
#include <byteorder.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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* elf_check_file tests if the file at file_addr is
|
* elf_check_file tests if the file at file_addr is
|
||||||
|
@ -185,7 +38,7 @@ elf_check_file(unsigned long *file_addr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* endian check */
|
/* endian check */
|
||||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
#ifdef __BIG_ENDIAN__
|
||||||
if (ehdr->ei_data != 2)
|
if (ehdr->ei_data != 2)
|
||||||
/* not a big endian image */
|
/* not a big endian image */
|
||||||
#else
|
#else
|
||||||
|
@ -194,8 +47,9 @@ elf_check_file(unsigned long *file_addr)
|
||||||
#endif
|
#endif
|
||||||
return -2;
|
return -2;
|
||||||
|
|
||||||
/* check if it is an ELF executable */
|
/* check if it is an ELF executable ... and also
|
||||||
if (ehdr->e_type != 2)
|
* allow DYN files, since this is specified by ePAPR */
|
||||||
|
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
|
||||||
return -3;
|
return -3;
|
||||||
|
|
||||||
/* check if it is a PPC ELF executable */
|
/* 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 file_addr pointer to the start of the elf file
|
||||||
* @param entry pointer where the ELF loader will store
|
* @param entry pointer where the ELF loader will store
|
||||||
* the entry point
|
* 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
|
* @return 1 for a 32 bit file
|
||||||
* 2 for a 64 bit file
|
* 2 for a 64 bit file
|
||||||
* anything else means an error during load
|
* anything else means an error during load
|
||||||
*/
|
*/
|
||||||
int
|
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);
|
int type = elf_check_file(file_addr);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 1:
|
case 1:
|
||||||
*entry = load_segments(file_addr);
|
*entry = elf_load_segments32(file_addr, 0, pre_load, post_load);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
*entry = load_segments64(file_addr);
|
*entry = elf_load_segments64(file_addr, 0, pre_load, post_load);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (c) 2004, 2008 IBM Corporation
|
* Copyright (c) 2004, 2011 IBM Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
* This program and the accompanying materials
|
* This program and the accompanying materials
|
||||||
* are made available under the terms of the BSD License
|
* are made available under the terms of the BSD License
|
||||||
|
@ -9,13 +9,35 @@
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* IBM Corporation - initial implementation
|
* 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;
|
void *file_addr = TOS.a;
|
||||||
int type;
|
int type;
|
||||||
unsigned long entry;
|
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;
|
TOS.u = entry;
|
||||||
PUSH; TOS.n = type;
|
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
|
MIRP
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (c) 2004, 2008 IBM Corporation
|
* Copyright (c) 2004, 2011 IBM Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
* This program and the accompanying materials
|
* This program and the accompanying materials
|
||||||
* are made available under the terms of the BSD License
|
* are made available under the terms of the BSD License
|
||||||
|
@ -9,4 +9,10 @@
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* IBM Corporation - initial implementation
|
* IBM Corporation - initial implementation
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
cod(LOADELF)
|
|
||||||
|
/*
|
||||||
|
* libelf bindings for Forth - definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
cod(ELF-LOAD-FILE)
|
||||||
|
cod(ELF-LOAD-FILE-TO-ADDR)
|
||||||
|
|
|
@ -32,7 +32,7 @@ CFLAGS = -DTARG=$(TARG) -static -Wall -W -std=gnu99 \
|
||||||
-fno-stack-protector
|
-fno-stack-protector
|
||||||
ASFLAGS = -Wa,-mpower4 -Wa,-mregnames $(FLAG) $(CPUARCHDEF)
|
ASFLAGS = -Wa,-mpower4 -Wa,-mregnames $(FLAG) $(CPUARCHDEF)
|
||||||
|
|
||||||
LDFLAGS += -static -nostdlib
|
LDFLAGS += -static -nostdlib -Wl,-q,-n
|
||||||
|
|
||||||
ifneq ($(TARG),unix)
|
ifneq ($(TARG),unix)
|
||||||
CFLAGS += -nostdinc -fno-builtin
|
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 $@
|
$(LLFWBRDDIR)/io_generic_lib.o $(LDFLAGS) $(SLOF_LIBS) -o $@
|
||||||
#save a copy of paflof before stripping
|
#save a copy of paflof before stripping
|
||||||
@cp $@ $@.unstripped
|
@cp $@ $@.unstripped
|
||||||
$(STRIP) -s $@
|
$(STRIP) --strip-unneeded $@
|
||||||
|
|
||||||
paflof.o: board.code dict.xt
|
paflof.o: board.code dict.xt
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/paflof.c
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/paflof.c
|
||||||
|
|
Loading…
Reference in New Issue