@@ -183,11 +183,15 @@ static bool try_load_elf64(struct elf_hdr *header)
return false;
}
- /* For the normal big-endian ELF ABI, the kernel entry points
- * to a function descriptor in the data section. Linux instead
- * has it point directly to code. Test whether it is pointing
+ /* On big-endian, typically ELF ABIv1 is used. With ELF ABIv1,
+ * the kernel entry points to a function descriptor in the
+ * data section. Linux instead has it point directly to code,
+ * which is ELF ABIv2 behaviour.
+ *
+ * If the ELF ABIv1 flag is set, test whether it is pointing
* into an executable section or not to figure this out. Default
- * to assuming it obeys the ABI.
+ * to assuming it obeys the ABI version set in its flags. If no
+ * ABI version is set, default to ELF ABIv2 behaviour.
*/
sh = (struct elf64_shdr *)(load_base + kh->e_shoff);
for (i = 0; i < kh->e_shnum; i++, sh++) {
@@ -196,7 +200,8 @@ static bool try_load_elf64(struct elf_hdr *header)
break;
}
- if (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X)) {
+ if ((kh->e_flags & EF_ELF_ABI_V1) &&
+ (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X))) {
kernel_entry = *(uint64_t *)(kernel_entry + load_base);
kernel_entry = kernel_entry - ph->p_vaddr + ph->p_offset;
}
@@ -39,6 +39,8 @@ struct elf64_hdr {
uint64_t e_phoff;
uint64_t e_shoff;
uint32_t e_flags;
+#define EF_ELF_ABI_V1 0x1
+#define EF_ELF_ABI_V2 0x2
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
On big-endian, ELF ABIv1 is typically used. For ELF ABIv1, the entry point is a function description. However, for ELF ABIv2 the entry points directly at code. The big-endian loader assumes this behaviour regardless of what ELF ABI version is set in the elf's flags. This can result in entering at the wrong locations for non ABIv1 elfs. Add a check for the ELF ABI version before assuming ABIv1 behaviour. If no version is set, default to ELF ABIv2 behaviour - that is the entry points directly to code. Signed-off-by: Jordan Niethe <jniethe5@gmail.com> --- core/init.c | 15 ++++++++++----- include/elf.h | 2 ++ 2 files changed, 12 insertions(+), 5 deletions(-)