]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Restructure module loading and many fixes. Now normal.mod loads successfully
authorphcoder <phcoder@debian>
Sun, 2 Jan 2011 22:30:25 +0000 (23:30 +0100)
committerphcoder <phcoder@debian>
Sun, 2 Jan 2011 22:30:25 +0000 (23:30 +0100)
grub-core/kern/dl.c
grub-core/kern/emu/full.c
grub-core/kern/ia64/dl.c
include/grub/dl.h

index 0ccdbe03b2b388fde10218091b238461ba37ca37..787fcfad0563e4e2b20464c559fc333043c04cd3 100644 (file)
@@ -229,6 +229,46 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
 {
   unsigned i;
   Elf_Shdr *s;
+  grub_size_t tsize = 0, talign = 1;
+#ifdef __ia64__
+  grub_size_t tramp;
+  grub_size_t got;
+#endif
+  char *ptr;
+
+  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
+    {
+      tsize += ALIGN_UP (s->sh_size, s->sh_addralign);
+      if (talign < s->sh_addralign)
+       talign = s->sh_addralign;
+    }
+
+#ifdef __ia64__
+  grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
+  tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
+  if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
+    talign = GRUB_ARCH_DL_TRAMP_ALIGN;
+  tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
+  if (talign < GRUB_ARCH_DL_GOT_ALIGN)
+    talign = GRUB_ARCH_DL_GOT_ALIGN;
+#endif
+
+#ifdef GRUB_MACHINE_EMU
+  if (talign < 8192 * 16)
+    talign = 8192 * 16;
+  tsize = ALIGN_UP (tsize, 8192 * 16);
+#endif
+
+  mod->base = grub_memalign (talign, tsize);
+  if (!mod->base)
+    return grub_errno;
+  ptr = mod->base;
+
+#ifdef GRUB_MACHINE_EMU
+  mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC);
+#endif
 
   for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
        i < e->e_shnum;
@@ -237,38 +277,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
       if (s->sh_flags & SHF_ALLOC)
        {
          grub_dl_segment_t seg;
-         grub_size_t tramp_size = 0;
-         grub_size_t alsize, align;
 
          seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
          if (! seg)
            return grub_errno;
 
-         alsize = s->sh_size;
-         align = s->sh_addralign;
-         tramp_size = grub_arch_dl_get_tramp_size (e, i);
-         if (tramp_size && align < GRUB_ARCH_DL_TRAMP_ALIGN)
-           {
-             align = GRUB_ARCH_DL_TRAMP_ALIGN;
-             alsize = ALIGN_UP (alsize, GRUB_ARCH_DL_TRAMP_ALIGN);
-           }
-         alsize += tramp_size;
-#ifdef GRUB_MACHINE_EMU
-         if (align < 8192 * 16)
-           align = 8192 * 16;
-         alsize = ALIGN_UP (alsize, 8192 * 16);
-#endif
-
-         if (alsize)
+         if (s->sh_size)
            {
              void *addr;
 
-             addr = grub_memalign (align, alsize);
-             if (! addr)
-               {
-                 grub_free (seg);
-                 return grub_errno;
-               }
+             ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
+             addr = ptr;
+             ptr += s->sh_size;
 
              switch (s->sh_type)
                {
@@ -281,10 +301,6 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
                }
 
              seg->addr = addr;
-#ifdef GRUB_MACHINE_EMU
-             if (s->sh_flags & SHF_EXECINSTR)
-               mprotect (addr, alsize, PROT_READ | PROT_WRITE | PROT_EXEC);
-#endif
            }
          else
            seg->addr = 0;
@@ -295,6 +311,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
          mod->segment = seg;
        }
     }
+#ifdef __ia64__
+  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
+  mod->tramp = ptr;
+  ptr += tramp;
+  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
+  mod->got = ptr;
+  ptr += got;
+#endif
 
   return GRUB_ERR_NONE;
 }
@@ -371,7 +395,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
              if (!desc)
                return grub_errno;
              desc[0] = (void *) sym->st_value;
-             desc[1] = mod->gp;
+             desc[1] = mod->base;
              if (grub_dl_register_symbol (name, (void *) desc, mod))
                return grub_errno;
              sym->st_value = (grub_addr_t) desc;
