Restructure module loading and many fixes. Now normal.mod loads successfully
This commit is contained in:
parent
bbbf84350e
commit
f49157dfe5
4 changed files with 99 additions and 126 deletions
|
@ -229,6 +229,46 @@ 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;
|
||||||
|
#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);
|
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||||
i < e->e_shnum;
|
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)
|
if (s->sh_flags & SHF_ALLOC)
|
||||||
{
|
{
|
||||||
grub_dl_segment_t seg;
|
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));
|
seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
|
||||||
if (! seg)
|
if (! seg)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
alsize = s->sh_size;
|
if (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)
|
|
||||||
{
|
{
|
||||||
void *addr;
|
void *addr;
|
||||||
|
|
||||||
addr = grub_memalign (align, alsize);
|
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
|
||||||
if (! addr)
|
addr = ptr;
|
||||||
{
|
ptr += s->sh_size;
|
||||||
grub_free (seg);
|
|
||||||
return grub_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (s->sh_type)
|
switch (s->sh_type)
|
||||||
{
|
{
|
||||||
|
@ -281,10 +301,6 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
seg->addr = addr;
|
seg->addr = addr;
|
||||||
#ifdef GRUB_MACHINE_EMU
|
|
||||||
if (s->sh_flags & SHF_EXECINSTR)
|
|
||||||
mprotect (addr, alsize, PROT_READ | PROT_WRITE | PROT_EXEC);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
seg->addr = 0;
|
seg->addr = 0;
|
||||||
|
@ -295,6 +311,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
mod->segment = seg;
|
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;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
@ -371,7 +395,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
|
||||||
if (!desc)
|
if (!desc)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
desc[0] = (void *) sym->st_value;
|
desc[0] = (void *) sym->st_value;
|
||||||
desc[1] = mod->gp;
|
desc[1] = mod->base;
|
||||||
if (grub_dl_register_symbol (name, (void *) desc, mod))
|
if (grub_dl_register_symbol (name, (void *) desc, mod))
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
sym->st_value = (grub_addr_t) desc;
|
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)
|
if (grub_dl_resolve_name (mod, e)
|
||||||
|| grub_dl_resolve_dependencies (mod, e)
|
|| grub_dl_resolve_dependencies (mod, e)
|
||||||
|| grub_dl_load_segments (mod, e)
|
|| grub_dl_load_segments (mod, e)
|
||||||
|| grub_arch_dl_allocate_gp (mod, e)
|
|
||||||
|| grub_dl_resolve_symbols (mod, e)
|
|| grub_dl_resolve_symbols (mod, e)
|
||||||
|| grub_arch_dl_relocate_symbols (mod, e))
|
|| grub_arch_dl_relocate_symbols (mod, e))
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,18 +50,11 @@ grub_emu_init (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
grub_size_t
|
void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
|
||||||
grub_arch_dl_get_tramp_size (const void *ehdr __attribute__ ((unused)),
|
grub_size_t *tramp, grub_size_t *got)
|
||||||
unsigned sec __attribute__ ((unused)))
|
|
||||||
{
|
{
|
||||||
return ~(grub_size_t)0;
|
*tramp = 0;
|
||||||
}
|
*got = 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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;
|
grub_uint32_t high, mid, low, c;
|
||||||
low = (a & 0x00007f);
|
low = (a & 0x00007f);
|
||||||
mid = (a & 0x7fc000) >> 7;
|
mid = (a & 0x7fc000) >> 7;
|
||||||
high = (a & 0x003e00) << 5;
|
high = (a & 0x003e00) << 7;
|
||||||
c = (low | mid | high) + value;
|
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
|
static void
|
||||||
|
@ -138,7 +138,7 @@ static void
|
||||||
make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
|
make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
|
||||||
{
|
{
|
||||||
grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
|
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[1] = (addr >> 24) & 0xff;
|
||||||
tr->addr_hi[2] = (addr >> 32) & 0xff;
|
tr->addr_hi[2] = (addr >> 32) & 0xff;
|
||||||
tr->addr_hi[3] = (addr >> 40) & 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_memcpy (tr->jump, jump, sizeof (tr->jump));
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_size_t
|
void
|
||||||
grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec)
|
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_Ehdr *e = ehdr;
|
||||||
int cnt = 0;
|
grub_size_t cntt = 0, cntg = 0;;
|
||||||
const Elf_Shdr *s;
|
const Elf_Shdr *s;
|
||||||
Elf_Word entsize;
|
Elf_Word entsize;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -169,7 +169,7 @@ grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == e->e_shnum)
|
if (i == e->e_shnum)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
entsize = s->sh_entsize;
|
entsize = s->sh_entsize;
|
||||||
|
|
||||||
|
@ -180,68 +180,25 @@ grub_arch_dl_get_tramp_size (const void *ehdr, unsigned sec)
|
||||||
{
|
{
|
||||||
Elf_Rela *rel, *max;
|
Elf_Rela *rel, *max;
|
||||||
|
|
||||||
if (s->sh_info != sec)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
|
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
|
||||||
max = rel + s->sh_size / s->sh_entsize;
|
max = rel + s->sh_size / s->sh_entsize;
|
||||||
rel < max; rel++)
|
rel < max; rel++)
|
||||||
if (ELF_R_TYPE (rel->r_info) == R_IA64_PCREL21B)
|
switch (ELF_R_TYPE (rel->r_info))
|
||||||
cnt++;
|
{
|
||||||
|
case R_IA64_PCREL21B:
|
||||||
|
cntt++;
|
||||||
|
break;
|
||||||
|
case R_IA64_LTOFF_FPTR22:
|
||||||
|
case R_IA64_LTOFF22X:
|
||||||
|
case R_IA64_LTOFF22:
|
||||||
|
cntg++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
*tramp = cntt * sizeof (struct ia64_trampoline);
|
||||||
return cnt * 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. */
|
/* Relocate symbols. */
|
||||||
grub_err_t
|
grub_err_t
|
||||||
|
@ -252,8 +209,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
Elf_Word entsize;
|
Elf_Word entsize;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
grub_uint64_t *gp, *gpptr;
|
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. */
|
/* Find a symbol table. */
|
||||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
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)
|
if (seg)
|
||||||
{
|
{
|
||||||
Elf_Rela *rel, *max;
|
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),
|
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
|
||||||
max = rel + s->sh_size / s->sh_entsize;
|
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
|
/* On the PPC the value does not have an explicit
|
||||||
addend, add it. */
|
addend, add it. */
|
||||||
value = sym->st_value + rel->r_addend;
|
value = sym->st_value + rel->r_addend;
|
||||||
|
|
||||||
switch (ELF_R_TYPE (rel->r_info))
|
switch (ELF_R_TYPE (rel->r_info))
|
||||||
{
|
{
|
||||||
case R_IA64_PCREL21B:
|
case R_IA64_PCREL21B:
|
||||||
|
@ -323,15 +281,24 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
case R_IA64_SEGREL64LSB:
|
case R_IA64_SEGREL64LSB:
|
||||||
*(grub_uint64_t *) addr += value - rel->r_offset;
|
*(grub_uint64_t *) addr += value - rel->r_offset;
|
||||||
break;
|
break;
|
||||||
|
case R_IA64_FPTR64LSB:
|
||||||
case R_IA64_DIR64LSB:
|
case R_IA64_DIR64LSB:
|
||||||
*(grub_uint64_t *) addr += value;
|
*(grub_uint64_t *) addr += value;
|
||||||
break;
|
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_LTOFF_FPTR22:
|
||||||
case R_IA64_LTOFF22X:
|
case R_IA64_LTOFF22X:
|
||||||
case R_IA64_LTOFF22:
|
case R_IA64_LTOFF22:
|
||||||
case R_IA64_GPREL22:
|
|
||||||
*gpptr = value;
|
*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++;
|
gpptr++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,10 @@ struct grub_dl
|
||||||
grub_addr_t init;
|
grub_addr_t init;
|
||||||
grub_addr_t fini;
|
grub_addr_t fini;
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
char *gp;
|
void *got;
|
||||||
|
void *tramp;
|
||||||
#endif
|
#endif
|
||||||
|
void *base;
|
||||||
struct grub_dl *next;
|
struct grub_dl *next;
|
||||||
};
|
};
|
||||||
typedef struct grub_dl *grub_dl_t;
|
typedef struct grub_dl *grub_dl_t;
|
||||||
|
@ -123,24 +125,12 @@ void grub_arch_dl_init_linker (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
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);
|
||||||
grub_err_t grub_arch_dl_allocate_gp (grub_dl_t mod, const void *ehdr);
|
|
||||||
|
|
||||||
#define GRUB_ARCH_DL_TRAMP_ALIGN 16
|
#define GRUB_ARCH_DL_TRAMP_ALIGN 16
|
||||||
#else
|
#define GRUB_ARCH_DL_GOT_ALIGN 16
|
||||||
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_TRAMP_ALIGN 1
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue