]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Unify GOT/trampoline handling between PPC, MIPS and IA64 as they
authorVladimir Serbinenko <phcoder@gmail.com>
Thu, 21 Nov 2013 20:54:33 +0000 (21:54 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Thu, 21 Nov 2013 20:54:33 +0000 (21:54 +0100)
do essentially the same thing, do it in similar way.

ChangeLog
grub-core/kern/dl.c
grub-core/kern/emu/full.c
grub-core/kern/ia64/dl_helper.c
grub-core/kern/mips/dl.c
grub-core/kern/powerpc/dl.c
include/grub/dl.h
util/grub-mkimagexx.c

index 6d4b5b21050f06b33eaa455f39c527ef0fcd280f..b94054a5a1896707d3c01bfd2853658de1ed0868 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-11-21  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Unify GOT/trampoline handling between PPC, MIPS and IA64 as they
+       do essentially the same thing, do it in similar way.
+
 2013-11-21  Colin Watson  <cjwatson@ubuntu.com>
 
        * util/grub-mkrescue.c (main): If a source directory is not
index ccbd5bac4418b1650bf8b917a601470807bd2301..1d6841479f620ccea968a7af6986396a524ad3fa 100644 (file)
@@ -229,9 +229,10 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
   unsigned i;
   Elf_Shdr *s;
   grub_size_t tsize = 0, talign = 1;
-#if defined (__ia64__) || defined (__powerpc__)
+#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
   grub_size_t tramp;
   grub_size_t got;
+  grub_err_t err;
 #endif
   char *ptr;
 
@@ -244,10 +245,10 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
        talign = s->sh_addralign;
     }
 
-#if defined (__ia64__) || defined (__powerpc__)
-  grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
-  tramp *= GRUB_ARCH_DL_TRAMP_SIZE;
-  got *= sizeof (grub_uint64_t);
+#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
+  err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
+  if (err)
+    return err;
   tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
   if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
     talign = GRUB_ARCH_DL_TRAMP_ALIGN;
@@ -313,7 +314,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
          mod->segment = seg;
        }
     }
-#if defined (__ia64__) || defined (__powerpc__)
+#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
   ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
   mod->tramp = ptr;
   ptr += tramp;
index 97d59fd32678fbbced1161117dc1ab43583de69d..8034c637b0000cdaf9f6da78db7a03e7da71a432 100644 (file)
@@ -46,7 +46,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
   return GRUB_ERR_BAD_MODULE;
 }
 
-#if defined (__ia64__) || defined (__powerpc__)
+#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
 void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
                                      grub_size_t *tramp, grub_size_t *got)
 {
index e2209ca0a0761a508d567650ff2f57a01a4b5af3..515e323ad7e7ddea652c0b20f601ff5c882220cd 100644 (file)
@@ -170,7 +170,7 @@ grub_ia64_make_trampoline (struct grub_ia64_trampoline *tr, grub_uint64_t addr)
   grub_memcpy (tr->jump, jump, sizeof (tr->jump));
 }
 
-void
+grub_err_t
 grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
                                 grub_size_t *got)
 {
@@ -187,7 +187,7 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
       break;
 
   if (i == grub_le_to_cpu16 (e->e_shnum))
-    return;
+    return GRUB_ERR_NONE;
 
   for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu64 (e->e_shoff));
        i < grub_le_to_cpu16 (e->e_shnum);
@@ -211,7 +211,9 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
              break;
            }
       }
-  *tramp = cntt;
-  *got = cntg;
+  *tramp = cntt * sizeof (struct grub_ia64_trampoline);
+  *got = cntg * sizeof (grub_uint64_t);
+
+  return GRUB_ERR_NONE;
 }
 
index ee65c9d18ca8ec0ca24e00cdbd7978a5089b342b..36ca9a2259fc774ff513bf67c1e3f98efe2a7db9 100644 (file)
@@ -51,6 +51,58 @@ grub_arch_dl_check_header (void *ehdr)
 
 #pragma GCC diagnostic ignored "-Wcast-align"
 
