diff options
author | Anton Blanchard <anton@samba.org> | 2013-12-06 09:12:36 +1100 |
---|---|---|
committer | Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> | 2013-12-06 16:30:34 +0530 |
commit | 7d0c28432892bcd44478b1c72c4d4cb9ae42077a (patch) | |
tree | c309f5a16065b0a0c95d0a7d0182192a35f98e05 | |
parent | dad7598b1b53a3c9cd8a3c20300270d0d621a5f3 (diff) | |
download | SLOF-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.h | 7 | ||||
-rw-r--r-- | lib/libelf/elf.c | 21 | ||||
-rw-r--r-- | lib/libelf/elf32.c | 40 | ||||
-rw-r--r-- | lib/libelf/elf64.c | 40 |
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); + } +} |