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

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to