+grub_err_t
+grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
+                                grub_size_t *got)
+{
+  const Elf_Ehdr *e = ehdr;
+  const Elf_Shdr *s;
+  unsigned i;
+  /* FIXME: suboptimal.  */
+  grub_size_t gp_size = 0;
+
+  *tramp = 0;
+  *got = 0;
+
+  /* Find a symbol table.  */
+  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_SYMTAB)
+      break;
+
+  if (i == e->e_shnum)
+    return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
+
+  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_REL)
+      {
+       const Elf_Rel *rel, *max;
+
+       for (rel = (const Elf_Rel *) ((const char *) e + s->sh_offset),
+              max = rel + s->sh_size / s->sh_entsize;
+            rel < max;
+            rel++)
+         switch (ELF_R_TYPE (rel->r_info))
+           {
+           case R_MIPS_GOT16:
+           case R_MIPS_CALL16:
+           case R_MIPS_GPREL32:
+             gp_size += 4;
+             break;
+           }
+      }
+
+  if (gp_size > 0x08000)
+    return grub_error (GRUB_ERR_OUT_OF_RANGE, "__gnu_local_gp is too big\n");
+
+  *got = gp_size;
+
+  return GRUB_ERR_NONE;
+}
+
 /* Relocate symbols.  */
 grub_err_t
 grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
@@ -59,7 +111,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
   Elf_Shdr *s;
   Elf_Word entsize;
   unsigned i;
-  grub_size_t gp_size = 0;
   /* FIXME: suboptimal.  */
   grub_uint32_t *gp, *gpptr;
   grub_uint32_t gp0;
@@ -88,43 +139,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
 
   gp0 = ((grub_uint32_t *)((char *) e + s->sh_offset))[5];
 
-  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
-       i < e->e_shnum;
-       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
-    if (s->sh_type == SHT_REL)
-      {
-       grub_dl_segment_t seg;
-
-       /* Find the target segment.  */
-       for (seg = mod->segment; seg; seg = seg->next)
-         if (seg->section == s->sh_info)
-           break;
-
-       if (seg)
-         {
-           Elf_Rel *rel, *max;
-
-           for (rel = (Elf_Rel *) ((char *) e + s->sh_offset),
-                  max = rel + s->sh_size / s->sh_entsize;
-                rel < max;
-                rel++)
-               switch (ELF_R_TYPE (rel->r_info))
-                 {
-                 case R_MIPS_GOT16:
-                 case R_MIPS_CALL16:
-                 case R_MIPS_GPREL32:
-                   gp_size += 4;
-                   break;
-                 }
-         }
-      }
-
-  if (gp_size > 0x08000)
-    return grub_error (GRUB_ERR_OUT_OF_RANGE, "__gnu_local_gp is too big\n");
-
-  gpptr = gp = grub_malloc (gp_size);
-  if (!gp)
-    return grub_errno;
+  gpptr = gp = mod->got;
 
   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
        i < e->e_shnum;
@@ -234,7 +249,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
                    break;
                  default:
                    {
-                     grub_free (gp);
                      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
                                         N_("relocation 0x%x is not implemented yet"),
                                         ELF_R_TYPE (rel->r_info));
index 8f77b6547a50ef383cfb55b178b036cc7cae3049..e874234389b6ae653fa4a0f664c2184d4a62e0bf 100644 (file)
@@ -38,9 +38,26 @@ grub_arch_dl_check_header (void *ehdr)
   return GRUB_ERR_NONE;
 }
 