@@ -564,7 +588,6 @@ grub_dl_load_core (void *addr, grub_size_t size)
   if (grub_dl_resolve_name (mod, e)
       || grub_dl_resolve_dependencies (mod, e)
       || grub_dl_load_segments (mod, e)
-      || grub_arch_dl_allocate_gp (mod, e)
       || grub_dl_resolve_symbols (mod, e)
       || grub_arch_dl_relocate_symbols (mod, e))
     {
index 67a12530106b038b0ecee6c60a264537055e8cdc..80edb991edd0a5843719b1fa72809fe57afc8d8e 100644 (file)
@@ -50,18 +50,11 @@ grub_emu_init (void)
 }
 
 #ifdef __ia64__
-grub_size_t
-grub_arch_dl_get_tramp_size (const void *ehdr __attribute__ ((unused)),
-                            unsigned sec  __attribute__ ((unused)))
+void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
+                                     grub_size_t *tramp, grub_size_t *got)
 {
-  return ~(grub_size_t)0;
-}
-
-grub_err_t
-grub_arch_dl_allocate_gp (grub_dl_t mod __attribute__ ((unused)),
-                         const void *ehdr __attribute__ ((unused)))
-{
-  return GRUB_ERR_BAD_MODULE;
+  *tramp = 0;
+  *got = 0;
 }
 
 #endif
index 55b50ff69da4da8497a762d6fd3e98faad9c1770..9bbebcd2f21b24570c6da6f5dff9b070825feb5f 100644 (file)
@@ -75,9 +75,9 @@ add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value)
   grub_uint32_t high, mid, low, c;
   low  = (a & 0x00007f);
   mid  = (a & 0x7fc000) >> 7;
-  high = (a & 0x003e00) << 5;
+  high = (a & 0x003e00) << 7;
   c = (low | mid | high) + value;
-  return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 5) & 0x003e00);
+  return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00
 }
 
 static void
@@ -138,7 +138,7 @@ static void
 make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
 {
   grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
-  tr->addr_hi[0] = ((addr & 0xc00000) >> 18);
+  tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
   tr->addr_hi[1] = (addr >> 24) & 0xff;
   tr->addr_hi[2] = (addr >> 32) & 0xff;
   tr->addr_hi[3] = (addr >> 40) & 0xff;
@@ -152,11 +152,11 @@ make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
   grub_memcpy (tr->jump, jump, sizeof (tr->jump));
 }
 
-grub_size_t
-grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec)
+void
+grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, grub_size_t *got)
 {
   const Elf_Ehdr *e = ehdr;
-  int cnt = 0;
+  grub_size_t cntt = 0, cntg = 0;;
   const Elf_Shdr *s;
   Elf_Word entsize;
   unsigned i;
@@ -169,7 +169,7 @@ grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec)
       break;
 
   if (i == e->e_shnum)
-    return 0;
+    return;
 
   entsize = s->sh_entsize;
 
@@ -180,68 +180,25 @@ grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec)
       {
        Elf_Rela *rel, *max;
 
-       if (s->sh_info != sec)
-         continue;
-       
        for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
               max = rel + s->sh_size / s->sh_entsize;
             rel < max; rel++)
-         if (ELF_R_TYPE (rel->r_info) == R_IA64_PCREL21B)
-           cnt++;
+         switch (ELF_R_TYPE (rel->r_info))
+           {
+           case R_IA64_PCREL21B:
+             cntt++;
+             break;
+           case R_IA64_LTOFF_FPTR22:
+           case R_IA64_LTOFF22X:
+           case R_IA64_LTOFF22:
+             cntg++;
+             break;
+           }
       }
-
-  return cnt * sizeof (struct ia64_trampoline);
+  *tramp = cntt * sizeof (struct ia64_trampoline);
+  *got = cntg * sizeof (grub_uint64_t);
 }
 
-grub_err_t
-grub_arch_dl_allocate_gp (grub_dl_t mod, const void *ehdr)
-{
-  grub_size_t gp_size = 0;
-  const Elf_Ehdr *e = ehdr;
-  const Elf_Shdr *s;
-  unsigned i;
-
-  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_RELA)
-      {
-       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_Rela *rel, *max;
-
-           for (rel = (Elf_Rela *) ((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_IA64_LTOFF_FPTR22:
-                 case R_IA64_LTOFF22X:
-                 case R_IA64_LTOFF22:
-                 case R_IA64_GPREL22:
-                   gp_size += 8;
-                   break;
-                 default: break;
-                 }
-         }
-      }
-
-  if (gp_size > MASK19)
-    return grub_error (GRUB_ERR_OUT_OF_RANGE, "gp too big");
-
-  mod->gp = grub_malloc (gp_size);
-  if (!mod->gp)
-    return grub_errno;
-  return GRUB_ERR_NONE;
-}
 
 /* Relocate symbols.  */
 grub_err_t
@@ -252,8 +209,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
   Elf_Word entsize;
   unsigned i;
   grub_uint64_t *gp, *gpptr;
+  struct ia64_trampoline *tr;
 
-  gp = gpptr = (grub_uint64_t *) mod->gp;
+  gp = (grub_uint64_t *) mod->base;
+  gpptr = (grub_uint64_t *) mod->got;
+  tr = mod->tramp;
 
   /* Find a symbol table.  */
   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
@@ -282,9 +242,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
        if (seg)
          {
            Elf_Rela *rel, *max;
-           struct ia64_trampoline *tr;
-
-           tr = (void *) ((char *) seg->addr + ALIGN_UP (seg->size, GRUB_ARCH_DL_TRAMP_ALIGN));
 
            for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
                   max = rel + s->sh_size / s->sh_entsize;
@@ -306,6 +263,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
                /* On the PPC the value does not have an explicit
                   addend, add it.  */
                value = sym->st_value + rel->r_addend;
+
                switch (ELF_R_TYPE (rel->r_info))
                  {
                  case R_IA64_PCREL21B:
@@ -323,15 +281,24 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
                  case R_IA64_SEGREL64LSB:
                    *(grub_uint64_t *) addr += value - rel->r_offset;
                    break;
+                 case R_IA64_FPTR64LSB:
                  case R_IA64_DIR64LSB:
                    *(grub_uint64_t *) addr += value;
                    break;
+                 case R_IA64_PCREL64LSB:
+                   *(grub_uint64_t *) addr += value - addr;
+                   break;
+                 case R_IA64_GPREL22:
+                   add_value_to_slot_21 (addr, value - (grub_addr_t) gp);
+                   break;
+
                  case R_IA64_LTOFF_FPTR22:
                  case R_IA64_LTOFF22X:
                  case R_IA64_LTOFF22:
-                 case R_IA64_GPREL22:
                    *gpptr = value;
-                   add_value_to_slot_21 (addr, (gpptr - gp) * sizeof (grub_uint64_t));
+                   if ((addr & 0xffff) == 0x4301)
+                     grub_dprintf ("modules", "off = %lx\n", (grub_addr_t) gpptr - (grub_addr_t) gp);
+                   add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp);
                    gpptr++;
                    break;
 
index c43c30ca7e2d56ddc1a02812968b981a81fe8a57..b57c3ae87cdbd4ef7bc31890cf78f1137b0cf6b3 100644 (file)
@@ -93,8 +93,10 @@ struct grub_dl
   grub_addr_t init;
   grub_addr_t fini;
 #ifdef __ia64__
-  char *gp;
+  void *got;
+  void *tramp;
 #endif
+  void *base;
   struct grub_dl *next;
 };
 typedef struct grub_dl *grub_dl_t;
@@ -123,24 +125,12 @@ void grub_arch_dl_init_linker (void);
 #endif
 
 #ifdef __ia64__
-grub_size_t grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec);
-grub_err_t grub_arch_dl_allocate_gp (grub_dl_t mod, const void *ehdr);
+void grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, grub_size_t *got);
 
 #define GRUB_ARCH_DL_TRAMP_ALIGN 16
-#else
-static inline grub_size_t
-grub_arch_dl_get_tramp_size (const void *ehdr __attribute__ ((unused)), int sec __attribute__ ((unused)))
-{
-  return 0;
-}
-static inline grub_err_t
-grub_arch_dl_allocate_gp (grub_dl_t mod __attribute__ ((unused)),
-                         const void *ehdr __attribute__ ((unused)))
-{
-  return GRUB_ERR_NONE;
-}
+#define GRUB_ARCH_DL_GOT_ALIGN 16
 
-#define GRUB_ARCH_DL_TRAMP_ALIGN 1
+#else
 #endif