Unify GOT/trampoline handling between PPC, MIPS and IA64 as they
do essentially the same thing, do it in similar way.
This commit is contained in:
parent
c6a823e267
commit
4906052019
8 changed files with 99 additions and 80 deletions
|
@ -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>
|
2013-11-21 Colin Watson <cjwatson@ubuntu.com>
|
||||||
|
|
||||||
* util/grub-mkrescue.c (main): If a source directory is not
|
* util/grub-mkrescue.c (main): If a source directory is not
|
||||||
|
|
|
@ -229,9 +229,10 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
unsigned i;
|
unsigned i;
|
||||||
Elf_Shdr *s;
|
Elf_Shdr *s;
|
||||||
grub_size_t tsize = 0, talign = 1;
|
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 tramp;
|
||||||
grub_size_t got;
|
grub_size_t got;
|
||||||
|
grub_err_t err;
|
||||||
#endif
|
#endif
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
|
@ -244,10 +245,10 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
talign = s->sh_addralign;
|
talign = s->sh_addralign;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (__ia64__) || defined (__powerpc__)
|
#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
|
||||||
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
||||||
tramp *= GRUB_ARCH_DL_TRAMP_SIZE;
|
if (err)
|
||||||
got *= sizeof (grub_uint64_t);
|
return err;
|
||||||
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
|
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||||
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
||||||
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;
|
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);
|
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||||
mod->tramp = ptr;
|
mod->tramp = ptr;
|
||||||
ptr += tramp;
|
ptr += tramp;
|
||||||
|
|
|
@ -46,7 +46,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
return GRUB_ERR_BAD_MODULE;
|
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)),
|
void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
|
||||||
grub_size_t *tramp, grub_size_t *got)
|
grub_size_t *tramp, grub_size_t *got)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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));
|
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_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
grub_size_t *got)
|
grub_size_t *got)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +187,7 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == grub_le_to_cpu16 (e->e_shnum))
|
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));
|
for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu64 (e->e_shoff));
|
||||||
i < grub_le_to_cpu16 (e->e_shnum);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*tramp = cntt;
|
*tramp = cntt * sizeof (struct grub_ia64_trampoline);
|
||||||
*got = cntg;
|
*got = cntg * sizeof (grub_uint64_t);
|
||||||
|
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,58 @@ grub_arch_dl_check_header (void *ehdr)
|
||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
#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. */
|
/* Relocate symbols. */
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
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_Shdr *s;
|
||||||
Elf_Word entsize;
|
Elf_Word entsize;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
grub_size_t gp_size = 0;
|
|
||||||
/* FIXME: suboptimal. */
|
/* FIXME: suboptimal. */
|
||||||
grub_uint32_t *gp, *gpptr;
|
grub_uint32_t *gp, *gpptr;
|
||||||
grub_uint32_t gp0;
|
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];
|
gp0 = ((grub_uint32_t *)((char *) e + s->sh_offset))[5];
|
||||||
|
|
||||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
gpptr = gp = mod->got;
|
||||||
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;
|
|
||||||
|
|
||||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||||
i < e->e_shnum;
|
i < e->e_shnum;
|
||||||
|
@ -234,7 +249,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
grub_free (gp);
|
|
||||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||||
N_("relocation 0x%x is not implemented yet"),
|
N_("relocation 0x%x is not implemented yet"),
|
||||||
ELF_R_TYPE (rel->r_info));
|
ELF_R_TYPE (rel->r_info));
|
||||||
|
|
|
@ -38,9 +38,26 @@ grub_arch_dl_check_header (void *ehdr)
|
||||||
return GRUB_ERR_NONE;
|
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"
|
#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_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
grub_size_t *got)
|
grub_size_t *got)
|
||||||
{
|
{
|
||||||
|
@ -59,7 +76,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == e->e_shnum)
|
if (i == e->e_shnum)
|
||||||
return;
|
return GRUB_ERR_NONE;
|
||||||
|
|
||||||
for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
|
for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
|
||||||
i < e->e_shnum;
|
i < e->e_shnum;
|
||||||
|
@ -77,26 +94,11 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
*tramp *= sizeof (struct trampoline);
|
||||||
|
|
||||||
|
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Relocate symbols. */
|
/* Relocate symbols. */
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
|
@ -167,8 +169,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
|
|
||||||
if (delta << 6 >> 6 != delta)
|
if (delta << 6 >> 6 != delta)
|
||||||
{
|
{
|
||||||
COMPILE_TIME_ASSERT (sizeof (struct trampoline)
|
|
||||||
== GRUB_ARCH_DL_TRAMP_SIZE);
|
|
||||||
grub_memcpy (tptr, &trampoline_template,
|
grub_memcpy (tptr, &trampoline_template,
|
||||||
sizeof (*tptr));
|
sizeof (*tptr));
|
||||||
delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
|
delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
|
||||||
|
|
|
@ -179,7 +179,7 @@ struct grub_dl
|
||||||
Elf_Sym *symtab;
|
Elf_Sym *symtab;
|
||||||
void (*init) (struct grub_dl *mod);
|
void (*init) (struct grub_dl *mod);
|
||||||
void (*fini) (void);
|
void (*fini) (void);
|
||||||
#if defined (__ia64__) || defined (__powerpc__)
|
#if defined (__ia64__) || defined (__powerpc__) || defined (__mips__)
|
||||||
void *got;
|
void *got;
|
||||||
void *tramp;
|
void *tramp;
|
||||||
#endif
|
#endif
|
||||||
|
@ -243,23 +243,21 @@ void grub_arch_dl_init_linker (void);
|
||||||
#define GRUB_IA64_DL_TRAMP_SIZE 48
|
#define GRUB_IA64_DL_TRAMP_SIZE 48
|
||||||
#define GRUB_IA64_DL_GOT_ALIGN 16
|
#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_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
grub_size_t *got);
|
grub_size_t *got);
|
||||||
|
|
||||||
#if defined (__ia64__)
|
#if defined (__ia64__)
|
||||||
#define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN
|
#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_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
|
#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
|
||||||
#else
|
#else
|
||||||
void
|
grub_err_t
|
||||||
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
grub_size_t *got);
|
grub_size_t *got);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __powerpc__
|
#if defined (__powerpc__) || defined (__mips__)
|
||||||
#define GRUB_ARCH_DL_TRAMP_SIZE 16
|
|
||||||
#define GRUB_ARCH_DL_TRAMP_ALIGN 4
|
#define GRUB_ARCH_DL_TRAMP_ALIGN 4
|
||||||
#define GRUB_ARCH_DL_GOT_ALIGN 4
|
#define GRUB_ARCH_DL_GOT_ALIGN 4
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1321,7 +1321,6 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
|
||||||
*kernel_sz = ALIGN_UP (*kernel_sz, 16);
|
*kernel_sz = ALIGN_UP (*kernel_sz, 16);
|
||||||
|
|
||||||
grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
|
grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
|
||||||
tramp *= sizeof (struct grub_ia64_trampoline);
|
|
||||||
|
|
||||||
ia64_toff = *kernel_sz;
|
ia64_toff = *kernel_sz;
|
||||||
*kernel_sz += ALIGN_UP (tramp, 16);
|
*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;
|
*kernel_sz += 16 * ia64jmpnum;
|
||||||
|
|
||||||
ia64_got_off = *kernel_sz;
|
ia64_got_off = *kernel_sz;
|
||||||
*kernel_sz += ALIGN_UP (got * sizeof (grub_uint64_t), 16);
|
*kernel_sz += ALIGN_UP (got, 16);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue