[Skiboot] [PATCH v5 06/27] elf: endian conversions
Nicholas Piggin
npiggin at gmail.com
Tue Oct 15 14:06:56 AEDT 2019
Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
core/flash.c | 36 +++++---
core/init.c | 92 ++++++++++---------
include/elf.h | 235 +++++++++++++++++++++++++++++++++---------------
include/stack.h | 4 +
4 files changed, 244 insertions(+), 123 deletions(-)
diff --git a/core/flash.c b/core/flash.c
index 7fbfca22b..5fc3f3946 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -520,24 +520,38 @@ const char *flash_map_resource_name(enum resource_id id)
static size_t sizeof_elf_from_hdr(void *buf)
{
- struct elf_hdr *elf = (struct elf_hdr*) buf;
+ struct elf_hdr *elf = (struct elf_hdr *)buf;
size_t sz = 0;
BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf_hdr));
- BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf64_hdr));
- BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf32_hdr));
+ BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf64be_hdr));
+ BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf32be_hdr));
if (elf->ei_ident == ELF_IDENT) {
if (elf->ei_class == ELF_CLASS_64) {
- struct elf64_hdr *elf64 = (struct elf64_hdr*) buf;
- sz = le64_to_cpu(elf64->e_shoff) +
- ((uint32_t)le16_to_cpu(elf64->e_shentsize) *
- (uint32_t)le16_to_cpu(elf64->e_shnum));
+ if (elf->ei_data == ELF_DATA_LSB) {
+ struct elf64le_hdr *kh = (struct elf64le_hdr *)buf;
+ sz = le64_to_cpu(kh->e_shoff) +
+ ((uint32_t)le16_to_cpu(kh->e_shentsize) *
+ (uint32_t)le16_to_cpu(kh->e_shnum));
+ } else {
+ struct elf64be_hdr *kh = (struct elf64be_hdr *)buf;
+ sz = be64_to_cpu(kh->e_shoff) +
+ ((uint32_t)be16_to_cpu(kh->e_shentsize) *
+ (uint32_t)be16_to_cpu(kh->e_shnum));
+ }
} else if (elf->ei_class == ELF_CLASS_32) {
- struct elf32_hdr *elf32 = (struct elf32_hdr*) buf;
- sz = le32_to_cpu(elf32->e_shoff) +
- (le16_to_cpu(elf32->e_shentsize) *
- le16_to_cpu(elf32->e_shnum));
+ if (elf->ei_data == ELF_DATA_LSB) {
+ struct elf32le_hdr *kh = (struct elf32le_hdr *)buf;
+ sz = le32_to_cpu(kh->e_shoff) +
+ (le16_to_cpu(kh->e_shentsize) *
+ le16_to_cpu(kh->e_shnum));
+ } else {
+ struct elf32be_hdr *kh = (struct elf32be_hdr *)buf;
+ sz = be32_to_cpu(kh->e_shoff) +
+ (be16_to_cpu(kh->e_shentsize) *
+ be16_to_cpu(kh->e_shnum));
+ }
}
}
diff --git a/core/init.c b/core/init.c
index 62d9c709f..67185c9e1 100644
--- a/core/init.c
+++ b/core/init.c
@@ -87,9 +87,9 @@ struct debug_descriptor debug_descriptor = {
static bool try_load_elf64_le(struct elf_hdr *header)
{
- struct elf64_hdr *kh = (struct elf64_hdr *)header;
+ struct elf64le_hdr *kh = (struct elf64le_hdr *)header;
uint64_t load_base = (uint64_t)kh;
- struct elf64_phdr *ph;
+ struct elf64le_phdr *ph;
unsigned int i;
printf("INIT: 64-bit LE kernel discovered\n");
@@ -101,7 +101,7 @@ static bool try_load_elf64_le(struct elf_hdr *header)
* to work for the Linux Kernel because it's a fairly dumb ELF
* but it will not work for any ELF binary.
*/
- ph = (struct elf64_phdr *)(load_base + le64_to_cpu(kh->e_phoff));
+ ph = (struct elf64le_phdr *)(load_base + le64_to_cpu(kh->e_phoff));
for (i = 0; i < le16_to_cpu(kh->e_phnum); i++, ph++) {
if (le32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD)
continue;
@@ -135,23 +135,24 @@ static bool try_load_elf64_le(struct elf_hdr *header)
static bool try_load_elf64(struct elf_hdr *header)
{
- struct elf64_hdr *kh = (struct elf64_hdr *)header;
+ struct elf64be_hdr *kh = (struct elf64be_hdr *)header;
+ struct elf64le_hdr *khle = (struct elf64le_hdr *)header;
uint64_t load_base = (uint64_t)kh;
- struct elf64_phdr *ph;
- struct elf64_shdr *sh;
+ struct elf64be_phdr *ph;
+ struct elf64be_shdr *sh;
unsigned int i;
/* Check it's a ppc64 LE ELF */
- if (kh->ei_ident == ELF_IDENT &&
- kh->ei_data == ELF_DATA_LSB &&
- kh->e_machine == le16_to_cpu(ELF_MACH_PPC64)) {
+ if (khle->ei_ident == ELF_IDENT &&
+ khle->ei_data == ELF_DATA_LSB &&
+ le16_to_cpu(khle->e_machine) == ELF_MACH_PPC64) {
return try_load_elf64_le(header);
}
/* Check it's a ppc64 ELF */
if (kh->ei_ident != ELF_IDENT ||
kh->ei_data != ELF_DATA_MSB ||
- kh->e_machine != ELF_MACH_PPC64) {
+ be16_to_cpu(kh->e_machine) != ELF_MACH_PPC64) {
prerror("INIT: Kernel doesn't look like an ppc64 ELF\n");
return false;
}
@@ -163,16 +164,18 @@ static bool try_load_elf64(struct elf_hdr *header)
* to work for the Linux Kernel because it's a fairly dumb ELF
* but it will not work for any ELF binary.
*/
- ph = (struct elf64_phdr *)(load_base + kh->e_phoff);
- for (i = 0; i < kh->e_phnum; i++, ph++) {
- if (ph->p_type != ELF_PTYPE_LOAD)
+ ph = (struct elf64be_phdr *)(load_base + be64_to_cpu(kh->e_phoff));
+ for (i = 0; i < be16_to_cpu(kh->e_phnum); i++, ph++) {
+ if (be32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD)
continue;
- if (ph->p_vaddr > kh->e_entry ||
- (ph->p_vaddr + ph->p_memsz) < kh->e_entry)
+ if (be64_to_cpu(ph->p_vaddr) > be64_to_cpu(kh->e_entry) ||
+ (be64_to_cpu(ph->p_vaddr) + be64_to_cpu(ph->p_memsz)) <
+ be64_to_cpu(kh->e_entry))
continue;
/* Get our entry */
- kernel_entry = kh->e_entry - ph->p_vaddr + ph->p_offset;
+ kernel_entry = be64_to_cpu(kh->e_entry) -
+ be64_to_cpu(ph->p_vaddr) + be64_to_cpu(ph->p_offset);
break;
}
@@ -187,23 +190,27 @@ static bool try_load_elf64(struct elf_hdr *header)
* into an executable section or not to figure this out. Default
* to assuming it obeys the ABI.
*/
- sh = (struct elf64_shdr *)(load_base + kh->e_shoff);
- for (i = 0; i < kh->e_shnum; i++, sh++) {
- if (sh->sh_addr <= kh->e_entry &&
- (sh->sh_addr + sh->sh_size) > kh->e_entry)
+ sh = (struct elf64be_shdr *)(load_base + be64_to_cpu(kh->e_shoff));
+ for (i = 0; i < be16_to_cpu(kh->e_shnum); i++, sh++) {
+ if (be64_to_cpu(sh->sh_addr) <= be64_to_cpu(kh->e_entry) &&
+ (be64_to_cpu(sh->sh_addr) + be64_to_cpu(sh->sh_size)) >
+ be64_to_cpu(kh->e_entry))
break;
}
- if (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X)) {
+ if (i == be16_to_cpu(kh->e_shnum) ||
+ !(be64_to_cpu(sh->sh_flags) & ELF_SFLAGS_X)) {
kernel_entry = *(uint64_t *)(kernel_entry + load_base);
- kernel_entry = kernel_entry - ph->p_vaddr + ph->p_offset;
+ kernel_entry = kernel_entry -
+ be64_to_cpu(ph->p_vaddr) + be64_to_cpu(ph->p_offset);
}
kernel_entry += load_base;
kernel_32bit = false;
- kernel_size = kh->e_shoff +
- ((uint32_t)kh->e_shentsize * (uint32_t)kh->e_shnum);
+ kernel_size = be64_to_cpu(kh->e_shoff) +
+ ((uint32_t)be16_to_cpu(kh->e_shentsize) *
+ (uint32_t)be16_to_cpu(kh->e_shnum));
printf("INIT: 64-bit kernel entry at 0x%llx, size 0x%lx\n",
kernel_entry, kernel_size);
@@ -213,9 +220,9 @@ static bool try_load_elf64(struct elf_hdr *header)
static bool try_load_elf32_le(struct elf_hdr *header)
{
- struct elf32_hdr *kh = (struct elf32_hdr *)header;
+ struct elf32le_hdr *kh = (struct elf32le_hdr *)header;
uint64_t load_base = (uint64_t)kh;
- struct elf32_phdr *ph;
+ struct elf32le_phdr *ph;
unsigned int i;
printf("INIT: 32-bit LE kernel discovered\n");
@@ -227,7 +234,7 @@ static bool try_load_elf32_le(struct elf_hdr *header)
* to work for the Linux Kernel because it's a fairly dumb ELF
* but it will not work for any ELF binary.
*/
- ph = (struct elf32_phdr *)(load_base + le32_to_cpu(kh->e_phoff));
+ ph = (struct elf32le_phdr *)(load_base + le32_to_cpu(kh->e_phoff));
for (i = 0; i < le16_to_cpu(kh->e_phnum); i++, ph++) {
if (le32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD)
continue;
@@ -257,22 +264,23 @@ static bool try_load_elf32_le(struct elf_hdr *header)
static bool try_load_elf32(struct elf_hdr *header)
{
- struct elf32_hdr *kh = (struct elf32_hdr *)header;
+ struct elf32be_hdr *kh = (struct elf32be_hdr *)header;
+ struct elf32le_hdr *khle = (struct elf32le_hdr *)header;
uint64_t load_base = (uint64_t)kh;
- struct elf32_phdr *ph;
+ struct elf32be_phdr *ph;
unsigned int i;
/* Check it's a ppc32 LE ELF */
- if (header->ei_ident == ELF_IDENT &&
- header->ei_data == ELF_DATA_LSB &&
- header->e_machine == le16_to_cpu(ELF_MACH_PPC32)) {
+ if (khle->ei_ident == ELF_IDENT &&
+ khle->ei_data == ELF_DATA_LSB &&
+ le16_to_cpu(khle->e_machine) == ELF_MACH_PPC32) {
return try_load_elf32_le(header);
}
/* Check it's a ppc32 ELF */
- if (header->ei_ident != ELF_IDENT ||
- header->ei_data != ELF_DATA_MSB ||
- header->e_machine != ELF_MACH_PPC32) {
+ if (kh->ei_ident != ELF_IDENT ||
+ kh->ei_data != ELF_DATA_MSB ||
+ be16_to_cpu(kh->e_machine) != ELF_MACH_PPC32) {
prerror("INIT: Kernel doesn't look like an ppc32 ELF\n");
return false;
}
@@ -284,16 +292,18 @@ static bool try_load_elf32(struct elf_hdr *header)
* to work for the Linux Kernel because it's a fairly dumb ELF
* but it will not work for any ELF binary.
*/
- ph = (struct elf32_phdr *)(load_base + kh->e_phoff);
- for (i = 0; i < kh->e_phnum; i++, ph++) {
- if (ph->p_type != ELF_PTYPE_LOAD)
+ ph = (struct elf32be_phdr *)(load_base + be32_to_cpu(kh->e_phoff));
+ for (i = 0; i < be16_to_cpu(kh->e_phnum); i++, ph++) {
+ if (be32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD)
continue;
- if (ph->p_vaddr > kh->e_entry ||
- (ph->p_vaddr + ph->p_memsz) < kh->e_entry)
+ if (be32_to_cpu(ph->p_vaddr) > be32_to_cpu(kh->e_entry) ||
+ (be32_to_cpu(ph->p_vaddr) + be32_to_cpu(ph->p_memsz)) <
+ be32_to_cpu(kh->e_entry))
continue;
/* Get our entry */
- kernel_entry = kh->e_entry - ph->p_vaddr + ph->p_offset;
+ kernel_entry = be32_to_cpu(kh->e_entry) -
+ be32_to_cpu(ph->p_vaddr) + be32_to_cpu(ph->p_offset);
break;
}
diff --git a/include/elf.h b/include/elf.h
index 93524bb99..f3e071de1 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -5,11 +5,16 @@
#define __ELF_H
#include <stdint.h>
+#include <types.h>
/* Generic ELF header */
struct elf_hdr {
uint32_t ei_ident;
+#if HAVE_BIG_ENDIAN
#define ELF_IDENT 0x7F454C46
+#else
+#define ELF_IDENT 0x464C457F
+#endif
uint8_t ei_class;
#define ELF_CLASS_32 1
#define ELF_CLASS_64 2
@@ -18,68 +23,190 @@ struct elf_hdr {
#define ELF_DATA_MSB 2
uint8_t ei_version;
uint8_t ei_pad[9];
- uint16_t e_type;
- uint16_t e_machine;
+};
+
#define ELF_MACH_PPC32 0x14
#define ELF_MACH_PPC64 0x15
- uint32_t e_version;
+
+/* 64-bit ELF header */
+struct elf64be_hdr {
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ __be16 e_type;
+ __be16 e_machine;
+ __be32 e_version;
+ __be64 e_entry;
+ __be64 e_phoff;
+ __be64 e_shoff;
+ __be32 e_flags;
+ __be16 e_ehsize;
+ __be16 e_phentsize;
+ __be16 e_phnum;
+ __be16 e_shentsize;
+ __be16 e_shnum;
+ __be16 e_shstrndx;
+};
+
+/* 64-bit ELF program header */
+struct elf64be_phdr {
+ __be32 p_type;
+#define ELF_PTYPE_LOAD 1
+ __be32 p_flags;
+#define ELF_PFLAGS_R 0x4
+#define ELF_PFLAGS_W 0x2
+#define ELF_PFLAGS_X 0x1
+ __be64 p_offset;
+ __be64 p_vaddr;
+ __be64 p_paddr;
+ __be64 p_filesz;
+ __be64 p_memsz;
+ __be64 p_align;
+};
+
+/* 64-bit ELF section header */
+struct elf64be_shdr {
+ __be32 sh_name;
+ __be32 sh_type;
+ __be64 sh_flags;
+#define ELF_SFLAGS_X 0x4
+#define ELF_SFLAGS_A 0x2
+#define ELF_SFLAGS_W 0x1
+ __be64 sh_addr;
+ __be64 sh_offset;
+ __be64 sh_size;
+ __be32 sh_link;
+ __be32 sh_info;
+ __be64 sh_addralign;
+ __be64 sh_entsize;
+};
+
+/* 32-bit ELF header */
+struct elf32be_hdr {
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ __be16 e_type;
+ __be16 e_machine;
+ __be32 e_version;
+ __be32 e_entry;
+ __be32 e_phoff;
+ __be32 e_shoff;
+ __be32 e_flags;
+ __be16 e_ehsize;
+ __be16 e_phentsize;
+ __be16 e_phnum;
+ __be16 e_shentsize;
+ __be16 e_shnum;
+ __be16 e_shstrndx;
+};
+
+/* 32-bit ELF program header*/
+struct elf32be_phdr {
+ __be32 p_type;
+ __be32 p_offset;
+ __be32 p_vaddr;
+ __be32 p_paddr;
+ __be32 p_filesz;
+ __be32 p_memsz;
+ __be32 p_flags;
+ __be32 p_align;
};
/* 64-bit ELF header */
-struct elf64_hdr {
+struct elf64le_hdr {
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;
+ __le16 e_type;
+ __le16 e_machine;
+ __le32 e_version;
+ __le64 e_entry;
+ __le64 e_phoff;
+ __le64 e_shoff;
+ __le32 e_flags;
+ __le16 e_ehsize;
+ __le16 e_phentsize;
+ __le16 e_phnum;
+ __le16 e_shentsize;
+ __le16 e_shnum;
+ __le16 e_shstrndx;
};
/* 64-bit ELF program header */
-struct elf64_phdr {
- uint32_t p_type;
+struct elf64le_phdr {
+ __le32 p_type;
#define ELF_PTYPE_LOAD 1
- uint32_t p_flags;
+ __le32 p_flags;
#define ELF_PFLAGS_R 0x4
#define ELF_PFLAGS_W 0x2
#define ELF_PFLAGS_X 0x1
- uint64_t p_offset;
- uint64_t p_vaddr;
- uint64_t p_paddr;
- uint64_t p_filesz;
- uint64_t p_memsz;
- uint64_t p_align;
+ __le64 p_offset;
+ __le64 p_vaddr;
+ __le64 p_paddr;
+ __le64 p_filesz;
+ __le64 p_memsz;
+ __le64 p_align;
};
/* 64-bit ELF section header */
-struct elf64_shdr {
- uint32_t sh_name;
- uint32_t sh_type;
- uint64_t sh_flags;
+struct elf64le_shdr {
+ __le32 sh_name;
+ __le32 sh_type;
+ __le64 sh_flags;
#define ELF_SFLAGS_X 0x4
#define ELF_SFLAGS_A 0x2
#define ELF_SFLAGS_W 0x1
- uint64_t sh_addr;
- uint64_t sh_offset;
- uint64_t sh_size;
- uint32_t sh_link;
- uint32_t sh_info;
- uint64_t sh_addralign;
- int64_t sh_entsize;
+ __le64 sh_addr;
+ __le64 sh_offset;
+ __le64 sh_size;
+ __le32 sh_link;
+ __le32 sh_info;
+ __le64 sh_addralign;
+ __le64 sh_entsize;
+};
+
+/* 32-bit ELF header */
+struct elf32le_hdr {
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ __le16 e_type;
+ __le16 e_machine;
+ __le32 e_version;
+ __le32 e_entry;
+ __le32 e_phoff;
+ __le32 e_shoff;
+ __le32 e_flags;
+ __le16 e_ehsize;
+ __le16 e_phentsize;
+ __le16 e_phnum;
+ __le16 e_shentsize;
+ __le16 e_shnum;
+ __le16 e_shstrndx;
+};
+
+/* 32-bit ELF program header*/
+struct elf32le_phdr {
+ __le32 p_type;
+ __le32 p_offset;
+ __le32 p_vaddr;
+ __le32 p_paddr;
+ __le32 p_filesz;
+ __le32 p_memsz;
+ __le32 p_flags;
+ __le32 p_align;
};
+
/* Some relocation related stuff used in relocate.c */
struct elf64_dyn {
int64_t d_tag;
@@ -101,39 +228,5 @@ struct elf64_rela {
/* relocs we support */
#define R_PPC64_RELATIVE 22
-/* 32-bit ELF header */
-struct elf32_hdr {
- 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;
-};
-
-/* 32-bit ELF program header*/
-struct elf32_phdr {
- 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;
-};
-
#endif /* __ELF_H */
diff --git a/include/stack.h b/include/stack.h
index 09d22adb6..b0d6df17d 100644
--- a/include/stack.h
+++ b/include/stack.h
@@ -11,7 +11,11 @@
#define STACK_ENTRY_RESET 0x0100 /* System reset */
#define STACK_ENTRY_SOFTPATCH 0x1500 /* Soft patch (denorm emulation) */
+#if HAVE_BIG_ENDIAN
#define STACK_TOC_OFFSET 40
+#else
+#define STACK_TOC_OFFSET 24
+#endif
/* Safety/ABI gap at top of stack */
#define STACK_TOP_GAP 0x100
--
2.23.0
More information about the Skiboot
mailing list