+/* For low-endian reverse lis and addr_high as well as ori and addr_low. */
+struct trampoline
+{
+  grub_uint32_t lis;
+  grub_uint32_t ori;
+  grub_uint32_t mtctr;
+  grub_uint32_t bctr;
+};
+
+static const struct trampoline trampoline_template = 
+  {
+    0x3d800000,
+    0x618c0000,
+    0x7d8903a6,
+    0x4e800420,
+  };
+
 #pragma GCC diagnostic ignored "-Wcast-align"
 
-void
+grub_err_t
 grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
                                 grub_size_t *got)
 {
@@ -59,7 +76,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
       break;
 
   if (i == e->e_shnum)
-    return;
+    return GRUB_ERR_NONE;
 
   for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
        i < e->e_shnum;
@@ -77,25 +94,10 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
        
       }
 
-  return;
-}
+  *tramp *= sizeof (struct trampoline);
 
-/* For low-endian reverse lis and addr_high as well as ori and addr_low. */
-struct trampoline
-{
-  grub_uint32_t lis;
-  grub_uint32_t ori;
-  grub_uint32_t mtctr;
-  grub_uint32_t bctr;
-};
-
-static const struct trampoline trampoline_template = 
-  {
-    0x3d800000,
-    0x618c0000,
-    0x7d8903a6,
-    0x4e800420,
-  };
+  return GRUB_ERR_NONE;
+}
 
 /* Relocate symbols.  */
 grub_err_t
@@ -167,8 +169,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
 
                      if (delta << 6 >> 6 != delta)
                        {
-                         COMPILE_TIME_ASSERT (sizeof (struct trampoline)
-                                              == GRUB_ARCH_DL_TRAMP_SIZE);
                          grub_memcpy (tptr, &trampoline_template,
                                       sizeof (*tptr));
                          delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
index 3dc88c75c2b41aaa46f2a4bc95b922f51abf32ea..11fc7756888e19e7bb916af977f3c6977569527a 100644 (file)
@@ -179,7 +179,7 @@ struct grub_dl
   Elf_Sym *symtab;
   void (*init) (struct grub_dl *mod);
   void (*fini) (void);
-#if defined (__ia64__) || defined (__powerpc__)
+#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
   void *got;
   void *tramp;
 #endif
@@ -243,23 +243,21 @@ void grub_arch_dl_init_linker (void);
 #define GRUB_IA64_DL_TRAMP_SIZE 48
 #define GRUB_IA64_DL_GOT_ALIGN 16
 
-void
+grub_err_t
 grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
                                 grub_size_t *got);
 
 #if defined (__ia64__)
 #define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN
 #define GRUB_ARCH_DL_GOT_ALIGN GRUB_IA64_DL_GOT_ALIGN
-#define GRUB_ARCH_DL_TRAMP_SIZE GRUB_IA64_DL_TRAMP_SIZE
 #define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
 #else
-void
+grub_err_t
 grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
                                 grub_size_t *got);
 #endif
 
-#ifdef __powerpc__
-#define GRUB_ARCH_DL_TRAMP_SIZE 16
+#if defined (__powerpc__) || defined (__mips__)
 #define GRUB_ARCH_DL_TRAMP_ALIGN 4
 #define GRUB_ARCH_DL_GOT_ALIGN 4
 #endif
index 36a683d6ff2aacbac92963e6a35dce4a25630c98..4f619b925e61b84374026bb1f2c7a3e29eb4f58a 100644 (file)
@@ -1321,7 +1321,6 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
          *kernel_sz = ALIGN_UP (*kernel_sz, 16);
 
          grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
-         tramp *= sizeof (struct grub_ia64_trampoline);
 
          ia64_toff = *kernel_sz;
          *kernel_sz += ALIGN_UP (tramp, 16);
@@ -1332,7 +1331,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
          *kernel_sz += 16 * ia64jmpnum;
 
          ia64_got_off = *kernel_sz;
-         *kernel_sz += ALIGN_UP (got * sizeof (grub_uint64_t), 16);
+         *kernel_sz += ALIGN_UP (got, 16);
        }
 #endif