grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 6/7] mkimage: support images which require full relocation at mki


From: Ian Campbell
Subject: [PATCH 6/7] mkimage: support images which require full relocation at mkimage time.
Date: Sun, 29 Dec 2013 18:47:35 +0000

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 <address@hidden>
---
 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]