Implement cross-endian ELF load for powerpc
This commit is contained in:
parent
9e5f70174e
commit
bf3df4070f
2 changed files with 105 additions and 2 deletions
|
@ -28,6 +28,23 @@
|
|||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#if defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)
|
||||
#define GRUB_ELF_ENABLE_BI_ENDIAN 1
|
||||
#else
|
||||
#define GRUB_ELF_ENABLE_BI_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if defined(GRUB_CPU_WORDS_BIGENDIAN)
|
||||
#define GRUB_ELF_NATIVE_ENDIANNESS ELFDATA2MSB
|
||||
#define GRUB_ELF_OPPOSITE_ENDIANNESS ELFDATA2LSB
|
||||
#else
|
||||
#define GRUB_ELF_NATIVE_ENDIANNESS ELFDATA2LSB
|
||||
#define GRUB_ELF_OPPOSITE_ENDIANNESS ELFDATA2MSB
|
||||
#endif
|
||||
|
||||
static int grub_elf32_check_endianess_and_bswap_ehdr (grub_elf_t elf);
|
||||
static int grub_elf64_check_endianess_and_bswap_ehdr (grub_elf_t elf);
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
static grub_err_t
|
||||
grub_elf_check_header (grub_elf_t elf)
|
||||
|
@ -38,8 +55,25 @@ grub_elf_check_header (grub_elf_t elf)
|
|||
|| e->e_ident[EI_MAG1] != ELFMAG1
|
||||
|| e->e_ident[EI_MAG2] != ELFMAG2
|
||||
|| e->e_ident[EI_MAG3] != ELFMAG3
|
||||
|| e->e_ident[EI_VERSION] != EV_CURRENT
|
||||
|| e->e_version != EV_CURRENT)
|
||||
|| e->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
|
||||
|
||||
if (grub_elf_is_elf32 (elf))
|
||||
{
|
||||
if (!grub_elf32_check_endianess_and_bswap_ehdr (elf)) {
|
||||
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF endianness magic");
|
||||
}
|
||||
}
|
||||
else if (grub_elf_is_elf64 (elf))
|
||||
{
|
||||
if (!grub_elf64_check_endianess_and_bswap_ehdr (elf)) {
|
||||
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF endianness magic");
|
||||
}
|
||||
}
|
||||
else
|
||||
return grub_error (GRUB_ERR_BAD_OS, "unknown ELF class");
|
||||
|
||||
if (e->e_version != EV_CURRENT)
|
||||
return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
@ -117,6 +151,9 @@ grub_elf_open (const char *name)
|
|||
}
|
||||
|
||||
|
||||
#define grub_swap_bytes_halfXX grub_swap_bytes16
|
||||
#define grub_swap_bytes_wordXX grub_swap_bytes32
|
||||
|
||||
/* 32-bit */
|
||||
#define ehdrXX ehdr32
|
||||
#define ELFCLASSXX ELFCLASS32
|
||||
|
@ -127,7 +164,12 @@ grub_elf_open (const char *name)
|
|||
#define grub_elf_is_elfXX grub_elf_is_elf32
|
||||
#define grub_elfXX_load_phdrs grub_elf32_load_phdrs
|
||||
#define ElfXX_Phdr Elf32_Phdr
|
||||
#define ElfXX_Ehdr Elf32_Ehdr
|
||||
#define grub_uintXX_t grub_uint32_t
|
||||
#define grub_swap_bytes_addrXX grub_swap_bytes32
|
||||
#define grub_swap_bytes_offXX grub_swap_bytes32
|
||||
#define grub_swap_bytes_XwordXX grub_swap_bytes32
|
||||
#define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr
|
||||
|
||||
#include "elfXX.c"
|
||||
|
||||
|
@ -140,7 +182,12 @@ grub_elf_open (const char *name)
|
|||
#undef grub_elf_is_elfXX
|
||||
#undef grub_elfXX_load_phdrs
|
||||
#undef ElfXX_Phdr
|
||||
#undef ElfXX_Ehdr
|
||||
#undef grub_uintXX_t
|
||||
#undef grub_swap_bytes_addrXX
|
||||
#undef grub_swap_bytes_offXX
|
||||
#undef grub_swap_bytes_XwordXX
|
||||
#undef grub_elfXX_check_endianess_and_bswap_ehdr
|
||||
|
||||
|
||||
/* 64-bit */
|
||||
|
@ -153,6 +200,11 @@ grub_elf_open (const char *name)
|
|||
#define grub_elf_is_elfXX grub_elf_is_elf64
|
||||
#define grub_elfXX_load_phdrs grub_elf64_load_phdrs
|
||||
#define ElfXX_Phdr Elf64_Phdr
|
||||
#define ElfXX_Ehdr Elf64_Ehdr
|
||||
#define grub_uintXX_t grub_uint64_t
|
||||
#define grub_swap_bytes_addrXX grub_swap_bytes64
|
||||
#define grub_swap_bytes_offXX grub_swap_bytes64
|
||||
#define grub_swap_bytes_XwordXX grub_swap_bytes64
|
||||
#define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr
|
||||
|
||||
#include "elfXX.c"
|
||||
|
|
|
@ -31,6 +31,25 @@ grub_elfXX_load_phdrs (grub_elf_t elf)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
#if GRUB_ELF_ENABLE_BI_ENDIAN
|
||||
if (elf->ehdr.ehdrXX.e_ident[EI_DATA] == GRUB_ELF_OPPOSITE_ENDIANNESS)
|
||||
{
|
||||
ElfXX_Phdr *phdr;
|
||||
for (phdr = elf->phdrs; (char *) phdr < (char *) elf->phdrs + phdrs_size;
|
||||
phdr = (ElfXX_Phdr *) ((char *) phdr + elf->ehdr.ehdrXX.e_phentsize))
|
||||
{
|
||||
phdr->p_type = grub_swap_bytes_wordXX (phdr->p_type);
|
||||
phdr->p_flags = grub_swap_bytes_wordXX (phdr->p_flags);
|
||||
phdr->p_offset = grub_swap_bytes_offXX (phdr->p_offset);
|
||||
phdr->p_vaddr = grub_swap_bytes_addrXX (phdr->p_vaddr);
|
||||
phdr->p_paddr = grub_swap_bytes_addrXX (phdr->p_paddr);
|
||||
phdr->p_filesz = grub_swap_bytes_XwordXX (phdr->p_filesz);
|
||||
phdr->p_memsz = grub_swap_bytes_XwordXX (phdr->p_memsz);
|
||||
phdr->p_align = grub_swap_bytes_XwordXX (phdr->p_align);
|
||||
}
|
||||
}
|
||||
#endif /* GRUB_ELF_ENABLE_BI_ENDIAN */
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
@ -154,3 +173,35 @@ grub_elfXX_load (grub_elf_t elf, const char *filename,
|
|||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_elfXX_check_endianess_and_bswap_ehdr (grub_elf_t elf)
|
||||
{
|
||||
ElfXX_Ehdr *e = &(elf->ehdr.ehdrXX);
|
||||
if (e->e_ident[EI_DATA] == GRUB_ELF_NATIVE_ENDIANNESS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if GRUB_ELF_ENABLE_BI_ENDIAN
|
||||
if (e->e_ident[EI_DATA] == GRUB_ELF_OPPOSITE_ENDIANNESS)
|
||||
{
|
||||
e->e_type = grub_swap_bytes_halfXX (e->e_type);
|
||||
e->e_machine = grub_swap_bytes_halfXX (e->e_machine);
|
||||
e->e_version = grub_swap_bytes_wordXX (e->e_version);
|
||||
e->e_entry = grub_swap_bytes_addrXX (e->e_entry);
|
||||
e->e_phoff = grub_swap_bytes_offXX (e->e_phoff);
|
||||
e->e_shoff = grub_swap_bytes_offXX (e->e_shoff);
|
||||
e->e_flags = grub_swap_bytes_wordXX (e->e_flags);
|
||||
e->e_ehsize = grub_swap_bytes_halfXX (e->e_ehsize);
|
||||
e->e_phentsize = grub_swap_bytes_halfXX (e->e_phentsize);
|
||||
e->e_phnum = grub_swap_bytes_halfXX (e->e_phnum);
|
||||
e->e_shentsize = grub_swap_bytes_halfXX (e->e_shentsize);
|
||||
e->e_shnum = grub_swap_bytes_halfXX (e->e_shnum);
|
||||
e->e_shstrndx = grub_swap_bytes_halfXX (e->e_shstrndx);
|
||||
return 1;
|
||||
}
|
||||
#endif /* GRUB_ELF_ENABLE_BI_ENDIAN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue