aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2013-12-06 09:12:36 +1100
committerNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2013-12-06 16:30:34 +0530
commit7d0c28432892bcd44478b1c72c4d4cb9ae42077a (patch)
treec309f5a16065b0a0c95d0a7d0182192a35f98e05
parentdad7598b1b53a3c9cd8a3c20300270d0d621a5f3 (diff)
downloadSLOF-7d0c28432892bcd44478b1c72c4d4cb9ae42077a.zip
SLOF-7d0c28432892bcd44478b1c72c4d4cb9ae42077a.tar.gz
SLOF-7d0c28432892bcd44478b1c72c4d4cb9ae42077a.tar.bz2
Add support for loading little endian ELF binaries.
We byte swap the entire header in place in elf_check_file. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
-rw-r--r--include/libelf.h7
-rw-r--r--lib/libelf/elf.c21
-rw-r--r--lib/libelf/elf32.c40
-rw-r--r--lib/libelf/elf64.c40
4 files changed, 102 insertions, 6 deletions
diff --git a/include/libelf.h b/include/libelf.h
index 9446fcf..495d697 100644
--- a/include/libelf.h
+++ b/include/libelf.h
@@ -26,6 +26,10 @@
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
+/* ELF object endian */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+
/* Generic ELF header */
struct ehdr {
uint32_t ei_ident;
@@ -72,6 +76,9 @@ int elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry,
int (*pre_load)(void*, long),
void (*post_load)(void*, long));
+void elf_byteswap_header32(void *file_addr);
+void elf_byteswap_header64(void *file_addr);
+
unsigned int elf_load_segments32(void *file_addr, signed long offset,
int (*pre_load)(void*, long),
void (*post_load)(void*, long));
diff --git a/lib/libelf/elf.c b/lib/libelf/elf.c
index 33d9211..1340103 100644
--- a/lib/libelf/elf.c
+++ b/lib/libelf/elf.c
@@ -33,19 +33,28 @@ static int
elf_check_file(unsigned long *file_addr)
{
struct ehdr *ehdr = (struct ehdr *) file_addr;
+ uint8_t native_endian;
+
/* check if it is an ELF image at all */
if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
return -1;
- /* endian check */
#ifdef __BIG_ENDIAN__
- if (ehdr->ei_data != 2)
- /* not a big endian image */
+ native_endian = ELFDATA2MSB;
#else
- if (ehdr->ei_data == 2)
- /* not a little endian image */
+ native_endian = ELFDATA2LSB;
#endif
- return -2;
+
+ if (native_endian != ehdr->ei_data) {
+ switch (ehdr->ei_class) {
+ case 1:
+ elf_byteswap_header32(file_addr);
+ break;
+ case 2:
+ elf_byteswap_header64(file_addr);
+ break;
+ }
+ }
/* check if it is an ELF executable ... and also
* allow DYN files, since this is specified by ePAPR */
diff --git a/lib/libelf/elf32.c b/lib/libelf/elf32.c
index 840df5d..3f5f374 100644
--- a/lib/libelf/elf32.c
+++ b/lib/libelf/elf32.c
@@ -16,6 +16,7 @@
#include <string.h>
#include <libelf.h>
+#include <byteorder.h>
struct ehdr32 {
uint32_t ei_ident;
@@ -142,3 +143,42 @@ elf_get_base_addr32(void *file_addr)
return 0;
}
+
+void
+elf_byteswap_header32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ struct phdr32 *phdr;
+ int i;
+
+ bswap_16p(&ehdr->e_type);
+ bswap_16p(&ehdr->e_machine);
+ bswap_32p(&ehdr->e_version);
+ bswap_32p(&ehdr->e_entry);
+ bswap_32p(&ehdr->e_phoff);
+ bswap_32p(&ehdr->e_shoff);
+ bswap_32p(&ehdr->e_flags);
+ bswap_16p(&ehdr->e_ehsize);
+ bswap_16p(&ehdr->e_phentsize);
+ bswap_16p(&ehdr->e_phnum);
+ bswap_16p(&ehdr->e_shentsize);
+ bswap_16p(&ehdr->e_shnum);
+ bswap_16p(&ehdr->e_shstrndx);
+
+ phdr = get_phdr32(file_addr);
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ bswap_32p(&phdr->p_type);
+ bswap_32p(&phdr->p_offset);
+ bswap_32p(&phdr->p_vaddr);
+ bswap_32p(&phdr->p_paddr);
+ bswap_32p(&phdr->p_filesz);
+ bswap_32p(&phdr->p_memsz);
+ bswap_32p(&phdr->p_flags);
+ bswap_32p(&phdr->p_align);
+
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+}
diff --git a/lib/libelf/elf64.c b/lib/libelf/elf64.c
index 78b7697..faddbfb 100644
--- a/lib/libelf/elf64.c
+++ b/lib/libelf/elf64.c
@@ -19,6 +19,7 @@
#include <string.h>
#include <stdio.h>
#include <libelf.h>
+#include <byteorder.h>
struct ehdr64
{
@@ -422,3 +423,42 @@ elf_relocate64(void *file_addr, signed long offset)
}
}
}
+
+void
+elf_byteswap_header64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ struct phdr64 *phdr;
+ int i;
+
+ bswap_16p(&ehdr->e_type);
+ bswap_16p(&ehdr->e_machine);
+ bswap_32p(&ehdr->e_version);
+ bswap_64p(&ehdr->e_entry);
+ bswap_64p(&ehdr->e_phoff);
+ bswap_64p(&ehdr->e_shoff);
+ bswap_32p(&ehdr->e_flags);
+ bswap_16p(&ehdr->e_ehsize);
+ bswap_16p(&ehdr->e_phentsize);
+ bswap_16p(&ehdr->e_phnum);
+ bswap_16p(&ehdr->e_shentsize);
+ bswap_16p(&ehdr->e_shnum);
+ bswap_16p(&ehdr->e_shstrndx);
+
+ phdr = get_phdr64(file_addr);
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ bswap_32p(&phdr->p_type);
+ bswap_32p(&phdr->p_flags);
+ bswap_64p(&phdr->p_offset);
+ bswap_64p(&phdr->p_vaddr);
+ bswap_64p(&phdr->p_paddr);
+ bswap_64p(&phdr->p_filesz);
+ bswap_64p(&phdr->p_memsz);
+ bswap_64p(&phdr->p_align);
+
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+}