grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
From: Ian Campbell <ijc@hellion.org.uk>
To: grub-devel@gnu.org
Cc: Vladimir Serbinenko <phcoder@gmail.com>,
	Leif Lindholm <leif.lindholm@linaro.org>,
	Ian Campbell <ijc@hellion.org.uk>
Subject: [PATCH 6/7] mkimage: support images which require full relocation at mkimage time.
Date: Sun, 29 Dec 2013 18:47:35 +0000	[thread overview]
Message-ID: <1388342856-18317-6-git-send-email-ijc@hellion.org.uk> (raw)
In-Reply-To: <1388342839.32105.25.camel@hastur.hellion.org.uk>

To do so support the specification of a "target_address" (which must be 0 for
image types which do not have this flag) and a new image flag to signal the
need for absolute relocation. If this flag is present then image->link_addr is
the default target.

Account for the target address when relocating.

Fabricate correct addresses for absolute symbols relating to the bss
("__bss_start" and "_end").

This functionality is not yet used by any image type and is connected only to
grub-mkimage ("-T option) and not yet to grub-install.

Signed-off-by: Ian Campbell <ijc@hellion.org.uk>
---
 include/grub/util/install.h |  2 +-
 util/grub-install-common.c  |  4 +--
 util/grub-mkimage.c         |  7 +++++
 util/grub-mkimagexx.c       | 74 +++++++++++++++++++++++++++++++--------------
 util/mkimage.c              | 24 ++++++++++++---
 5 files changed, 81 insertions(+), 30 deletions(-)

diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index bc987aa..b7ecf27 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -167,7 +167,7 @@ struct grub_install_image_target_desc;
 
 void
 grub_install_generate_image (const char *dir, const char *prefix,
-			     FILE *out,
+			     FILE *out, grub_uint64_t target_address,
 			     const char *outname, char *mods[],
 			     char *memdisk_path, char **pubkey_paths,
 			     size_t npubkeys,
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index ae26875..82a44f2 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -495,8 +495,8 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
   if (!tgt)
     grub_util_error (_("unknown target format %s\n"), mkimage_target);
 
-  grub_install_generate_image (dir, prefix, fp, outname,
-			       modules.entries, memdisk_path,
+  grub_install_generate_image (dir, prefix, fp, 0,
+			       outname, modules.entries, memdisk_path,
 			       pubkeys, npubkeys, config_path, tgt,
 			       note, compression);
   while (dc--)
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index a2bd4c1..267beaa 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -65,6 +65,7 @@ static struct argp_option options[] = {
    /* TRANSLATORS: platform here isn't identifier. It can be translated.  */
    N_("use images and modules under DIR [default=%s/<platform>]"), 0},
   {"prefix",  'p', N_("DIR"), 0, N_("set prefix directory [default=%s]"), 0},
+  {"target-address", 'T', N_("ADDR"), 0, N_("set kernel target address [default=%d]"), 0},
   {"memdisk",  'm', N_("FILE"), 0,
    /* TRANSLATORS: "memdisk" here isn't an identifier, it can be translated.
     "embed" is a verb (command description).  "*/
@@ -126,6 +127,7 @@ struct arguments
   int note;
   const struct grub_install_image_target_desc *image_target;
   grub_compression_t comp;
+  grub_uint64_t target_address;
 };
 
 static error_t
@@ -217,6 +219,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
       arguments->prefix = xstrdup (arg);
       break;
 
+    case 'T':
+      arguments->target_address = strtoull (arg, NULL, 0);
+      break;
+
     case 'v':
       verbosity++;
       break;
@@ -289,6 +295,7 @@ main (int argc, char *argv[])
 
   grub_install_generate_image (arguments.dir,
 			       arguments.prefix ? : DEFAULT_DIRECTORY, fp,
+			       arguments.target_address,
 			       arguments.output, arguments.modules,
 			       arguments.memdisk, arguments.pubkeys,
 			       arguments.npubkeys, arguments.config,
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index b4216ff..186d259 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -378,6 +378,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_addr, size_t bss_size,
 			   const struct grub_install_image_target_desc *image_target)
 {
   Elf_Word symtab_size, sym_size, num_syms;
@@ -416,10 +417,14 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
         }
       else if (cur_index == STN_UNDEF)
 	{
-	  if (sym->st_name)
+	  if (strcmp (name, "__bss_start") == 0 && bss_addr)
+	      sym->st_value = bss_addr;
+	  else if (strcmp (name, "_end") == 0 && bss_addr)
+	      sym->st_value = bss_addr + bss_size;
+	  else if (sym->st_name)
 	    grub_util_error ("undefined symbol %s", name);
-	  else
-	    continue;
+
+	  continue;
 	}
       else if (cur_index >= num_sections)
 	grub_util_error ("section %d does not exist", cur_index);
@@ -584,7 +589,7 @@ static void
 SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
 			     Elf_Addr *section_addresses,
 			     Elf_Half section_entsize, Elf_Half num_sections,
-			     const char *strtab,
+			     const char *strtab, grub_uint64_t target_address,
 			     char *pe_target, Elf_Addr tramp_off,
 			     Elf_Addr got_off,
 			     const struct grub_install_image_target_desc *image_target)
@@ -867,6 +872,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
 		   {
 		   case R_ARM_ABS32:
 		     {
+		       sym_addr += target_address;
 		       grub_util_info ("  ABS32:\ttarget=0x%08lx\toffset=(0x%08x)",
 				       (unsigned long) ((char *) target
 							- (char *) e),
@@ -928,7 +934,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
 			   grub_uint32_t tr_addr;
 			   grub_int32_t new_offset;
 			   tr_addr = (char *) tr - (char *) pe_target
-			     - target_section_addr;
+			     - (target_address - target_section_addr);
 			   new_offset = sym_addr - tr_addr - 12;
 
 			   /* There is no immediate version of bx, only register one...  */
@@ -1337,6 +1343,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,
+			  grub_uint64_t target_address,
 			  size_t *exec_size, size_t *kernel_sz,
 			  size_t *all_align,
 			  const struct grub_install_image_target_desc *image_target)
@@ -1351,7 +1358,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;
+  current_address = target_address;
 
   for (i = 0, s = sections;
        i < num_sections;
@@ -1391,6 +1398,15 @@ SUFFIX (locate_sections) (const char *kernel_path,
 		grub_util_error ("%s", msg);
 	      }
 	  }
+	else if (!grub_image_needs_abs_reloc(image_target))
+	  {
+	    if (grub_host_to_target_addr (s->sh_addr))
+	      grub_util_error (_("`%s' is miscompiled: its start address is 0x%llx"
+				 " but this platform uses late relocation"),
+			       kernel_path,
+			       (unsigned long long) grub_host_to_target_addr (s->sh_addr));
+	  }
+
 	section_addresses[i] = current_address;
 	current_address += grub_host_to_target_addr (s->sh_size);
       }
@@ -1398,7 +1414,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;
+  *exec_size = current_address - target_address;
 
   /* .data */
   for (i = 0, s = sections;
@@ -1426,14 +1442,15 @@ 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;
+  *kernel_sz = current_address - target_address;
   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,
+		     size_t total_module_size, grub_uint64_t target_address,
+		     grub_uint64_t *start,
 		     void **reloc_section, size_t *reloc_size,
 		     size_t *align,
 		     const struct grub_install_image_target_desc *image_target)
@@ -1444,6 +1461,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
   Elf_Shdr *sections;
   Elf_Addr *section_addresses;
   Elf_Addr *section_vaddresses;
+  Elf_Addr bss_addr = 0;
   int i;
   Elf_Shdr *s;
   Elf_Half num_sections;
@@ -1455,6 +1473,9 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
   Elf_Shdr *symtab_section = 0;
   grub_size_t got = 0;
 
+  if (target_address && !grub_image_needs_abs_reloc(image_target))
+    grub_util_error("cannot perform absolute relocation for this image type");
+
   *start = 0;
 
   kernel_size = grub_util_get_image_size (kernel_path);
@@ -1481,7 +1502,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
 
   section_addresses = SUFFIX (locate_sections) (kernel_path,
 						sections, section_entsize,
-						num_sections, strtab,
+						num_sections, strtab, target_address,
 						exec_size, kernel_sz, align,
 						image_target);
 
@@ -1530,9 +1551,9 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
   for (i = 0; i < num_sections; i++)
     section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset;
 
-  if (!grub_image_needs_reloc(image_target))
+  if (!grub_image_needs_reloc(image_target) || grub_image_needs_abs_reloc(image_target))
     {
-      Elf_Addr current_address = *kernel_sz;
+      Elf_Addr current_address = target_address + *kernel_sz;
 
       for (i = 0, s = sections;
 	   i < num_sections;
@@ -1558,11 +1579,16 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
 	    section_vaddresses[i] = current_address
 	      + image_target->vaddr_offset;
 	    current_address += grub_host_to_target_addr (s->sh_size);
+
+	    if (!bss_addr)
+	      bss_addr = section_vaddresses[i];
 	  }
       current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
 				  image_target->section_align)
 	- image_target->vaddr_offset;
-      *bss_size = current_address - *kernel_sz;
+      *bss_size = current_address - *kernel_sz - target_address;
+      grub_util_info ("locating bss at 0x%x-0x%x (0x%x bytes)",
+		      (int)bss_addr, (int)(bss_addr + *bss_size), (int)*bss_size);
     }
   else
     *bss_size = 0;
@@ -1603,6 +1629,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
 					  (char *) out_img + ia64jmp_off, 
 					  ia64jmp_off 
 					  + image_target->vaddr_offset,
+					  bss_addr, *bss_size,
 					  image_target);
       if (*start == INVALID_START_ADDR)
 	grub_util_error ("start symbol is not defined");
@@ -1612,17 +1639,18 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
       /* Resolve addresses in the virtual address space.  */
       SUFFIX (relocate_addresses) (e, sections, section_addresses, 
 				   section_entsize,
-				   num_sections, strtab,
+				   num_sections, strtab, target_address,
 				   out_img, tramp_off, 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);
+      if (!grub_image_needs_abs_reloc(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);
     }
 
   for (i = 0, s = sections;
@@ -1632,10 +1660,10 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
 	|| SUFFIX (is_text_section) (s, image_target))
       {
 	if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
-	  memset (out_img + section_addresses[i], 0,
+	  memset (out_img + section_addresses[i] - target_address, 0,
 		  grub_host_to_target_addr (s->sh_size));
 	else
-	  memcpy (out_img + section_addresses[i],
+	  memcpy (out_img + section_addresses[i] - target_address,
 		  kernel_img + grub_host_to_target_addr (s->sh_offset),
 		  grub_host_to_target_addr (s->sh_size));
       }
diff --git a/util/mkimage.c b/util/mkimage.c
index 645e296..7b29acf 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -74,6 +74,7 @@ struct grub_install_image_target_desc
       PLATFORM_FLAGS_NONE = 0,
       PLATFORM_FLAGS_DECOMPRESSORS = 2,
       PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4,
+      PLATFORM_FLAGS_ABS_RELOC = 8,
     } flags;
   unsigned total_module_size;
   unsigned decompressor_compressed_size;
@@ -922,11 +923,16 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
   return GRUB_ERR_NONE;
 }
 
+static int grub_image_needs_abs_reloc(const struct grub_install_image_target_desc *target)
+{
+  return target->flags & PLATFORM_FLAGS_ABS_RELOC;
+}
+
 static int grub_image_needs_reloc(const struct grub_install_image_target_desc *target)
 {
   if (target->id == IMAGE_EFI)
     return 1;
-  return 0;
+  return grub_image_needs_abs_reloc(target);
 }
 
 #pragma GCC diagnostic ignored "-Wcast-align"
@@ -987,7 +993,8 @@ grub_install_get_image_targets_string (void)
 
 void
 grub_install_generate_image (const char *dir, const char *prefix,
-			     FILE *out, const char *outname, char *mods[],
+			     FILE *out, grub_uint64_t target_address,
+			     const char *outname, char *mods[],
 			     char *memdisk_path, char **pubkey_paths,
 			     size_t npubkeys, char *config_path,
 			     const struct grub_install_image_target_desc *image_target,
@@ -1024,6 +1031,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
   else
     total_module_size = sizeof (struct grub_module_info32);
 
+  if (!target_address && grub_image_needs_abs_reloc(image_target))
+    {
+      grub_util_info ("Using default target address 0x%llx",
+		      (unsigned long long)image_target->link_addr);
+      target_address = image_target->link_addr;
+    }
+
   {
     size_t i;
     for (i = 0; i < npubkeys; i++)
@@ -1069,11 +1083,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
 
   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,
+			       total_module_size, target_address,
+			       &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,
+			       total_module_size, target_address,
+			       &start_address, &rel_section,
 			       &reloc_size, &align, image_target);
   if (image_target->id == IMAGE_XEN && align < 4096)
     align = 4096;
-- 
1.8.4.rc3



  parent reply	other threads:[~2013-12-29 18:48 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-29 18:47 [PATCH 0/7] arm-uboot: support for different RAM bases Ian Campbell
2013-12-29 18:47 ` [PATCH 1/7] mkimage: Refactor IMAGE_EFI checks into a function grub_image_needs_reloc Ian Campbell
2013-12-29 18:47 ` [PATCH 2/7] mkimage: Replace hardcoded 0x400 in R_ARM_ABS32 relocation Ian Campbell
2013-12-29 18:47 ` [PATCH 3/7] mkimage: account for space for trampolines earlier Ian Campbell
2013-12-29 18:47 ` [PATCH 4/7] mkimage: make R_ARM_ABS32 debug output more consistent Ian Campbell
2013-12-29 18:47 ` [PATCH 5/7] mkimage: allow linking at address 0 Ian Campbell
2013-12-29 18:47 ` Ian Campbell [this message]
2013-12-29 22:53   ` [PATCH 6/7] mkimage: support images which require full relocation at mkimage time Leif Lindholm
2013-12-30  3:49     ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-12-30 10:54     ` Ian Campbell
2013-12-30 15:46   ` Andrey Borzenkov
2013-12-31 14:19   ` Francesco Lavra
2013-12-31 16:44     ` Ian Campbell
2013-12-29 18:47 ` [PATCH 7/7] arm-uboot: support relocation at installation time Ian Campbell
2013-12-29 19:10 ` [PATCH 0/7] arm-uboot: support for different RAM bases Ian Campbell
2013-12-29 23:04 ` Leif Lindholm
2013-12-30  1:55 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-12-30 10:48   ` Ian Campbell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1388342856-18317-6-git-send-email-ijc@hellion.org.uk \
    --to=ijc@hellion.org.uk \
    --cc=grub-devel@gnu.org \
    --cc=leif.lindholm@linaro.org \
    --cc=phcoder@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).