From a553e95d858fc08a9e923f7a87fe28780370fbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Fri, 4 May 2018 21:06:23 +0200 Subject: [PATCH] kernel: support elf32 on x86_64. * define ELF32_COMPAT to enable ELF32 macros. * add a flag ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE to only check the format. It will be used by load_image_internal() to check which mode to use when loading an image. * in arch_elf_relocate_rel(), switch to elf_addr instead of addr_t, which would be the wrong size for elf32 on x86_64. * the ELF compat loader reuses the relevant parts of elf.cpp and arch_elf.cpp, excluding for instance load_kernel_add_on() or dump functions. Change-Id: Ifa47334e5adefd45405a823a3accbd12eee5b116 --- headers/private/kernel/elf.h | 9 +++- headers/private/kernel/elf_priv.h | 4 +- headers/private/system/arch/x86_64/arch_elf.h | 2 +- headers/private/system/elf_private.h | 7 +-- src/system/kernel/arch/x86/arch_elf.cpp | 29 +++++++------ .../kernel/arch/x86/arch_elf_compat.cpp | 18 ++++++++ src/system/kernel/elf.cpp | 43 ++++++++++++++++--- src/system/kernel/elf_compat.cpp | 26 +++++++++++ 8 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 src/system/kernel/arch/x86/arch_elf_compat.cpp create mode 100644 src/system/kernel/elf_compat.cpp diff --git a/headers/private/kernel/elf.h b/headers/private/kernel/elf.h index 0ce5efb89d..abb1352220 100644 --- a/headers/private/kernel/elf.h +++ b/headers/private/kernel/elf.h @@ -1,5 +1,5 @@ /* - * Copyright 2005, Haiku Inc. All Rights Reserved. + * Copyright 2005-2018 Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -27,8 +27,13 @@ struct elf_symbol_info { extern "C" { #endif -status_t elf_load_user_image(const char *path, Team *team, int flags, +status_t elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *_entry); +#ifdef _COMPAT_MODE +#define ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE 0x1 +status_t elf32_load_user_image(const char *path, Team *team, uint32 flags, + addr_t *_entry); +#endif // these two might get public one day: image_id load_kernel_add_on(const char *path); diff --git a/headers/private/kernel/elf_priv.h b/headers/private/kernel/elf_priv.h index 69e675f191..50153b85f0 100644 --- a/headers/private/kernel/elf_priv.h +++ b/headers/private/kernel/elf_priv.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007, Haiku Inc. All Rights Reserved. + * Copyright 2002-2018, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -81,7 +81,7 @@ extern "C" { extern status_t elf_resolve_symbol(struct elf_image_info* image, elf_sym* symbol, struct elf_image_info* sharedImage, - addr_t* _symbolAddress); + elf_addr* _symbolAddress); #ifdef __cplusplus } diff --git a/headers/private/system/arch/x86_64/arch_elf.h b/headers/private/system/arch/x86_64/arch_elf.h index 6bbba4e5b3..b75648df16 100644 --- a/headers/private/system/arch/x86_64/arch_elf.h +++ b/headers/private/system/arch/x86_64/arch_elf.h @@ -47,7 +47,7 @@ #define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base. */ -#ifdef _BOOT_MODE +#if defined(_BOOT_MODE) || defined(ELF32_COMPAT) # include "../x86/arch_elf.h" #endif diff --git a/headers/private/system/elf_private.h b/headers/private/system/elf_private.h index 78da6ffcd4..3cb4cfdaa5 100644 --- a/headers/private/system/elf_private.h +++ b/headers/private/system/elf_private.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 Haiku, Inc. All rights reserved. + * Copyright 2002-2018 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001 Travis Geiselbrecht. All rights reserved. @@ -18,7 +18,7 @@ // Determine the correct ELF types to use for the architecture -#if B_HAIKU_64_BIT +#if defined(B_HAIKU_64_BIT) && !defined(ELF32_COMPAT) # define _ELF_TYPE(type) Elf64_##type #else # define _ELF_TYPE(type) Elf32_##type @@ -26,6 +26,7 @@ #define DEFINE_ELF_TYPE(type, name) \ typedef _ELF_TYPE(type) name +DEFINE_ELF_TYPE(Addr, elf_addr); DEFINE_ELF_TYPE(Ehdr, elf_ehdr); DEFINE_ELF_TYPE(Phdr, elf_phdr); DEFINE_ELF_TYPE(Shdr, elf_shdr); @@ -48,7 +49,7 @@ DEFINE_ELF_TYPE(Note_Thread_Entry, elf_note_thread_entry); typedef uint16 elf_versym; -#if B_HAIKU_64_BIT +#if defined(B_HAIKU_64_BIT) && !defined(ELF32_COMPAT) # define ELF_CLASS ELFCLASS64 #else # define ELF_CLASS ELFCLASS32 diff --git a/src/system/kernel/arch/x86/arch_elf.cpp b/src/system/kernel/arch/x86/arch_elf.cpp index 204eb522ac..f785e20645 100644 --- a/src/system/kernel/arch/x86/arch_elf.cpp +++ b/src/system/kernel/arch/x86/arch_elf.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2004-2008, Haiku Inc. All Rights Reserved. + * Copyright 2004-2018, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Copyright 2002, Travis Geiselbrecht. All rights reserved. @@ -37,7 +37,8 @@ is_in_image(struct elf_image_info *image, addr_t address) #endif // !_BOOT_MODE -#if !defined(__x86_64__) || (defined(_BOOT_MODE) && _BOOT_PLATFORM != efi) +#if !defined(__x86_64__) || defined(ELF32_COMPAT) \ + || (defined(_BOOT_MODE) && _BOOT_PLATFORM != efi) #ifdef TRACE_ARCH_ELF @@ -67,11 +68,11 @@ arch_elf_relocate_rel(struct elf_image_info *image, struct elf_image_info *resolveImage, Elf32_Rel *rel, int relLength) #endif { - addr_t S; - addr_t A; - addr_t P; - addr_t finalAddress; - addr_t *resolveAddress; + elf_addr S; + uint32 A; + uint32 P; + uint32 finalAddress; + uint32 *resolveAddress; int i; S = A = P = 0; @@ -112,7 +113,7 @@ arch_elf_relocate_rel(struct elf_image_info *image, case R_386_RELATIVE: case R_386_GOTOFF: case R_386_GOTPC: - A = *(addr_t *)(image->text_region.delta + rel[i].r_offset); + A = *(uint32 *)(image->text_region.delta + rel[i].r_offset); TRACE(("A %p\n", (void *)A)); break; } @@ -151,7 +152,7 @@ arch_elf_relocate_rel(struct elf_image_info *image, return B_BAD_DATA; } - resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset); + resolveAddress = (uint32 *)(image->text_region.delta + rel[i].r_offset); #ifndef _BOOT_MODE if (!is_in_image(image, (addr_t)resolveAddress)) { dprintf("arch_elf_relocate_rel: invalid offset %#lx\n", @@ -160,8 +161,8 @@ arch_elf_relocate_rel(struct elf_image_info *image, } #endif *resolveAddress = finalAddress; - TRACE(("-> offset %#lx = %#lx\n", - (image->text_region.delta + rel[i].r_offset), finalAddress)); + TRACE(("-> offset %#lx (%#lx) = %#lx\n", + (image->text_region.delta + rel[i].r_offset), rel[i].r_offset, finalAddress)); } return B_NO_ERROR; @@ -183,10 +184,10 @@ arch_elf_relocate_rela(struct elf_image_info *image, } -#endif // !__x86_64__ || (_BOOT_MODE && _BOOT_PLATFORM != efi) +#endif // !__x86_64__ || defined(ELF32_COMPAT) || (_BOOT_MODE && _BOOT_PLATFORM != efi) -#if defined(__x86_64__) || defined(_BOOT_MODE) +#if (defined(__x86_64__) && !defined(ELF32_COMPAT)) || defined(_BOOT_MODE) #ifdef _BOOT_MODE @@ -276,4 +277,4 @@ arch_elf_relocate_rela(struct elf_image_info *image, } -#endif // __x86_64__ || _BOOT_MODE +#endif // (defined(__x86_64__) && !defined(ELF32_COMPAT)) || defined(_BOOT_MODE) diff --git a/src/system/kernel/arch/x86/arch_elf_compat.cpp b/src/system/kernel/arch/x86/arch_elf_compat.cpp new file mode 100644 index 0000000000..87746e3163 --- /dev/null +++ b/src/system/kernel/arch/x86/arch_elf_compat.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + +/*! Contains the ELF compat loader */ + + +//#define TRACE_ARCH_ELF +#define ELF32_COMPAT 1 + + +#define arch_elf_relocate_rel arch_elf32_relocate_rel +#define arch_elf_relocate_rela arch_elf32_relocate_rela +#define elf_resolve_symbol elf32_resolve_symbol + + +#include "arch_elf.cpp" diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index cb4fbce472..6aa29c8fda 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -83,6 +83,8 @@ typedef BOpenHashTable ImageHash; } // namespace +#ifndef ELF32_COMPAT + static ImageHash *sImagesHash; static struct elf_image_info *sKernelImage = NULL; @@ -253,6 +255,9 @@ find_image_by_vnode(void *vnode) } +#endif // ELF32_COMPAT + + static struct elf_image_info * create_image_struct() { @@ -340,6 +345,9 @@ get_symbol_bind_string(elf_sym *symbol) } +#ifndef ELF32_COMPAT + + /*! Searches a symbol (pattern) in all kernel images */ static int dump_symbol(int argc, char **argv) @@ -571,8 +579,7 @@ dump_image(int argc, char **argv) // Currently unused -#if 0 -static +/*static void dump_symbol(struct elf_image_info *image, elf_sym *sym) { @@ -585,7 +592,10 @@ void dump_symbol(struct elf_image_info *image, elf_sym *sym) kprintf(" st_other 0x%x\n", sym->st_other); kprintf(" st_shndx %d\n", sym->st_shndx); } -#endif +*/ + + +#endif // ELF32_COMPAT static elf_sym * @@ -800,6 +810,9 @@ elf_parse_dynamic_section(struct elf_image_info *image) } +#ifndef ELF32_COMPAT + + static status_t assert_defined_image_version(elf_image_info* dependentImage, elf_image_info* image, const elf_version_info& neededVersion, bool weak) @@ -980,12 +993,15 @@ check_needed_image_versions(elf_image_info* image) } +#endif // ELF32_COMPAT + + /*! Resolves the \a symbol by linking against \a sharedImage if necessary. Returns the resolved symbol's address in \a _symbolAddress. */ status_t elf_resolve_symbol(struct elf_image_info *image, elf_sym *symbol, - struct elf_image_info *sharedImage, addr_t *_symbolAddress) + struct elf_image_info *sharedImage, elf_addr *_symbolAddress) { // Local symbols references are always resolved to the given symbol. if (symbol->Bind() == STB_LOCAL) { @@ -1124,6 +1140,9 @@ verify_eheader(elf_ehdr *elfHeader) } +#ifndef ELF32_COMPAT + + static void unload_elf_image(struct elf_image_info *image) { @@ -1803,8 +1822,11 @@ elf_lookup_kernel_symbol(const char* name, elf_symbol_info* info) } +#endif // ELF32_COMPAT + + status_t -elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) +elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry) { elf_ehdr elfHeader; elf_phdr *programHeaders = NULL; @@ -1845,6 +1867,11 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) if (status < B_OK) goto error; +#ifdef ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE + if ((flags & ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE) != 0) + return B_OK; +#endif + struct elf_image_info* image; image = create_image_struct(); if (image == NULL) { @@ -2088,6 +2115,7 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) status = B_OK; error2: + clear_ac(); free(mappedAreas); image->elf_header = NULL; @@ -2101,6 +2129,8 @@ error: } +#ifndef ELF32_COMPAT + image_id load_kernel_add_on(const char *path) { @@ -2750,3 +2780,6 @@ _user_read_kernel_image_symbols(image_id id, elf_sym* symbolTable, return elf_read_kernel_image_symbols(id, symbolTable, _symbolCount, stringTable, _stringTableSize, _imageDelta, false); } + +#endif // ELF32_COMPAT + diff --git a/src/system/kernel/elf_compat.cpp b/src/system/kernel/elf_compat.cpp new file mode 100644 index 0000000000..db81053006 --- /dev/null +++ b/src/system/kernel/elf_compat.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + +/*! Contains the ELF compat loader */ + + +//#define TRACE_ELF +#define ELF32_COMPAT 1 + + +#include + + +#define elf_load_user_image elf32_load_user_image +#define elf_resolve_symbol elf32_resolve_symbol +#define elf_find_symbol elf32_find_symbol +#define elf_parse_dynamic_section elf32_parse_dynamic_section +#define elf_relocate elf32_relocate + +#define arch_elf_relocate_rel arch_elf32_relocate_rel +#define arch_elf_relocate_rela arch_elf32_relocate_rela + + +#include "elf.cpp"