{
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;
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)
{
}
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;
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;
}
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;
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))
{
}
#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
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
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;
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;
break;
if (i == e->e_shnum)
- return 0;
+ return;
entsize = s->sh_entsize;
{
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
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);
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;
/* 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:
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;
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;
#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