Currently to compile arm-uboot port for a different platform you need to relink it at new address with modifying source code. This set of patches changes to U-boot in-place loading and images that relocate themselves. I'd be interested in opinion of ARM guys
From 80f8cfe29ace49167c1ad6439ddd15519b0a5455 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko <phco...@gmail.com> Date: Thu, 18 Feb 2016 20:26:44 +0100 Subject: [PATCH 1/6] mkimage.c: Split into separate files.
util/grub-mkimagexx.c is included in a special way into mkimage.c. Interoperation between defines makes this very tricky. Instead just have a clean interface and compile util/grub-mkimage*.c separately from mkimage.c --- Makefile.util.def | 10 ++ include/grub/util/mkimage.h | 170 +++++++++++++++++++++++++++ util/grub-mkimage32.c | 22 ++++ util/grub-mkimage64.c | 22 ++++ util/grub-mkimagexx.c | 246 +++++++++++++++++++++++++++------------ util/mkimage.c | 273 ++------------------------------------------ 6 files changed, 405 insertions(+), 338 deletions(-) create mode 100644 include/grub/util/mkimage.h create mode 100644 util/grub-mkimage32.c create mode 100644 util/grub-mkimage64.c diff --git a/Makefile.util.def b/Makefile.util.def index db7e8ec..ed9b4c6 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -172,6 +172,8 @@ program = { common = util/grub-mkimage.c; common = util/mkimage.c; + common = util/grub-mkimage32.c; + common = util/grub-mkimage64.c; common = util/resolve.c; common = grub-core/kern/emu/argp_common.c; common = grub-core/osdep/init.c; @@ -510,6 +512,8 @@ program = { common = util/render-label.c; common = util/glue-efi.c; common = util/mkimage.c; + common = util/grub-mkimage32.c; + common = util/grub-mkimage64.c; common = util/grub-install-common.c; common = util/setup_bios.c; common = util/setup_sparc.c; @@ -552,6 +556,8 @@ program = { common = util/render-label.c; common = util/glue-efi.c; common = util/mkimage.c; + common = util/grub-mkimage32.c; + common = util/grub-mkimage64.c; common = util/grub-install-common.c; common = util/setup_bios.c; common = util/setup_sparc.c; @@ -595,6 +601,8 @@ program = { common = util/grub-install.c; common = util/probe.c; common = util/mkimage.c; + common = util/grub-mkimage32.c; + common = util/grub-mkimage64.c; common = util/grub-install-common.c; common = util/setup_bios.c; common = util/setup_sparc.c; @@ -632,6 +640,8 @@ program = { common = util/grub-mknetdir.c; common = util/mkimage.c; + common = util/grub-mkimage32.c; + common = util/grub-mkimage64.c; common = util/grub-install-common.c; common = util/setup_bios.c; common = util/setup_sparc.c; diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h new file mode 100644 index 0000000..564adbc --- /dev/null +++ b/include/grub/util/mkimage.h @@ -0,0 +1,170 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_UTIL_MKIMAGE_HEADER +#define GRUB_UTIL_MKIMAGE_HEADER 1 + +/* Private header. Use only in mkimage-related sources. */ +char * +grub_mkimage_load_image32 (const char *kernel_path, size_t *exec_size, + size_t *kernel_sz, size_t *bss_size, + size_t total_module_size, grub_uint64_t *start, + void **reloc_section, size_t *reloc_size, + size_t *align, + const struct grub_install_image_target_desc *image_target); +char * +grub_mkimage_load_image64 (const char *kernel_path, size_t *exec_size, + size_t *kernel_sz, size_t *bss_size, + size_t total_module_size, grub_uint64_t *start, + void **reloc_section, size_t *reloc_size, + size_t *align, + const struct grub_install_image_target_desc *image_target); +void +grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, + int note, char **core_img, size_t *core_size, + Elf32_Addr target_addr, grub_size_t align, + size_t kernel_size, size_t bss_size); +void +grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, + int note, char **core_img, size_t *core_size, + Elf64_Addr target_addr, grub_size_t align, + size_t kernel_size, size_t bss_size); + +struct grub_install_image_target_desc +{ + const char *dirname; + const char *names[6]; + grub_size_t voidp_sizeof; + int bigendian; + enum { + IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, + IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_SPARC64_CDCORE, + IMAGE_I386_IEEE1275, + IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, + IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC, + IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT, IMAGE_XEN, IMAGE_I386_PC_ELTORITO + } id; + enum + { + PLATFORM_FLAGS_NONE = 0, + PLATFORM_FLAGS_DECOMPRESSORS = 2, + PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4, + } flags; + unsigned total_module_size; + unsigned decompressor_compressed_size; + unsigned decompressor_uncompressed_size; + unsigned decompressor_uncompressed_addr; + unsigned link_align; + grub_uint16_t elf_target; + unsigned section_align; + signed vaddr_offset; + grub_uint64_t link_addr; + unsigned mod_gap, mod_align; + grub_compression_t default_compression; + grub_uint16_t pe_target; +}; + +#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x))) +#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x))) +#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x))) +#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x))) +#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x))) +#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x))) +#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x))) + +static inline grub_uint32_t +grub_target_to_host32_real (const struct grub_install_image_target_desc *image_target, + grub_uint32_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu32 (in); + else + return grub_le_to_cpu32 (in); +} + +static inline grub_uint64_t +grub_target_to_host64_real (const struct grub_install_image_target_desc *image_target, + grub_uint64_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu64 (in); + else + return grub_le_to_cpu64 (in); +} + +static inline grub_uint64_t +grub_host_to_target64_real (const struct grub_install_image_target_desc *image_target, + grub_uint64_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be64 (in); + else + return grub_cpu_to_le64 (in); +} + +static inline grub_uint32_t +grub_host_to_target32_real (const struct grub_install_image_target_desc *image_target, + grub_uint32_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be32 (in); + else + return grub_cpu_to_le32 (in); +} + +static inline grub_uint16_t +grub_target_to_host16_real (const struct grub_install_image_target_desc *image_target, + grub_uint16_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu16 (in); + else + return grub_le_to_cpu16 (in); +} + +static inline grub_uint16_t +grub_host_to_target16_real (const struct grub_install_image_target_desc *image_target, + grub_uint16_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be16 (in); + else + return grub_cpu_to_le16 (in); +} + +static inline grub_uint64_t +grub_host_to_target_addr_real (const struct grub_install_image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->voidp_sizeof == 8) + return grub_host_to_target64_real (image_target, in); + else + return grub_host_to_target32_real (image_target, in); +} + +static inline grub_uint64_t +grub_target_to_host_real (const struct grub_install_image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->voidp_sizeof == 8) + return grub_target_to_host64_real (image_target, in); + else + return grub_target_to_host32_real (image_target, in); +} + +#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val)) + +#endif diff --git a/util/grub-mkimage32.c b/util/grub-mkimage32.c new file mode 100644 index 0000000..9b31397 --- /dev/null +++ b/util/grub-mkimage32.c @@ -0,0 +1,22 @@ +#define MKIMAGE_ELF32 1 + +# define SUFFIX(x) x ## 32 +# define ELFCLASSXX ELFCLASS32 +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Phdr Elf32_Phdr +# define Elf_Nhdr Elf32_Nhdr +# define Elf_Addr Elf32_Addr +# define Elf_Sym Elf32_Sym +# define Elf_Off Elf32_Off +# define Elf_Shdr Elf32_Shdr +# define Elf_Rela Elf32_Rela +# define Elf_Rel Elf32_Rel +# define Elf_Word Elf32_Word +# define Elf_Half Elf32_Half +# define Elf_Section Elf32_Section +# define ELF_R_SYM(val) ELF32_R_SYM(val) +# define ELF_R_TYPE(val) ELF32_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +#define XEN_NOTE_SIZE 132 + +#include "grub-mkimagexx.c" diff --git a/util/grub-mkimage64.c b/util/grub-mkimage64.c new file mode 100644 index 0000000..d833459 --- /dev/null +++ b/util/grub-mkimage64.c @@ -0,0 +1,22 @@ +#define MKIMAGE_ELF64 1 + +# define SUFFIX(x) x ## 64 +# define ELFCLASSXX ELFCLASS64 +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Phdr Elf64_Phdr +# define Elf_Nhdr Elf64_Nhdr +# define Elf_Addr Elf64_Addr +# define Elf_Sym Elf64_Sym +# define Elf_Off Elf64_Off +# define Elf_Shdr Elf64_Shdr +# define Elf_Rela Elf64_Rela +# define Elf_Rel Elf64_Rel +# define Elf_Word Elf64_Word +# define Elf_Half Elf64_Half +# define Elf_Section Elf64_Section +# define ELF_R_SYM(val) ELF64_R_SYM(val) +# define ELF_R_TYPE(val) ELF64_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val) +#define XEN_NOTE_SIZE 120 + +#include "grub-mkimagexx.c" diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 06b6a72..03874be 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -17,58 +17,172 @@ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ -#undef ELF_R_SYM -#undef ELF_R_TYPE - -#if defined(MKIMAGE_ELF32) -# define SUFFIX(x) x ## 32 -# define ELFCLASSXX ELFCLASS32 -# define Elf_Ehdr Elf32_Ehdr -# define Elf_Phdr Elf32_Phdr -# define Elf_Nhdr Elf32_Nhdr -# define Elf_Addr Elf32_Addr -# define Elf_Sym Elf32_Sym -# define Elf_Off Elf32_Off -# define Elf_Shdr Elf32_Shdr -# define Elf_Rela Elf32_Rela -# define Elf_Rel Elf32_Rel -# define Elf_Word Elf32_Word -# define Elf_Half Elf32_Half -# define Elf_Section Elf32_Section -# define ELF_R_SYM(val) ELF32_R_SYM(val) -# define ELF_R_TYPE(val) ELF32_R_TYPE(val) -# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) -#define XEN_NOTE_SIZE 132 -#elif defined(MKIMAGE_ELF64) -# define SUFFIX(x) x ## 64 -# define ELFCLASSXX ELFCLASS64 -# define Elf_Ehdr Elf64_Ehdr -# define Elf_Phdr Elf64_Phdr -# define Elf_Nhdr Elf64_Nhdr -# define Elf_Addr Elf64_Addr -# define Elf_Sym Elf64_Sym -# define Elf_Off Elf64_Off -# define Elf_Shdr Elf64_Shdr -# define Elf_Rela Elf64_Rela -# define Elf_Rel Elf64_Rel -# define Elf_Word Elf64_Word -# define Elf_Half Elf64_Half -# define Elf_Section Elf64_Section -# define ELF_R_SYM(val) ELF64_R_SYM(val) -# define ELF_R_TYPE(val) ELF64_R_TYPE(val) -# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val) -#define XEN_NOTE_SIZE 120 -#else -#error "I'm confused" -#endif +#include <config.h> +#include <grub/types.h> +#include <grub/elf.h> +#include <grub/aout.h> +#include <grub/i18n.h> +#include <grub/kernel.h> +#include <grub/disk.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/util/resolve.h> +#include <grub/misc.h> +#include <grub/offsets.h> +#include <grub/crypto.h> +#include <grub/dl.h> +#include <time.h> +#include <multiboot.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <grub/efi/pe32.h> +#include <grub/uboot/image.h> +#include <grub/arm/reloc.h> +#include <grub/arm64/reloc.h> +#include <grub/ia64/reloc.h> +#include <grub/osdep/hostfile.h> +#include <grub/util/install.h> +#include <grub/util/mkimage.h> + +#pragma GCC diagnostic ignored "-Wcast-align" static Elf_Addr SUFFIX (entry_point); -static void -SUFFIX (generate_elf) (const struct grub_install_image_target_desc *image_target, - int note, char **core_img, size_t *core_size, - Elf_Addr target_addr, grub_size_t align, - size_t kernel_size, size_t bss_size) +/* These structures are defined according to the CHRP binding to IEEE1275, + "Client Program Format" section. */ + +struct grub_ieee1275_note_desc +{ + grub_uint32_t real_mode; + grub_uint32_t real_base; + grub_uint32_t real_size; + grub_uint32_t virt_base; + grub_uint32_t virt_size; + grub_uint32_t load_base; +}; + +#define GRUB_IEEE1275_NOTE_NAME "PowerPC" +#define GRUB_IEEE1275_NOTE_TYPE 0x1275 + +struct grub_ieee1275_note +{ + Elf32_Nhdr header; + char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)]; + struct grub_ieee1275_note_desc descriptor; +}; + +#define GRUB_XEN_NOTE_NAME "Xen" + +struct fixup_block_list +{ + struct fixup_block_list *next; + int state; + struct grub_pe32_fixup_block b; +}; + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +#ifdef MKIMAGE_ELF32 + +/* + * R_ARM_THM_CALL/THM_JUMP24 + * + * Relocate Thumb (T32) instruction set relative branches: + * B.W, BL and BLX + */ +static grub_err_t +grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + offset = grub_arm_thm_call_get_offset (target); + + grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr); + + offset += sym_addr; + + grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n", + target, sym_addr, offset); + + /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel + is bigger than 2M (currently under 150K) then we probably have a problem + somewhere else. */ + if (offset < -0x200000 || offset >= 0x200000) + return grub_error (GRUB_ERR_BAD_MODULE, + "THM_CALL Relocation out of range."); + + grub_dprintf ("dl", " relative destination = %p", + (char *) target + offset); + + return grub_arm_thm_call_set_offset (target, offset); +} + +/* + * R_ARM_THM_JUMP19 + * + * Relocate conditional Thumb (T32) B<c>.W + */ +static grub_err_t +grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + if (!(sym_addr & 1)) + return grub_error (GRUB_ERR_BAD_MODULE, + "Relocation targeting wrong execution state"); + + offset = grub_arm_thm_jump19_get_offset (target); + + /* Adjust and re-truncate offset */ + offset += sym_addr; + + if (!grub_arm_thm_jump19_check_offset (offset)) + return grub_error (GRUB_ERR_BAD_MODULE, + "THM_JUMP19 Relocation out of range."); + + grub_arm_thm_jump19_set_offset (target, offset); + + return GRUB_ERR_NONE; +} + +/* + * R_ARM_JUMP24 + * + * Relocate ARM (A32) B + */ +static grub_err_t +grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + if (sym_addr & 1) + return grub_error (GRUB_ERR_BAD_MODULE, + "Relocation targeting wrong execution state"); + + offset = grub_arm_jump24_get_offset (target); + offset += sym_addr; + + if (!grub_arm_jump24_check_offset (offset)) + return grub_error (GRUB_ERR_BAD_MODULE, + "JUMP24 Relocation out of range."); + + + grub_arm_jump24_set_offset (target, offset); + + return GRUB_ERR_NONE; +} + +#endif + +void +SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, + int note, char **core_img, size_t *core_size, + Elf_Addr target_addr, grub_size_t align, + size_t kernel_size, size_t bss_size) { char *elf_img; size_t program_size; @@ -1457,13 +1571,13 @@ SUFFIX (locate_sections) (const char *kernel_path, return section_addresses; } -static char * -SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, - size_t *kernel_sz, size_t *bss_size, - size_t total_module_size, grub_uint64_t *start, - void **reloc_section, size_t *reloc_size, - size_t *align, - const struct grub_install_image_target_desc *image_target) +char * +SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, + size_t *kernel_sz, size_t *bss_size, + size_t total_module_size, grub_uint64_t *start, + void **reloc_section, size_t *reloc_size, + size_t *align, + const struct grub_install_image_target_desc *image_target) { char *kernel_img, *out_img; const char *strtab; @@ -1671,23 +1785,3 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, return out_img; } - - -#undef SUFFIX -#undef ELFCLASSXX -#undef Elf_Ehdr -#undef Elf_Phdr -#undef Elf_Nhdr -#undef Elf_Shdr -#undef Elf_Addr -#undef Elf_Sym -#undef Elf_Off -#undef Elf_Rela -#undef Elf_Rel -#undef ELF_R_TYPE -#undef ELF_R_SYM -#undef Elf_Word -#undef Elf_Half -#undef Elf_Section -#undef ELF_ST_TYPE -#undef XEN_NOTE_SIZE diff --git a/util/mkimage.c b/util/mkimage.c index c3365bb..678b221 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -46,6 +46,7 @@ #include <grub/ia64/reloc.h> #include <grub/osdep/hostfile.h> #include <grub/util/install.h> +#include <grub/util/mkimage.h> #define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) @@ -58,40 +59,6 @@ /* use 2015-01-01T00:00:00+0000 as a stock timestamp */ #define STABLE_EMBEDDING_TIMESTAMP 1420070400 -struct grub_install_image_target_desc -{ - const char *dirname; - const char *names[6]; - grub_size_t voidp_sizeof; - int bigendian; - enum { - IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, - IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_SPARC64_CDCORE, - IMAGE_I386_IEEE1275, - IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, - IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC, - IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT, IMAGE_XEN, IMAGE_I386_PC_ELTORITO - } id; - enum - { - PLATFORM_FLAGS_NONE = 0, - PLATFORM_FLAGS_DECOMPRESSORS = 2, - PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4, - } flags; - unsigned total_module_size; - unsigned decompressor_compressed_size; - unsigned decompressor_uncompressed_size; - unsigned decompressor_uncompressed_addr; - unsigned link_align; - grub_uint16_t elf_target; - unsigned section_align; - signed vaddr_offset; - grub_uint64_t link_addr; - unsigned mod_gap, mod_align; - grub_compression_t default_compression; - grub_uint16_t pe_target; -}; - #define EFI32_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE \ + GRUB_PE32_SIGNATURE_SIZE \ + sizeof (struct grub_pe32_coff_header) \ @@ -603,119 +570,6 @@ static const struct grub_install_image_target_desc image_targets[] = }, }; -#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x))) -#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x))) -#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x))) -#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x))) -#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x))) -#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x))) -#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x))) - -static inline grub_uint32_t -grub_target_to_host32_real (const struct grub_install_image_target_desc *image_target, - grub_uint32_t in) -{ - if (image_target->bigendian) - return grub_be_to_cpu32 (in); - else - return grub_le_to_cpu32 (in); -} - -static inline grub_uint64_t -grub_target_to_host64_real (const struct grub_install_image_target_desc *image_target, - grub_uint64_t in) -{ - if (image_target->bigendian) - return grub_be_to_cpu64 (in); - else - return grub_le_to_cpu64 (in); -} - -static inline grub_uint64_t -grub_host_to_target64_real (const struct grub_install_image_target_desc *image_target, - grub_uint64_t in) -{ - if (image_target->bigendian) - return grub_cpu_to_be64 (in); - else - return grub_cpu_to_le64 (in); -} - -static inline grub_uint32_t -grub_host_to_target32_real (const struct grub_install_image_target_desc *image_target, - grub_uint32_t in) -{ - if (image_target->bigendian) - return grub_cpu_to_be32 (in); - else - return grub_cpu_to_le32 (in); -} - -static inline grub_uint16_t -grub_target_to_host16_real (const struct grub_install_image_target_desc *image_target, - grub_uint16_t in) -{ - if (image_target->bigendian) - return grub_be_to_cpu16 (in); - else - return grub_le_to_cpu16 (in); -} - -static inline grub_uint16_t -grub_host_to_target16_real (const struct grub_install_image_target_desc *image_target, - grub_uint16_t in) -{ - if (image_target->bigendian) - return grub_cpu_to_be16 (in); - else - return grub_cpu_to_le16 (in); -} - -static inline grub_uint64_t -grub_host_to_target_addr_real (const struct grub_install_image_target_desc *image_target, grub_uint64_t in) -{ - if (image_target->voidp_sizeof == 8) - return grub_host_to_target64_real (image_target, in); - else - return grub_host_to_target32_real (image_target, in); -} - -static inline grub_uint64_t -grub_target_to_host_real (const struct grub_install_image_target_desc *image_target, grub_uint64_t in) -{ - if (image_target->voidp_sizeof == 8) - return grub_target_to_host64_real (image_target, in); - else - return grub_target_to_host32_real (image_target, in); -} - -#define GRUB_IEEE1275_NOTE_NAME "PowerPC" -#define GRUB_IEEE1275_NOTE_TYPE 0x1275 - -/* These structures are defined according to the CHRP binding to IEEE1275, - "Client Program Format" section. */ - -struct grub_ieee1275_note_desc -{ - grub_uint32_t real_mode; - grub_uint32_t real_base; - grub_uint32_t real_size; - grub_uint32_t virt_base; - grub_uint32_t virt_size; - grub_uint32_t load_base; -}; - -struct grub_ieee1275_note -{ - Elf32_Nhdr header; - char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)]; - struct grub_ieee1275_note_desc descriptor; -}; - -#define GRUB_XEN_NOTE_NAME "Xen" - -#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val)) - #include <grub/lib/LzmaEnc.h> static void *SzAlloc(void *p __attribute__ ((unused)), size_t size) { return xmalloc(size); } @@ -830,111 +684,6 @@ compress_kernel (const struct grub_install_image_target_desc *image_target, char *core_size = kernel_size; } -struct fixup_block_list -{ - struct fixup_block_list *next; - int state; - struct grub_pe32_fixup_block b; -}; - -/* - * R_ARM_THM_CALL/THM_JUMP24 - * - * Relocate Thumb (T32) instruction set relative branches: - * B.W, BL and BLX - */ -static grub_err_t -grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) -{ - grub_int32_t offset; - - offset = grub_arm_thm_call_get_offset (target); - - grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr); - - offset += sym_addr; - - grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n", - target, sym_addr, offset); - - /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel - is bigger than 2M (currently under 150K) then we probably have a problem - somewhere else. */ - if (offset < -0x200000 || offset >= 0x200000) - return grub_error (GRUB_ERR_BAD_MODULE, - "THM_CALL Relocation out of range."); - - grub_dprintf ("dl", " relative destination = %p", - (char *) target + offset); - - return grub_arm_thm_call_set_offset (target, offset); -} - -/* - * R_ARM_THM_JUMP19 - * - * Relocate conditional Thumb (T32) B<c>.W - */ -static grub_err_t -grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr) -{ - grub_int32_t offset; - - if (!(sym_addr & 1)) - return grub_error (GRUB_ERR_BAD_MODULE, - "Relocation targeting wrong execution state"); - - offset = grub_arm_thm_jump19_get_offset (target); - - /* Adjust and re-truncate offset */ - offset += sym_addr; - - if (!grub_arm_thm_jump19_check_offset (offset)) - return grub_error (GRUB_ERR_BAD_MODULE, - "THM_JUMP19 Relocation out of range."); - - grub_arm_thm_jump19_set_offset (target, offset); - - return GRUB_ERR_NONE; -} - -/* - * R_ARM_JUMP24 - * - * Relocate ARM (A32) B - */ -static grub_err_t -grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) -{ - grub_int32_t offset; - - if (sym_addr & 1) - return grub_error (GRUB_ERR_BAD_MODULE, - "Relocation targeting wrong execution state"); - - offset = grub_arm_jump24_get_offset (target); - offset += sym_addr; - - if (!grub_arm_jump24_check_offset (offset)) - return grub_error (GRUB_ERR_BAD_MODULE, - "JUMP24 Relocation out of range."); - - - grub_arm_jump24_set_offset (target, offset); - - return GRUB_ERR_NONE; -} - -#pragma GCC diagnostic ignored "-Wcast-align" - -#define MKIMAGE_ELF32 1 -#include "grub-mkimagexx.c" -#undef MKIMAGE_ELF32 - -#define MKIMAGE_ELF64 1 -#include "grub-mkimagexx.c" -#undef MKIMAGE_ELF64 - const struct grub_install_image_target_desc * grub_install_get_image_target (const char *arg) { @@ -1063,13 +812,13 @@ grub_install_generate_image (const char *dir, const char *prefix, (unsigned long long) total_module_size); if (image_target->voidp_sizeof == 4) - kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, - total_module_size, &start_address, &rel_section, - &reloc_size, &align, image_target); + kernel_img = grub_mkimage_load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, + total_module_size, &start_address, &rel_section, + &reloc_size, &align, image_target); else - kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, - total_module_size, &start_address, &rel_section, - &reloc_size, &align, image_target); + kernel_img = grub_mkimage_load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, + total_module_size, &start_address, &rel_section, + &reloc_size, &align, image_target); if (image_target->id == IMAGE_XEN && align < 4096) align = 4096; @@ -1890,11 +1639,11 @@ grub_install_generate_image (const char *dir, const char *prefix, else target_addr = image_target->link_addr; if (image_target->voidp_sizeof == 4) - generate_elf32 (image_target, note, &core_img, &core_size, - target_addr, align, kernel_size, bss_size); + grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, + target_addr, align, kernel_size, bss_size); else - generate_elf64 (image_target, note, &core_img, &core_size, - target_addr, align, kernel_size, bss_size); + grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, + target_addr, align, kernel_size, bss_size); } break; } -- 2.7.0
From 88091fb936a45f8dece352c5bec26e011f9573c3 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko <phco...@gmail.com> Date: Thu, 18 Feb 2016 20:54:37 +0100 Subject: [PATCH 2/6] mkimagexx: Split PE and generic part for relocations. As a preparation for U-Boot relocations, split emitting PE-relocations from parsing source ELF-relocations. --- util/grub-mkimagexx.c | 415 ++++++++++++++++++++++++++------------------------ 1 file changed, 219 insertions(+), 196 deletions(-) diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 03874be..a39803a 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -1095,9 +1095,9 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, /* Add a PE32's fixup entry for a relocation. Return the resulting address after having written to the file OUT. */ static Elf_Addr -SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type, - Elf_Addr addr, int flush, Elf_Addr current_address, - const struct grub_install_image_target_desc *image_target) +add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + Elf_Addr addr, int flush, Elf_Addr current_address, + const struct grub_install_image_target_desc *image_target) { struct grub_pe32_fixup_block *b; @@ -1187,22 +1187,222 @@ SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type, return current_address; } +struct translate_context +{ + struct fixup_block_list *lst, *lst0; + Elf_Addr current_address; +}; + +static void +translate_reloc_start (struct translate_context *ctx) +{ + ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000); + memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000); + ctx->current_address = 0; +} + +static void +translate_relocation (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + /* Necessary to relocate only absolute addresses. */ + switch (image_target->elf_target) + { + case EM_386: + if (ELF_R_TYPE (info) == R_386_32) + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + case EM_X86_64: + if ((ELF_R_TYPE (info) == R_X86_64_32) || + (ELF_R_TYPE (info) == R_X86_64_32S)) + { + grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); + } + else if (ELF_R_TYPE (info) == R_X86_64_64) + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + } + break; + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL64LSB: + case R_IA64_LDXMOV: + case R_IA64_PCREL21B: + case R_IA64_LTOFF_FPTR22: + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + case R_IA64_GPREL22: + case R_IA64_SEGREL64LSB: + break; + + case R_IA64_FPTR64LSB: + case R_IA64_DIR64LSB: +#if 1 + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + } +#endif + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_AARCH64: + switch (ELF_R_TYPE (info)) + { + case R_AARCH64_ABS64: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, 0, ctx->current_address, + image_target); + } + break; + /* Relative relocations do not require fixup entries. */ + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + break; + /* Page-relative relocations do not require fixup entries. */ + case R_AARCH64_ADR_PREL_PG_HI21: + /* We page-align the whole kernel, so no need + for fixup entries. + */ + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + break; +#if defined(MKIMAGE_ELF32) + case EM_ARM: + switch (ELF_R_TYPE (info)) + { + case R_ARM_V4BX: + /* Relative relocations do not require fixup entries. */ + case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_CALL: + { + grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address); + } + break; + /* Create fixup entry for PE/COFF loader */ + case R_ARM_ABS32: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#endif /* defined(MKIMAGE_ELF32) */ + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); + } +} + +static Elf_Addr +finish_reloc_translation (struct translate_context *ctx, void **out, + const struct grub_install_image_target_desc *image_target) +{ + ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target); + + { + grub_uint8_t *ptr; + ptr = *out = xmalloc (ctx->current_address); + for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next) + if (ctx->lst->state) + { + memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size)); + ptr += grub_target_to_host32 (ctx->lst->b.block_size); + } + assert ((ctx->current_address + (grub_uint8_t *) *out) == ptr); + } + + for (ctx->lst = ctx->lst0; ctx->lst; ) + { + struct fixup_block_list *next; + next = ctx->lst->next; + free (ctx->lst); + ctx->lst = next; + } + + return ctx->current_address; +} + +static void +translate_reloc_jumpers (struct translate_context *ctx, + Elf_Addr jumpers, grub_size_t njumpers, + const struct grub_install_image_target_desc *image_target) +{ + unsigned i; + for (i = 0; i < njumpers; i++) + ctx->current_address = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + jumpers + 8 * i, + 0, ctx->current_address, + image_target); +} + /* Make a .reloc section. */ static Elf_Addr -SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, - Elf_Addr *section_addresses, Elf_Shdr *sections, - Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab, - Elf_Addr jumpers, grub_size_t njumpers, - const struct grub_install_image_target_desc *image_target) +make_reloc_section (Elf_Ehdr *e, void **out, + Elf_Addr *section_addresses, Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections, + const char *strtab, + Elf_Addr jumpers, grub_size_t njumpers, + const struct grub_install_image_target_desc *image_target) { unsigned i; Elf_Shdr *s; - struct fixup_block_list *lst, *lst0; - Elf_Addr current_address = 0; + struct translate_context ctx; - lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000); - memset (lst, 0, sizeof (*lst) + 2 * 0x1000); + translate_reloc_start (&ctx); for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) @@ -1231,199 +1431,22 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, { Elf_Addr info; Elf_Addr offset; + Elf_Addr addr; offset = grub_target_to_host (r->r_offset); info = grub_target_to_host (r->r_info); - /* Necessary to relocate only absolute addresses. */ - switch (image_target->elf_target) - { - case EM_386: - if (ELF_R_TYPE (info) == R_386_32) - { - Elf_Addr addr; + addr = section_address + offset; - addr = section_address + offset; - grub_util_info ("adding a relocation entry for 0x%" - GRUB_HOST_PRIxLONG_LONG, - (unsigned long long) addr); - current_address - = SUFFIX (add_fixup_entry) (&lst, - GRUB_PE32_REL_BASED_HIGHLOW, - addr, 0, current_address, - image_target); - } - break; - case EM_X86_64: - if ((ELF_R_TYPE (info) == R_X86_64_32) || - (ELF_R_TYPE (info) == R_X86_64_32S)) - { - grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); - } - else if (ELF_R_TYPE (info) == R_X86_64_64) - { - Elf_Addr addr; - - addr = section_address + offset; - grub_util_info ("adding a relocation entry for 0x%" - GRUB_HOST_PRIxLONG_LONG, - (unsigned long long) addr); - current_address - = SUFFIX (add_fixup_entry) (&lst, - GRUB_PE32_REL_BASED_DIR64, - addr, - 0, current_address, - image_target); - } - break; - case EM_IA_64: - switch (ELF_R_TYPE (info)) - { - case R_IA64_PCREL64LSB: - case R_IA64_LDXMOV: - case R_IA64_PCREL21B: - case R_IA64_LTOFF_FPTR22: - case R_IA64_LTOFF22X: - case R_IA64_LTOFF22: - case R_IA64_GPREL22: - case R_IA64_SEGREL64LSB: - break; - - case R_IA64_FPTR64LSB: - case R_IA64_DIR64LSB: -#if 1 - { - Elf_Addr addr; - - addr = section_address + offset; - grub_util_info ("adding a relocation entry for 0x%" - GRUB_HOST_PRIxLONG_LONG, - (unsigned long long) addr); - current_address - = SUFFIX (add_fixup_entry) (&lst, - GRUB_PE32_REL_BASED_DIR64, - addr, - 0, current_address, - image_target); - } -#endif - break; - default: - grub_util_error (_("relocation 0x%x is not implemented yet"), - (unsigned int) ELF_R_TYPE (info)); - break; - } - break; - case EM_AARCH64: - switch (ELF_R_TYPE (info)) - { - case R_AARCH64_ABS64: - { - Elf_Addr addr; - - addr = section_address + offset; - current_address - = SUFFIX (add_fixup_entry) (&lst, - GRUB_PE32_REL_BASED_DIR64, - addr, 0, current_address, - image_target); - } - break; - /* Relative relocations do not require fixup entries. */ - case R_AARCH64_CALL26: - case R_AARCH64_JUMP26: - break; - /* Page-relative relocations do not require fixup entries. */ - case R_AARCH64_ADR_PREL_PG_HI21: - /* We page-align the whole kernel, so no need - for fixup entries. - */ - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_LDST64_ABS_LO12_NC: - break; - - default: - grub_util_error (_("relocation 0x%x is not implemented yet"), - (unsigned int) ELF_R_TYPE (info)); - break; - } - break; - break; -#if defined(MKIMAGE_ELF32) - case EM_ARM: - switch (ELF_R_TYPE (info)) - { - case R_ARM_V4BX: - /* Relative relocations do not require fixup entries. */ - case R_ARM_JUMP24: - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP19: - case R_ARM_THM_JUMP24: - case R_ARM_CALL: - { - Elf_Addr addr; - - addr = section_address + offset; - grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) current_address); - } - break; - /* Create fixup entry for PE/COFF loader */ - case R_ARM_ABS32: - { - Elf_Addr addr; - - addr = section_address + offset; - current_address - = SUFFIX (add_fixup_entry) (&lst, - GRUB_PE32_REL_BASED_HIGHLOW, - addr, 0, current_address, - image_target); - } - break; - default: - grub_util_error (_("relocation 0x%x is not implemented yet"), - (unsigned int) ELF_R_TYPE (info)); - break; - } - break; -#endif /* defined(MKIMAGE_ELF32) */ - default: - grub_util_error ("unknown machine type 0x%x", image_target->elf_target); - } + translate_relocation (&ctx, addr, info, image_target); } } if (image_target->elf_target == EM_IA_64) - for (i = 0; i < njumpers; i++) - current_address = SUFFIX (add_fixup_entry) (&lst, - GRUB_PE32_REL_BASED_DIR64, - jumpers + 8 * i, - 0, current_address, - image_target); + translate_reloc_jumpers (&ctx, jumpers, njumpers, + image_target); - current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target); - - { - grub_uint8_t *ptr; - ptr = *out = xmalloc (current_address); - for (lst = lst0; lst; lst = lst->next) - if (lst->state) - { - memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size)); - ptr += grub_target_to_host32 (lst->b.block_size); - } - assert ((current_address + (grub_uint8_t *) *out) == ptr); - } - - for (lst = lst0; lst; ) - { - struct fixup_block_list *next; - next = lst->next; - free (lst); - lst = next; - } - - return current_address; + return finish_reloc_translation (&ctx, out, image_target); } /* Determine if this section is a text section. Return false if this -- 2.7.0
From 7cfa8d4568b714b463e0ad4ac900017a538a5840 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko <phco...@gmail.com> Date: Fri, 19 Feb 2016 01:49:53 +0100 Subject: [PATCH 3/6] Encapsulate image layout into a separate structure. Currently we pass around a lot of pointer. Instead put all relevant data into one structure. --- include/grub/util/mkimage.h | 32 ++++++++---- util/grub-mkimagexx.c | 116 ++++++++++++++++++++++---------------------- util/mkimage.c | 112 +++++++++++++++++++++--------------------- 3 files changed, 133 insertions(+), 127 deletions(-) diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h index 564adbc..8169939 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -19,20 +19,32 @@ #ifndef GRUB_UTIL_MKIMAGE_HEADER #define GRUB_UTIL_MKIMAGE_HEADER 1 +struct grub_mkimage_layout +{ + size_t exec_size; + size_t kernel_size; + size_t bss_size; + grub_uint64_t start_address; + void *reloc_section; + size_t reloc_size; + size_t align; + grub_size_t ia64jmp_off; + grub_size_t tramp_off; + grub_size_t ia64_got_off; + grub_size_t got_size; + unsigned ia64jmpnum; +}; + /* Private header. Use only in mkimage-related sources. */ char * -grub_mkimage_load_image32 (const char *kernel_path, size_t *exec_size, - size_t *kernel_sz, size_t *bss_size, - size_t total_module_size, grub_uint64_t *start, - void **reloc_section, size_t *reloc_size, - size_t *align, +grub_mkimage_load_image32 (const char *kernel_path, + size_t total_module_size, + struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target); char * -grub_mkimage_load_image64 (const char *kernel_path, size_t *exec_size, - size_t *kernel_sz, size_t *bss_size, - size_t total_module_size, grub_uint64_t *start, - void **reloc_section, size_t *reloc_size, - size_t *align, +grub_mkimage_load_image64 (const char *kernel_path, + size_t total_module_size, + struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target); void grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index a39803a..74f86f5 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -1346,22 +1346,23 @@ translate_relocation (struct translate_context *ctx, } } -static Elf_Addr -finish_reloc_translation (struct translate_context *ctx, void **out, +static void +finish_reloc_translation (struct translate_context *ctx, + struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target) { ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target); { grub_uint8_t *ptr; - ptr = *out = xmalloc (ctx->current_address); + layout->reloc_section = ptr = xmalloc (ctx->current_address); for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next) if (ctx->lst->state) { memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size)); ptr += grub_target_to_host32 (ctx->lst->b.block_size); } - assert ((ctx->current_address + (grub_uint8_t *) *out) == ptr); + assert ((ctx->current_address + (grub_uint8_t *) layout->reloc_section) == ptr); } for (ctx->lst = ctx->lst0; ctx->lst; ) @@ -1372,7 +1373,7 @@ finish_reloc_translation (struct translate_context *ctx, void **out, ctx->lst = next; } - return ctx->current_address; + layout->reloc_size = ctx->current_address; } static void @@ -1390,8 +1391,8 @@ translate_reloc_jumpers (struct translate_context *ctx, } /* Make a .reloc section. */ -static Elf_Addr -make_reloc_section (Elf_Ehdr *e, void **out, +static void +make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, Elf_Addr *section_addresses, Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, const char *strtab, @@ -1446,7 +1447,7 @@ make_reloc_section (Elf_Ehdr *e, void **out, translate_reloc_jumpers (&ctx, jumpers, njumpers, image_target); - return finish_reloc_translation (&ctx, out, image_target); + finish_reloc_translation (&ctx, layout, image_target); } /* Determine if this section is a text section. Return false if this @@ -1498,8 +1499,7 @@ static Elf_Addr * SUFFIX (locate_sections) (const char *kernel_path, Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, const char *strtab, - size_t *exec_size, size_t *kernel_sz, - size_t *all_align, + struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target) { int i; @@ -1507,10 +1507,10 @@ SUFFIX (locate_sections) (const char *kernel_path, Elf_Addr *section_addresses; Elf_Shdr *s; - *all_align = 1; + layout->align = 1; /* Page-aligning simplifies relocation handling. */ if (image_target->elf_target == EM_AARCH64) - *all_align = 4096; + layout->align = 4096; section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); @@ -1521,8 +1521,8 @@ SUFFIX (locate_sections) (const char *kernel_path, i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) - && grub_host_to_target32 (s->sh_addralign) > *all_align) - *all_align = grub_host_to_target32 (s->sh_addralign); + && grub_host_to_target32 (s->sh_addralign) > layout->align) + layout->align = grub_host_to_target32 (s->sh_addralign); /* .text */ @@ -1562,7 +1562,7 @@ SUFFIX (locate_sections) (const char *kernel_path, current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - *exec_size = current_address; + layout->exec_size = current_address; /* .data */ for (i = 0, s = sections; @@ -1590,16 +1590,14 @@ SUFFIX (locate_sections) (const char *kernel_path, current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - *kernel_sz = current_address; + layout->kernel_size = current_address; return section_addresses; } char * -SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, - size_t *kernel_sz, size_t *bss_size, - size_t total_module_size, grub_uint64_t *start, - void **reloc_section, size_t *reloc_size, - size_t *align, +SUFFIX (grub_mkimage_load_image) (const char *kernel_path, + size_t total_module_size, + struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target) { char *kernel_img, *out_img; @@ -1614,12 +1612,11 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, Elf_Off section_offset; Elf_Half section_entsize; grub_size_t kernel_size; - grub_size_t ia64jmp_off = 0, tramp_off = 0, ia64_got_off = 0; - unsigned ia64jmpnum = 0; Elf_Shdr *symtab_section = 0; - grub_size_t got = 0; - *start = 0; + grub_memset (layout, 0, sizeof (*layout)); + + layout->start_address = 0; kernel_size = grub_util_get_image_size (kernel_path); kernel_img = xmalloc (kernel_size); @@ -1646,7 +1643,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, section_addresses = SUFFIX (locate_sections) (kernel_path, sections, section_entsize, num_sections, strtab, - exec_size, kernel_sz, align, + layout, image_target); section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections); @@ -1656,7 +1653,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, if (image_target->id != IMAGE_EFI) { - Elf_Addr current_address = *kernel_sz; + Elf_Addr current_address = layout->kernel_size; for (i = 0, s = sections; i < num_sections; @@ -1686,15 +1683,15 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - *bss_size = current_address - *kernel_sz; + layout->bss_size = current_address - layout->kernel_size; } else - *bss_size = 0; + layout->bss_size = 0; if (image_target->id == IMAGE_SPARC64_AOUT || image_target->id == IMAGE_SPARC64_RAW || image_target->id == IMAGE_SPARC64_CDCORE) - *kernel_sz = ALIGN_UP (*kernel_sz, image_target->mod_align); + layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align); if (image_target->id == IMAGE_EFI) { @@ -1715,13 +1712,13 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, { grub_size_t tramp; - *kernel_sz = ALIGN_UP (*kernel_sz, 16); + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); tramp = arm_get_trampoline_size (e, sections, section_entsize, num_sections, image_target); - tramp_off = *kernel_sz; - *kernel_sz += ALIGN_UP (tramp, 16); + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); } #endif @@ -1730,61 +1727,62 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, size_t *exec_size, { grub_size_t tramp; - *kernel_sz = ALIGN_UP (*kernel_sz, 16); + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); - grub_ia64_dl_get_tramp_got_size (e, &tramp, &got); + grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size); - tramp_off = *kernel_sz; - *kernel_sz += ALIGN_UP (tramp, 16); + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); - ia64jmp_off = *kernel_sz; - ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section, + layout->ia64jmp_off = layout->kernel_size; + layout->ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section, image_target); - *kernel_sz += 16 * ia64jmpnum; + layout->kernel_size += 16 * layout->ia64jmpnum; - ia64_got_off = *kernel_sz; - *kernel_sz += ALIGN_UP (got, 16); + layout->ia64_got_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (layout->got_size, 16); } #endif } else { - *reloc_size = 0; - *reloc_section = NULL; + layout->reloc_size = 0; + layout->reloc_section = NULL; } - out_img = xmalloc (*kernel_sz + total_module_size); - memset (out_img, 0, *kernel_sz + total_module_size); + out_img = xmalloc (layout->kernel_size + total_module_size); + memset (out_img, 0, layout->kernel_size + total_module_size); if (image_target->id == IMAGE_EFI) { - *start = SUFFIX (relocate_symbols) (e, sections, symtab_section, + layout->start_address = SUFFIX (relocate_symbols) (e, sections, symtab_section, section_vaddresses, section_entsize, num_sections, - (char *) out_img + ia64jmp_off, - ia64jmp_off + (char *) out_img + layout->ia64jmp_off, + layout->ia64jmp_off + image_target->vaddr_offset, image_target); - if (*start == 0) + if (layout->start_address == 0) grub_util_error ("start symbol is not defined"); - SUFFIX (entry_point) = (Elf_Addr) *start; + SUFFIX (entry_point) = (Elf_Addr) layout->start_address; /* Resolve addresses in the virtual address space. */ SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize, num_sections, strtab, - out_img, tramp_off, ia64_got_off, + out_img, layout->tramp_off, + layout->ia64_got_off, image_target); - *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, - section_vaddresses, sections, - section_entsize, num_sections, - strtab, ia64jmp_off - + image_target->vaddr_offset, - 2 * ia64jmpnum + (got / 8), - image_target); + make_reloc_section (e, layout, + section_vaddresses, sections, + section_entsize, num_sections, + strtab, layout->ia64jmp_off + + image_target->vaddr_offset, + 2 * layout->ia64jmpnum + (layout->got_size / 8), + image_target); } for (i = 0, s = sections; diff --git a/util/mkimage.c b/util/mkimage.c index 678b221..84b4823 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -740,17 +740,14 @@ grub_install_generate_image (const char *dir, const char *prefix, grub_compression_t comp) { char *kernel_img, *core_img; - size_t kernel_size, total_module_size, core_size, exec_size; + size_t total_module_size, core_size; size_t memdisk_size = 0, config_size = 0; size_t prefix_size = 0; char *kernel_path; size_t offset; struct grub_util_path_list *path_list, *p; - size_t bss_size; - grub_uint64_t start_address; - void *rel_section = 0; - size_t reloc_size = 0, align; size_t decompress_size = 0; + struct grub_mkimage_layout layout; if (comp == GRUB_COMPRESSION_AUTO) comp = image_target->default_compression; @@ -812,15 +809,13 @@ grub_install_generate_image (const char *dir, const char *prefix, (unsigned long long) total_module_size); if (image_target->voidp_sizeof == 4) - kernel_img = grub_mkimage_load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, - total_module_size, &start_address, &rel_section, - &reloc_size, &align, image_target); + kernel_img = grub_mkimage_load_image32 (kernel_path, total_module_size, + &layout, image_target); else - kernel_img = grub_mkimage_load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, - total_module_size, &start_address, &rel_section, - &reloc_size, &align, image_target); - if (image_target->id == IMAGE_XEN && align < 4096) - align = 4096; + kernel_img = grub_mkimage_load_image64 (kernel_path, total_module_size, + &layout, image_target); + if (image_target->id == IMAGE_XEN && layout.align < 4096) + layout.align = 4096; if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) && (image_target->total_module_size != TARGET_NO_FIELD)) @@ -829,7 +824,7 @@ grub_install_generate_image (const char *dir, const char *prefix, if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) { - memmove (kernel_img + total_module_size, kernel_img, kernel_size); + memmove (kernel_img + total_module_size, kernel_img, layout.kernel_size); memset (kernel_img, 0, total_module_size); } @@ -840,14 +835,14 @@ grub_install_generate_image (const char *dir, const char *prefix, if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) modinfo = (struct grub_module_info64 *) kernel_img; else - modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size); + modinfo = (struct grub_module_info64 *) (kernel_img + layout.kernel_size); modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64)); modinfo->size = grub_host_to_target_addr (total_module_size); if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) offset = sizeof (struct grub_module_info64); else - offset = kernel_size + sizeof (struct grub_module_info64); + offset = layout.kernel_size + sizeof (struct grub_module_info64); } else { @@ -856,14 +851,14 @@ grub_install_generate_image (const char *dir, const char *prefix, if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) modinfo = (struct grub_module_info32 *) kernel_img; else - modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size); + modinfo = (struct grub_module_info32 *) (kernel_img + layout.kernel_size); modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32)); modinfo->size = grub_host_to_target_addr (total_module_size); if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) offset = sizeof (struct grub_module_info32); else - offset = kernel_size + sizeof (struct grub_module_info32); + offset = layout.kernel_size + sizeof (struct grub_module_info32); } for (p = path_list; p; p = p->next) @@ -942,8 +937,8 @@ grub_install_generate_image (const char *dir, const char *prefix, grub_util_info ("kernel_img=%p, kernel_size=0x%" GRUB_HOST_PRIxLONG_LONG, kernel_img, - (unsigned long long) kernel_size); - compress_kernel (image_target, kernel_img, kernel_size + total_module_size, + (unsigned long long) layout.kernel_size); + compress_kernel (image_target, kernel_img, layout.kernel_size + total_module_size, &core_img, &core_size, comp); free (kernel_img); @@ -995,7 +990,7 @@ grub_install_generate_image (const char *dir, const char *prefix, if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD) *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_size)) - = grub_host_to_target32 (kernel_size + total_module_size); + = grub_host_to_target32 (layout.kernel_size + total_module_size); if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD) { @@ -1028,16 +1023,17 @@ grub_install_generate_image (const char *dir, const char *prefix, case IMAGE_I386_PC_ELTORITO: if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000 || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS)) - || (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)) + || (layout.kernel_size + layout.bss_size + + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)) grub_util_error (_("core image is too big (0x%x > 0x%x)"), GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size, 0x78000); /* fallthrough */ case IMAGE_COREBOOT: case IMAGE_QEMU: - if (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000) + if (layout.kernel_size + layout.bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000) grub_util_error (_("kernel image is too big (0x%x > 0x%x)"), - (unsigned) kernel_size + (unsigned) bss_size + (unsigned) layout.kernel_size + (unsigned) layout.bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR, 0x68000); break; @@ -1159,13 +1155,13 @@ grub_install_generate_image (const char *dir, const char *prefix, reloc_addr = ALIGN_UP (header_size + core_size, image_target->section_align); - pe_size = ALIGN_UP (reloc_addr + reloc_size, + pe_size = ALIGN_UP (reloc_addr + layout.reloc_size, image_target->section_align); - pe_img = xmalloc (reloc_addr + reloc_size); + pe_img = xmalloc (reloc_addr + layout.reloc_size); memset (pe_img, 0, header_size); memcpy ((char *) pe_img + header_size, core_img, core_size); memset ((char *) pe_img + header_size + core_size, 0, reloc_addr - (header_size + core_size)); - memcpy ((char *) pe_img + reloc_addr, rel_section, reloc_size); + memcpy ((char *) pe_img + reloc_addr, layout.reloc_section, layout.reloc_size); header = pe_img; /* The magic. */ @@ -1199,14 +1195,14 @@ grub_install_generate_image (const char *dir, const char *prefix, (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + sizeof (struct grub_pe32_coff_header)); o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); - o->code_size = grub_host_to_target32 (exec_size); - o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size - header_size); - o->bss_size = grub_cpu_to_le32 (bss_size); - o->entry_addr = grub_cpu_to_le32 (start_address); + o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); o->code_base = grub_cpu_to_le32 (header_size); - o->data_base = grub_host_to_target32 (header_size + exec_size); + o->data_base = grub_host_to_target32 (header_size + layout.exec_size); o->image_base = 0; o->section_alignment = grub_host_to_target32 (image_target->section_align); @@ -1224,7 +1220,7 @@ grub_install_generate_image (const char *dir, const char *prefix, o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); - o->base_relocation_table.size = grub_host_to_target32 (reloc_size); + o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); sections = o + 1; } else @@ -1237,11 +1233,11 @@ grub_install_generate_image (const char *dir, const char *prefix, (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + sizeof (struct grub_pe32_coff_header)); o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); - o->code_size = grub_host_to_target32 (exec_size); - o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size - header_size); - o->bss_size = grub_cpu_to_le32 (bss_size); - o->entry_addr = grub_cpu_to_le32 (start_address); + o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); o->code_base = grub_cpu_to_le32 (header_size); o->image_base = 0; o->section_alignment = grub_host_to_target32 (image_target->section_align); @@ -1260,15 +1256,15 @@ grub_install_generate_image (const char *dir, const char *prefix, = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); - o->base_relocation_table.size = grub_host_to_target32 (reloc_size); + o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); sections = o + 1; } /* The sections. */ text_section = sections; strcpy (text_section->name, ".text"); - text_section->virtual_size = grub_cpu_to_le32 (exec_size); + text_section->virtual_size = grub_cpu_to_le32 (layout.exec_size); text_section->virtual_address = grub_cpu_to_le32 (header_size); - text_section->raw_data_size = grub_cpu_to_le32 (exec_size); + text_section->raw_data_size = grub_cpu_to_le32 (layout.exec_size); text_section->raw_data_offset = grub_cpu_to_le32 (header_size); text_section->characteristics = grub_cpu_to_le32_compile_time ( GRUB_PE32_SCN_CNT_CODE @@ -1277,10 +1273,10 @@ grub_install_generate_image (const char *dir, const char *prefix, data_section = text_section + 1; strcpy (data_section->name, ".data"); - data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size); - data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size); - data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size); - data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size); + data_section->virtual_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); + data_section->virtual_address = grub_cpu_to_le32 (header_size + layout.exec_size); + data_section->raw_data_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); + data_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.exec_size); data_section->characteristics = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA | GRUB_PE32_SCN_MEM_READ @@ -1289,8 +1285,8 @@ grub_install_generate_image (const char *dir, const char *prefix, #if 0 bss_section = data_section + 1; strcpy (bss_section->name, ".bss"); - bss_section->virtual_size = grub_cpu_to_le32 (bss_size); - bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size); + bss_section->virtual_size = grub_cpu_to_le32 (layout.bss_size); + bss_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size); bss_section->raw_data_size = 0; bss_section->raw_data_offset = 0; bss_section->characteristics @@ -1303,10 +1299,10 @@ grub_install_generate_image (const char *dir, const char *prefix, mods_section = data_section + 1; strcpy (mods_section->name, "mods"); - mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size); - mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size); - mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size); - mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size); + mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); + mods_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size + layout.bss_size); + mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); + mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.kernel_size); mods_section->characteristics = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA | GRUB_PE32_SCN_MEM_READ @@ -1314,9 +1310,9 @@ grub_install_generate_image (const char *dir, const char *prefix, reloc_section = mods_section + 1; strcpy (reloc_section->name, ".reloc"); - reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size); - reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size); - reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size); + reloc_section->virtual_size = grub_cpu_to_le32 (layout.reloc_size); + reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + layout.bss_size); + reloc_section->raw_data_size = grub_cpu_to_le32 (layout.reloc_size); reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); reloc_section->characteristics = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA @@ -1587,7 +1583,7 @@ grub_install_generate_image (const char *dir, const char *prefix, target_addr = (image_target->link_addr - decompress_size); else target_addr = ALIGN_UP (image_target->link_addr - + kernel_size + total_module_size, 32); + + layout.kernel_size + total_module_size, 32); ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section)); grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section)); @@ -1634,16 +1630,16 @@ grub_install_generate_image (const char *dir, const char *prefix, target_addr = (image_target->link_addr - decompress_size); else target_addr = ALIGN_UP (image_target->link_addr - + kernel_size + total_module_size, 32); + + layout.kernel_size + total_module_size, 32); } else target_addr = image_target->link_addr; if (image_target->voidp_sizeof == 4) grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, - target_addr, align, kernel_size, bss_size); + target_addr, layout.align, layout.kernel_size, layout.bss_size); else grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, - target_addr, align, kernel_size, bss_size); + target_addr, layout.align, layout.kernel_size, layout.bss_size); } break; } @@ -1651,7 +1647,7 @@ grub_install_generate_image (const char *dir, const char *prefix, grub_util_write_image (core_img, core_size, out, outname); free (core_img); free (kernel_path); - free (rel_section); + free (layout.reloc_section); grub_util_free_path_list (path_list); } -- 2.7.0
From dc76d5c6eb07ddab8b20e71b1161fe3a72ca045f Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko <phco...@gmail.com> Date: Thu, 18 Feb 2016 20:57:21 +0100 Subject: [PATCH 4/6] Provide __bss_start and _end symbols in grub-mkimage. For this ensure that all bss sections are merged. We need this to correctly prelink non-PE relocatable images. --- include/grub/util/mkimage.h | 2 + util/grub-mkimagexx.c | 133 ++++++++++++++++++++++++++++---------------- 2 files changed, 87 insertions(+), 48 deletions(-) diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h index 8169939..25a49d5 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -33,6 +33,8 @@ struct grub_mkimage_layout grub_size_t ia64_got_off; grub_size_t got_size; unsigned ia64jmpnum; + Elf_Addr bss_start; + Elf_Addr end; }; /* Private header. Use only in mkimage-related sources. */ diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 74f86f5..433322d 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -490,6 +490,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Shdr *symtab_section, Elf_Addr *section_addresses, Elf_Half section_entsize, Elf_Half num_sections, void *jumpers, Elf_Addr jumpers_addr, + Elf_Addr bss_start, Elf_Addr end, const struct grub_install_image_target_desc *image_target) { Elf_Word symtab_size, sym_size, num_syms; @@ -528,16 +529,22 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, } else if (cur_index == STN_UNDEF) { - if (sym->st_name) + if (sym->st_name && grub_strcmp (name, "__bss_start")) + sym->st_value = bss_start; + else if (sym->st_name && grub_strcmp (name, "__end")) + sym->st_value = end; + else if (sym->st_name) grub_util_error ("undefined symbol %s", name); else continue; } else if (cur_index >= num_sections) grub_util_error ("section %d does not exist", cur_index); - - sym->st_value = (grub_target_to_host (sym->st_value) - + section_addresses[cur_index]); + else + { + sym->st_value = (grub_target_to_host (sym->st_value) + + section_addresses[cur_index]); + } if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) == STT_FUNC) @@ -1462,9 +1469,7 @@ SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_de == (SHF_EXECINSTR | SHF_ALLOC)); } -/* Determine if this section is a data section. This assumes that - BSS is also a data section, since the converter initializes BSS - when producing PE32 to avoid a bug in EFI implementations. */ +/* Determine if this section is a data section. */ static int SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) { @@ -1472,7 +1477,16 @@ SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_de && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) return 0; return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) - == SHF_ALLOC); + == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS); +} + +static int +SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target)) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS); } /* Return if the ELF header is valid. */ @@ -1492,6 +1506,32 @@ SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_i return 1; } +static Elf_Addr +SUFFIX (put_section) (Elf_Shdr *s, int i, + Elf_Addr current_address, + Elf_Addr *section_addresses, + const char *strtab, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%" + GRUB_HOST_PRIxLONG_LONG, + name, (unsigned long long) current_address); + if (!is_relocatable (image_target)) + current_address = grub_host_to_target_addr (s->sh_addr) + - image_target->link_addr; + section_addresses[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + return current_address; +} + /* Locate section addresses by merging code sections and data sections into .text and .data, respectively. Return the array of section addresses. */ @@ -1531,32 +1571,22 @@ SUFFIX (locate_sections) (const char *kernel_path, i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_text_section) (s, image_target)) { - Elf_Word align = grub_host_to_target_addr (s->sh_addralign); - const char *name = strtab + grub_host_to_target32 (s->sh_name); - if (align) - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, - align) - image_target->vaddr_offset; - grub_util_info ("locating the section %s at 0x%" - GRUB_HOST_PRIxLONG_LONG, - name, (unsigned long long) current_address); - if (image_target->id != IMAGE_EFI) + current_address = SUFFIX (put_section) (s, i, + current_address, + section_addresses, + strtab, + image_target); + if (!is_relocatable (image_target) && + grub_host_to_target_addr (s->sh_addr) != image_target->link_addr) { - current_address = grub_host_to_target_addr (s->sh_addr) - - image_target->link_addr; - if (grub_host_to_target_addr (s->sh_addr) - != image_target->link_addr) - { - char *msg - = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" - " instead of 0x%llx: ld.gold bug?"), - kernel_path, - (unsigned long long) grub_host_to_target_addr (s->sh_addr), - (unsigned long long) image_target->link_addr); - grub_util_error ("%s", msg); - } + char *msg + = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" + " instead of 0x%llx: ld.gold bug?"), + kernel_path, + (unsigned long long) grub_host_to_target_addr (s->sh_addr), + (unsigned long long) image_target->link_addr); + grub_util_error ("%s", msg); } - section_addresses[i] = current_address; - current_address += grub_host_to_target_addr (s->sh_size); } current_address = ALIGN_UP (current_address + image_target->vaddr_offset, @@ -1569,27 +1599,31 @@ SUFFIX (locate_sections) (const char *kernel_path, i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_data_section) (s, image_target)) - { - Elf_Word align = grub_host_to_target_addr (s->sh_addralign); - const char *name = strtab + grub_host_to_target32 (s->sh_name); + current_address = SUFFIX (put_section) (s, i, + current_address, + section_addresses, + strtab, + image_target); - if (align) - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, - align) - - image_target->vaddr_offset; + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) - image_target->vaddr_offset; - grub_util_info ("locating the section %s at 0x%" - GRUB_HOST_PRIxLONG_LONG, - name, (unsigned long long) current_address); - if (image_target->id != IMAGE_EFI) - current_address = grub_host_to_target_addr (s->sh_addr) - - image_target->link_addr; - section_addresses[i] = current_address; - current_address += grub_host_to_target_addr (s->sh_size); - } + layout->bss_start = current_address; + + /* .bss */ + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_bss_section) (s, image_target)) + current_address = SUFFIX (put_section) (s, i, + current_address, + section_addresses, + strtab, + image_target); current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; + layout->end = current_address; layout->kernel_size = current_address; return section_addresses; } @@ -1789,8 +1823,11 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_data_section) (s, image_target) + || SUFFIX (is_bss_section) (s, image_target) || SUFFIX (is_text_section) (s, image_target)) { + /* Explicitly initialize BSS + when producing PE32 to avoid a bug in EFI implementations. */ if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) memset (out_img + section_addresses[i], 0, grub_host_to_target_addr (s->sh_size)); -- 2.7.0
From d116b78258afc7664b0fbcae49bb5facbad08129 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko <phco...@gmail.com> Date: Thu, 18 Feb 2016 20:58:38 +0100 Subject: [PATCH 5/6] Allow _start == 0 with relocatable images --- util/grub-mkimagexx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 433322d..fff8112 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -495,7 +495,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, { Elf_Word symtab_size, sym_size, num_syms; Elf_Off symtab_offset; - Elf_Addr start_address = 0; + Elf_Addr start_address = (Elf_Addr) -1; Elf_Sym *sym; Elf_Word i; Elf_Shdr *strtab_section; @@ -560,7 +560,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, (unsigned long long) sym->st_value, (unsigned long long) section_addresses[cur_index]); - if (! start_address) + if (start_address == (Elf_Addr)-1) if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) start_address = sym->st_value; } @@ -1797,7 +1797,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, layout->ia64jmp_off + image_target->vaddr_offset, image_target); - if (layout->start_address == 0) + if (layout->start_address == (Elf_Addr) -1) grub_util_error ("start symbol is not defined"); SUFFIX (entry_point) = (Elf_Addr) layout->start_address; -- 2.7.0
From a20df5d8ffa95a8af7bbc175c4beff8454cc9875 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko <phco...@gmail.com> Date: Fri, 19 Feb 2016 00:43:36 +0100 Subject: [PATCH 6/6] arm-uboot: Make self-relocatable to allow loading at any address --- grub-core/Makefile.core.def | 2 +- grub-core/kern/arm/uboot/startup.S | 58 +++++-- include/grub/arm/uboot/kernel.h | 2 +- include/grub/offsets.h | 1 - include/grub/util/mkimage.h | 5 +- util/grub-mkimagexx.c | 313 +++++++++++++++++++++++++++++-------- util/mkimage.c | 8 +- 7 files changed, 303 insertions(+), 86 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 8874501..58b4208 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -90,7 +90,7 @@ kernel = { i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)'; emu_cflags = '$(CFLAGS_GNULIB)'; emu_cppflags = '$(CPPFLAGS_GNULIB)'; - arm_uboot_ldflags = '-Wl,-Ttext=0x08000000'; + arm_uboot_ldflags = '-Wl,-r,-d'; arm_uboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; i386_pc_startup = kern/i386/pc/startup.S; diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/uboot/startup.S index 0c4a5f6..5efaae1 100644 --- a/grub-core/kern/arm/uboot/startup.S +++ b/grub-core/kern/arm/uboot/startup.S @@ -55,10 +55,6 @@ FUNCTION(_start) VARIABLE(grub_total_module_size) .long 0 -VARIABLE(grub_uboot_machine_type) - .long 0 -VARIABLE(grub_uboot_boot_data) - .long 0 VARIABLE(grub_modbase) .long 0 bss_start_ptr: @@ -66,29 +62,66 @@ bss_start_ptr: end_ptr: .long EXT_C(_end) + @ Memory map at start: + @ * text+data + @ * list relocations + @ * modules + @ Before we enter C, we need to apply the relocations + @ and get following map: + @ * text+data + @ * BSS (cleared) + @ * stack + @ * modules + @ + @ To make things easier we ensure + @ that BSS+stack is larger than list of relocations + @ by increasing stack if necessarry. + @ This allows us to always unconditionally copy backwards + @ Currently list of relocations is ~5K and stack is set + @ to be at least 256K + FUNCTION(codestart) @ Store context: Machine ID, atags/dtb, ... @ U-Boot API signature is stored on the U-Boot heap @ Stack pointer used as start address for signature probing mov r12, sp adr sp, entry_state - push {r4-r12,lr} @ store U-Boot context (sp in r12) + push {r1-r12,lr} @ store U-Boot context (sp in r12) - str r1, EXT_C(grub_uboot_machine_type) - str r2, EXT_C(grub_uboot_boot_data) + adr r1, _start + ldr r0, bss_start_ptr @ src + add r0, r0, r1 - @ Modules have been stored as a blob in BSS, + add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + mvn r2, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + and r0, r0, r2 +1: + ldr r3, [r0], #4 @load next offset + @ both -2 and -1 are treated the same as we have only one type of relocs + @ -2 means "end of this type of relocs" and -1 means "end of all relocs" + add r2, r3, #2 + cmp r2, #1 + bls reloc_done + @ Adjust next offset + ldr r2, [r3, r1] + add r2, r2, r1 + str r2, [r3, r1] + b 1b + +reloc_done: + + @ Modules have been stored as a blob @ they need to be manually relocated to _end - ldr r0, bss_start_ptr @ src add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) - and r0, r0, r1 + and r0, r0, r1 @ src = aligned end of relocations ldr r1, end_ptr @ dst = End of BSS ldr r2, grub_total_module_size @ blob size add r1, r1, #GRUB_KERNEL_MACHINE_STACK_SIZE and r1, r1, #~0x7 @ Ensure 8-byte alignment + sub sp, r1, #8 add r1, r1, #1024 @@ -157,6 +190,11 @@ FUNCTION(grub_uboot_return) .align 3 @ U-boot context stack space entry_state_end: +VARIABLE(grub_uboot_machine_type) + .long 0 @ r1 +VARIABLE(grub_uboot_boot_data) + .long 0 @ r2 + .long 0 @ r3 .long 0 @ r4 .long 0 @ r5 .long 0 @ r6 diff --git a/include/grub/arm/uboot/kernel.h b/include/grub/arm/uboot/kernel.h index 06e5433..ce0b149 100644 --- a/include/grub/arm/uboot/kernel.h +++ b/include/grub/arm/uboot/kernel.h @@ -26,7 +26,7 @@ #endif /* ! ASM_FILE */ -#define GRUB_KERNEL_MACHINE_STACK_SIZE 0x40000 +#define GRUB_KERNEL_MACHINE_STACK_SIZE GRUB_KERNEL_ARM_STACK_SIZE #define GRUB_KERNEL_MACHINE_HEAP_SIZE (grub_size_t) (16 * 1024 * 1024) #endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/include/grub/offsets.h b/include/grub/offsets.h index 85e7401..3502a43 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -120,7 +120,6 @@ #define GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN 0x8 #define GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE 0x4 -#define GRUB_KERNEL_ARM_UBOOT_LINK_ADDR 0x08000000 /* Minimal gap between _end and the start of the modules. It's a hack for PowerMac to prevent "CLAIM failed" error. The real fix is to diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h index 25a49d5..2a48942 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -33,8 +33,8 @@ struct grub_mkimage_layout grub_size_t ia64_got_off; grub_size_t got_size; unsigned ia64jmpnum; - Elf_Addr bss_start; - Elf_Addr end; + grub_uint32_t bss_start; + grub_uint32_t end; }; /* Private header. Use only in mkimage-related sources. */ @@ -83,6 +83,7 @@ struct grub_install_image_target_desc unsigned decompressor_compressed_size; unsigned decompressor_uncompressed_size; unsigned decompressor_uncompressed_addr; + unsigned reloc_table_offset; unsigned link_align; grub_uint16_t elf_target; unsigned section_align; diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index fff8112..353a940 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -86,6 +86,12 @@ struct fixup_block_list #define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) +static int +is_relocatable (const struct grub_install_image_target_desc *image_target) +{ + return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT; +} + #ifdef MKIMAGE_ELF32 /* @@ -529,9 +535,9 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, } else if (cur_index == STN_UNDEF) { - if (sym->st_name && grub_strcmp (name, "__bss_start")) + if (sym->st_name && grub_strcmp (name, "__bss_start") == 0) sym->st_value = bss_start; - else if (sym->st_name && grub_strcmp (name, "__end")) + else if (sym->st_name && grub_strcmp (name, "_end") == 0) sym->st_value = end; else if (sym->st_name) grub_util_error ("undefined symbol %s", name); @@ -1008,7 +1014,8 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, grub_util_info (" ABS32:\toffset=%d\t(0x%08x)", (int) sym_addr, (int) sym_addr); /* Data will be naturally aligned */ - sym_addr += 0x400; + if (image_target->id == IMAGE_EFI) + sym_addr += 0x400; *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr); } break; @@ -1194,25 +1201,45 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, return current_address; } +struct raw_reloc +{ + struct raw_reloc *next; + grub_uint32_t offset; + enum raw_reloc_type { + RAW_RELOC_NONE = -1, + RAW_RELOC_32 = 0, + RAW_RELOC_MAX = 1, + } type; +}; + struct translate_context { + /* PE */ struct fixup_block_list *lst, *lst0; Elf_Addr current_address; + + /* Raw */ + struct raw_reloc *raw_relocs; }; static void -translate_reloc_start (struct translate_context *ctx) +translate_reloc_start (struct translate_context *ctx, + const struct grub_install_image_target_desc *image_target) { - ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000); - memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000); - ctx->current_address = 0; + grub_memset (ctx, 0, sizeof (*ctx)); + if (image_target->id == IMAGE_EFI) + { + ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000); + memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000); + ctx->current_address = 0; + } } static void -translate_relocation (struct translate_context *ctx, - Elf_Addr addr, - Elf_Addr info, - const struct grub_install_image_target_desc *image_target) +translate_relocation_pe (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) { /* Necessary to relocate only absolute addresses. */ switch (image_target->elf_target) @@ -1353,11 +1380,69 @@ translate_relocation (struct translate_context *ctx, } } +static enum raw_reloc_type +classify_raw_reloc (Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + /* Necessary to relocate only absolute addresses. */ + switch (image_target->elf_target) + { + case EM_ARM: + switch (ELF_R_TYPE (info)) + { + case R_ARM_V4BX: + case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_CALL: + return RAW_RELOC_NONE; + case R_ARM_ABS32: + return RAW_RELOC_32; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); + } +} + static void -finish_reloc_translation (struct translate_context *ctx, - struct grub_mkimage_layout *layout, +translate_relocation_raw (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, const struct grub_install_image_target_desc *image_target) { + enum raw_reloc_type class = classify_raw_reloc (info, image_target); + struct raw_reloc *rel; + if (class == RAW_RELOC_NONE) + return; + rel = xmalloc (sizeof (*rel)); + rel->next = ctx->raw_relocs; + rel->type = class; + rel->offset = addr; + ctx->raw_relocs = rel; +} + +static void +translate_relocation (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + if (image_target->id == IMAGE_EFI) + translate_relocation_pe (ctx, addr, info, image_target); + else + translate_relocation_raw (ctx, addr, info, image_target); +} + +static void +finish_reloc_translation_pe (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target); { @@ -1381,14 +1466,90 @@ finish_reloc_translation (struct translate_context *ctx, } layout->reloc_size = ctx->current_address; + if (image_target->elf_target == EM_ARM && layout->reloc_size > GRUB_KERNEL_ARM_STACK_SIZE) + grub_util_error ("Reloc section (%d) is bigger than stack size (%d). " + "This breaks assembly assumptions. Please increase stack size", + (int) layout->reloc_size, + (int) GRUB_KERNEL_ARM_STACK_SIZE); } +/* + Layout: + <type 0 relocations> + <fffffffe> + <type 1 relocations> + <fffffffe> + ... + <type n relocations> + <ffffffff> + each relocation starts with 32-bit offset. Rest depends on relocation. + mkimage stops when it sees first unknown type or end marker. + This allows images to be created with mismatched mkimage and + kernel as long as no relocations are present in kernel that mkimage + isn't aware of (in which case mkimage aborts). + This also allows simple assembly to do the relocs. +*/ + +#define RAW_SEPARATOR 0xfffffffe +#define RAW_END_MARKER 0xffffffff + +static void +finish_reloc_translation_raw (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + size_t count = 0, sz; + enum raw_reloc_type highest = RAW_RELOC_NONE; + enum raw_reloc_type curtype; + struct raw_reloc *cur; + grub_uint32_t *p; + if (!ctx->raw_relocs) + { + layout->reloc_section = p = xmalloc (sizeof (grub_uint32_t)); + p[0] = RAW_END_MARKER; + layout->reloc_size = sizeof (grub_uint32_t); + return; + } + for (cur = ctx->raw_relocs; cur; cur = cur->next) + { + count++; + if (cur->type > highest) + highest = cur->type; + } + /* highest separators, count relocations and one end marker. */ + sz = (highest + count + 1) * sizeof (grub_uint32_t); + layout->reloc_section = p = xmalloc (sz); + for (curtype = 0; curtype <= highest; curtype++) + { + /* Support for special cases would go here. */ + for (cur = ctx->raw_relocs; cur; cur = cur->next) + if (cur->type == curtype) + { + *p++ = cur->offset; + } + *p++ = RAW_SEPARATOR; + } + *--p = RAW_END_MARKER; + layout->reloc_size = sz; +} + +static void +finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + if (image_target->id == IMAGE_EFI) + finish_reloc_translation_pe (ctx, layout, image_target); + else + finish_reloc_translation_raw (ctx, layout, image_target); +} + + static void translate_reloc_jumpers (struct translate_context *ctx, Elf_Addr jumpers, grub_size_t njumpers, const struct grub_install_image_target_desc *image_target) { unsigned i; + assert (image_target->id == IMAGE_EFI); for (i = 0; i < njumpers; i++) ctx->current_address = add_fixup_entry (&ctx->lst, GRUB_PE32_REL_BASED_DIR64, @@ -1403,14 +1564,13 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, Elf_Addr *section_addresses, Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, const char *strtab, - Elf_Addr jumpers, grub_size_t njumpers, const struct grub_install_image_target_desc *image_target) { unsigned i; Elf_Shdr *s; struct translate_context ctx; - translate_reloc_start (&ctx); + translate_reloc_start (&ctx, image_target); for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) @@ -1451,7 +1611,10 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, } if (image_target->elf_target == EM_IA_64) - translate_reloc_jumpers (&ctx, jumpers, njumpers, + translate_reloc_jumpers (&ctx, + layout->ia64jmp_off + + image_target->vaddr_offset, + 2 * layout->ia64jmpnum + (layout->got_size / 8), image_target); finish_reloc_translation (&ctx, layout, image_target); @@ -1462,7 +1625,7 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, static int SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) { - if (image_target->id != IMAGE_EFI + if (!is_relocatable (image_target) && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) return 0; return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) @@ -1473,7 +1636,7 @@ SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_de static int SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) { - if (image_target->id != IMAGE_EFI + if (!is_relocatable (image_target) && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) return 0; return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) @@ -1536,14 +1699,13 @@ SUFFIX (put_section) (Elf_Shdr *s, int i, into .text and .data, respectively. Return the array of section addresses. */ static Elf_Addr * -SUFFIX (locate_sections) (const char *kernel_path, +SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path, Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, const char *strtab, struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target) { int i; - Elf_Addr current_address; Elf_Addr *section_addresses; Elf_Shdr *s; @@ -1555,7 +1717,7 @@ SUFFIX (locate_sections) (const char *kernel_path, section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); - current_address = 0; + layout->kernel_size = 0; for (i = 0, s = sections; i < num_sections; @@ -1571,8 +1733,8 @@ SUFFIX (locate_sections) (const char *kernel_path, i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_text_section) (s, image_target)) { - current_address = SUFFIX (put_section) (s, i, - current_address, + layout->kernel_size = SUFFIX (put_section) (s, i, + layout->kernel_size, section_addresses, strtab, image_target); @@ -1589,42 +1751,63 @@ SUFFIX (locate_sections) (const char *kernel_path, } } - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - layout->exec_size = current_address; + layout->exec_size = layout->kernel_size; /* .data */ for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_data_section) (s, image_target)) - current_address = SUFFIX (put_section) (s, i, - current_address, + layout->kernel_size = SUFFIX (put_section) (s, i, + layout->kernel_size, section_addresses, strtab, image_target); - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, - image_target->section_align) - image_target->vaddr_offset; +#ifdef MKIMAGE_ELF32 + if (image_target->elf_target == EM_ARM) + { + grub_size_t tramp; + layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, + image_target->section_align) - image_target->vaddr_offset; - layout->bss_start = current_address; + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + tramp = arm_get_trampoline_size (e, sections, section_entsize, + num_sections, image_target); + + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); + } +#endif + + layout->bss_start = layout->kernel_size; + layout->end = layout->kernel_size; /* .bss */ for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_bss_section) (s, image_target)) - current_address = SUFFIX (put_section) (s, i, - current_address, - section_addresses, - strtab, - image_target); + layout->end = SUFFIX (put_section) (s, i, + layout->end, + section_addresses, + strtab, + image_target); - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - layout->end = current_address; - layout->kernel_size = current_address; + /* Explicitly initialize BSS + when producing PE32 to avoid a bug in EFI implementations. + Platforms other than EFI and U-boot shouldn't have .bss in + their binaries as we build with -Wl,-Ttext. + */ + if (image_target->id != IMAGE_UBOOT) + layout->kernel_size = layout->end; + return section_addresses; } @@ -1674,7 +1857,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, + grub_host_to_target16 (e->e_shstrndx) * section_entsize); strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); - section_addresses = SUFFIX (locate_sections) (kernel_path, + section_addresses = SUFFIX (locate_sections) (e, kernel_path, sections, section_entsize, num_sections, strtab, layout, @@ -1685,7 +1868,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, for (i = 0; i < num_sections; i++) section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; - if (image_target->id != IMAGE_EFI) + if (!is_relocatable (image_target)) { Elf_Addr current_address = layout->kernel_size; @@ -1706,7 +1889,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, grub_util_info ("locating the section %s at 0x%" GRUB_HOST_PRIxLONG_LONG, name, (unsigned long long) current_address); - if (image_target->id != IMAGE_EFI) + if (!is_relocatable (image_target)) current_address = grub_host_to_target_addr (s->sh_addr) - image_target->link_addr; @@ -1724,10 +1907,11 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, if (image_target->id == IMAGE_SPARC64_AOUT || image_target->id == IMAGE_SPARC64_RAW + || image_target->id == IMAGE_UBOOT || image_target->id == IMAGE_SPARC64_CDCORE) layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align); - if (image_target->id == IMAGE_EFI) + if (is_relocatable (image_target)) { symtab_section = NULL; for (i = 0, s = sections; @@ -1740,22 +1924,6 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, } if (! symtab_section) grub_util_error ("%s", _("no symbol table")); - -#ifdef MKIMAGE_ELF32 - if (image_target->elf_target == EM_ARM) - { - grub_size_t tramp; - - layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); - - tramp = arm_get_trampoline_size (e, sections, section_entsize, - num_sections, image_target); - - layout->tramp_off = layout->kernel_size; - layout->kernel_size += ALIGN_UP (tramp, 16); - } -#endif - #ifdef MKIMAGE_ELF64 if (image_target->elf_target == EM_IA_64) { @@ -1770,14 +1938,13 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, layout->ia64jmp_off = layout->kernel_size; layout->ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section, - image_target); + image_target); layout->kernel_size += 16 * layout->ia64jmpnum; layout->ia64_got_off = layout->kernel_size; layout->kernel_size += ALIGN_UP (layout->got_size, 16); } #endif - } else { @@ -1788,7 +1955,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, out_img = xmalloc (layout->kernel_size + total_module_size); memset (out_img, 0, layout->kernel_size + total_module_size); - if (image_target->id == IMAGE_EFI) + if (is_relocatable (image_target)) { layout->start_address = SUFFIX (relocate_symbols) (e, sections, symtab_section, section_vaddresses, section_entsize, @@ -1796,6 +1963,8 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, (char *) out_img + layout->ia64jmp_off, layout->ia64jmp_off + image_target->vaddr_offset, + layout->bss_start, + layout->end, image_target); if (layout->start_address == (Elf_Addr) -1) grub_util_error ("start symbol is not defined"); @@ -1813,21 +1982,31 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, make_reloc_section (e, layout, section_vaddresses, sections, section_entsize, num_sections, - strtab, layout->ia64jmp_off - + image_target->vaddr_offset, - 2 * layout->ia64jmpnum + (layout->got_size / 8), + strtab, image_target); + if (image_target->id != IMAGE_EFI) + { + out_img = xrealloc (out_img, layout->kernel_size + total_module_size + + ALIGN_UP (layout->reloc_size, image_target->mod_align)); + memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size); + memset (out_img + layout->kernel_size + layout->reloc_size, 0, + total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size); + layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align); + } } for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_data_section) (s, image_target) - || SUFFIX (is_bss_section) (s, image_target) + /* Explicitly initialize BSS + when producing PE32 to avoid a bug in EFI implementations. + Platforms other than EFI and U-boot shouldn't have .bss in + their binaries as we build with -Wl,-Ttext. + */ + || (SUFFIX (is_bss_section) (s, image_target) && (image_target->id != IMAGE_UBOOT)) || SUFFIX (is_text_section) (s, image_target)) { - /* Explicitly initialize BSS - when producing PE32 to avoid a bug in EFI implementations. */ if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) memset (out_img + section_addresses[i], 0, grub_host_to_target_addr (s->sh_size)); diff --git a/util/mkimage.c b/util/mkimage.c index 84b4823..06d28e7 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -86,6 +86,7 @@ static const struct grub_install_image_target_desc image_targets[] = .decompressor_compressed_size = TARGET_NO_FIELD, .decompressor_uncompressed_size = TARGET_NO_FIELD, .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .reloc_table_offset = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, @@ -525,7 +526,6 @@ static const struct grub_install_image_target_desc image_targets[] = .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN, .vaddr_offset = 0, - .link_addr = GRUB_KERNEL_ARM_UBOOT_LINK_ADDR, .elf_target = EM_ARM, .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP, .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN, @@ -1520,9 +1520,9 @@ grub_install_generate_image (const char *dir, const char *prefix, hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC); hdr->ih_time = grub_cpu_to_be32 (STABLE_EMBEDDING_TIMESTAMP); hdr->ih_size = grub_cpu_to_be32 (core_size); - hdr->ih_load = grub_cpu_to_be32 (image_target->link_addr); - hdr->ih_ep = grub_cpu_to_be32 (image_target->link_addr); - hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL; + hdr->ih_load = 0; + hdr->ih_ep = 0; + hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL_NOLOAD; hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX; hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM; hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE; -- 2.7.0
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel