do essentially the same thing, do it in similar way.
+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
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;
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;
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;
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)
{
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)
{
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);
break;
}
}
- *tramp = cntt;
- *got = cntg;
+ *tramp = cntt * sizeof (struct grub_ia64_trampoline);
+ *got = cntg * sizeof (grub_uint64_t);
+
+ return GRUB_ERR_NONE;
}
#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)
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;
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;
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));
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)
{
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;
}
- 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
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;
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
#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
*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);
*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