mkimagexx: Split PE and generic part for relocations.

As a preparation for U-Boot relocations, split emitting PE-relocations
from parsing source ELF-relocations.
This commit is contained in:
Vladimir Serbinenko 2016-02-18 20:54:37 +01:00
parent 36212460d3
commit dd3969e7ec

View file

@ -1095,7 +1095,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
/* Add a PE32's fixup entry for a relocation. Return the resulting address
after having written to the file OUT. */
static Elf_Addr
SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
Elf_Addr addr, int flush, Elf_Addr current_address,
const struct grub_install_image_target_desc *image_target)
{
@ -1187,70 +1187,39 @@ SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
return current_address;
}
/* Make a .reloc section. */
static Elf_Addr
SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
Elf_Addr *section_addresses, Elf_Shdr *sections,
Elf_Half section_entsize, Elf_Half num_sections,
const char *strtab,
Elf_Addr jumpers, grub_size_t njumpers,
struct translate_context
{
struct fixup_block_list *lst, *lst0;
Elf_Addr current_address;
};
static void
translate_reloc_start (struct translate_context *ctx)
{
ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000);
memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000);
ctx->current_address = 0;
}
static void
translate_relocation (struct translate_context *ctx,
Elf_Addr addr,
Elf_Addr info,
const struct grub_install_image_target_desc *image_target)
{
unsigned i;
Elf_Shdr *s;
struct fixup_block_list *lst, *lst0;
Elf_Addr current_address = 0;
lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000);
memset (lst, 0, sizeof (*lst) + 2 * 0x1000);
for (i = 0, s = sections; i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
(grub_target_to_host32 (s->sh_type) == SHT_RELA))
{
Elf_Rel *r;
Elf_Word rtab_size, r_size, num_rs;
Elf_Off rtab_offset;
Elf_Addr section_address;
Elf_Word j;
grub_util_info ("translating the relocation section %s",
strtab + grub_le_to_cpu32 (s->sh_name));
rtab_size = grub_target_to_host (s->sh_size);
r_size = grub_target_to_host (s->sh_entsize);
rtab_offset = grub_target_to_host (s->sh_offset);
num_rs = rtab_size / r_size;
section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
j < num_rs;
j++, r = (Elf_Rel *) ((char *) r + r_size))
{
Elf_Addr info;
Elf_Addr offset;
offset = grub_target_to_host (r->r_offset);
info = grub_target_to_host (r->r_info);
/* Necessary to relocate only absolute addresses. */
switch (image_target->elf_target)
{
case EM_386:
if (ELF_R_TYPE (info) == R_386_32)
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info ("adding a relocation entry for 0x%"
GRUB_HOST_PRIxLONG_LONG,
(unsigned long long) addr);
current_address
= SUFFIX (add_fixup_entry) (&lst,
ctx->current_address
= add_fixup_entry (&ctx->lst,
GRUB_PE32_REL_BASED_HIGHLOW,
addr, 0, current_address,
addr, 0, ctx->current_address,
image_target);
}
break;
@ -1262,17 +1231,14 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
}
else if (ELF_R_TYPE (info) == R_X86_64_64)
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info ("adding a relocation entry for 0x%"
GRUB_HOST_PRIxLONG_LONG,
(unsigned long long) addr);
current_address
= SUFFIX (add_fixup_entry) (&lst,
ctx->current_address
= add_fixup_entry (&ctx->lst,
GRUB_PE32_REL_BASED_DIR64,
addr,
0, current_address,
0, ctx->current_address,
image_target);
}
break;
@ -1293,17 +1259,14 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
case R_IA64_DIR64LSB:
#if 1
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info ("adding a relocation entry for 0x%"
GRUB_HOST_PRIxLONG_LONG,
(unsigned long long) addr);
current_address
= SUFFIX (add_fixup_entry) (&lst,
ctx->current_address
= add_fixup_entry (&ctx->lst,
GRUB_PE32_REL_BASED_DIR64,
addr,
0, current_address,
0, ctx->current_address,
image_target);
}
#endif
@ -1319,13 +1282,10 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
{
case R_AARCH64_ABS64:
{
Elf_Addr addr;
addr = section_address + offset;
current_address
= SUFFIX (add_fixup_entry) (&lst,
ctx->current_address
= add_fixup_entry (&ctx->lst,
GRUB_PE32_REL_BASED_DIR64,
addr, 0, current_address,
addr, 0, ctx->current_address,
image_target);
}
break;
@ -1361,22 +1321,16 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
case R_ARM_THM_JUMP24:
case R_ARM_CALL:
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) current_address);
grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address);
}
break;
/* Create fixup entry for PE/COFF loader */
case R_ARM_ABS32:
{
Elf_Addr addr;
addr = section_address + offset;
current_address
= SUFFIX (add_fixup_entry) (&lst,
ctx->current_address
= add_fixup_entry (&ctx->lst,
GRUB_PE32_REL_BASED_HIGHLOW,
addr, 0, current_address,
addr, 0, ctx->current_address,
image_target);
}
break;
@ -1390,40 +1344,109 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
default:
grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
}
}
static Elf_Addr
finish_reloc_translation (struct translate_context *ctx, void **out,
const struct grub_install_image_target_desc *image_target)
{
ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target);
{
grub_uint8_t *ptr;
ptr = *out = xmalloc (ctx->current_address);
for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next)
if (ctx->lst->state)
{
memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size));
ptr += grub_target_to_host32 (ctx->lst->b.block_size);
}
assert ((ctx->current_address + (grub_uint8_t *) *out) == ptr);
}
for (ctx->lst = ctx->lst0; ctx->lst; )
{
struct fixup_block_list *next;
next = ctx->lst->next;
free (ctx->lst);
ctx->lst = next;
}
return ctx->current_address;
}
static void
translate_reloc_jumpers (struct translate_context *ctx,
Elf_Addr jumpers, grub_size_t njumpers,
const struct grub_install_image_target_desc *image_target)
{
unsigned i;
for (i = 0; i < njumpers; i++)
ctx->current_address = add_fixup_entry (&ctx->lst,
GRUB_PE32_REL_BASED_DIR64,
jumpers + 8 * i,
0, ctx->current_address,
image_target);
}
/* Make a .reloc section. */
static Elf_Addr
make_reloc_section (Elf_Ehdr *e, void **out,
Elf_Addr *section_addresses, Elf_Shdr *sections,
Elf_Half section_entsize, Elf_Half num_sections,
const char *strtab,
Elf_Addr jumpers, grub_size_t njumpers,
const struct grub_install_image_target_desc *image_target)
{
unsigned i;
Elf_Shdr *s;
struct translate_context ctx;
translate_reloc_start (&ctx);
for (i = 0, s = sections; i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
(grub_target_to_host32 (s->sh_type) == SHT_RELA))
{
Elf_Rel *r;
Elf_Word rtab_size, r_size, num_rs;
Elf_Off rtab_offset;
Elf_Addr section_address;
Elf_Word j;
grub_util_info ("translating the relocation section %s",
strtab + grub_le_to_cpu32 (s->sh_name));
rtab_size = grub_target_to_host (s->sh_size);
r_size = grub_target_to_host (s->sh_entsize);
rtab_offset = grub_target_to_host (s->sh_offset);
num_rs = rtab_size / r_size;
section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
j < num_rs;
j++, r = (Elf_Rel *) ((char *) r + r_size))
{
Elf_Addr info;
Elf_Addr offset;
Elf_Addr addr;
offset = grub_target_to_host (r->r_offset);
info = grub_target_to_host (r->r_info);
addr = section_address + offset;
translate_relocation (&ctx, addr, info, image_target);
}
}
if (image_target->elf_target == EM_IA_64)
for (i = 0; i < njumpers; i++)
current_address = SUFFIX (add_fixup_entry) (&lst,
GRUB_PE32_REL_BASED_DIR64,
jumpers + 8 * i,
0, current_address,
translate_reloc_jumpers (&ctx, jumpers, njumpers,
image_target);
current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target);
{
grub_uint8_t *ptr;
ptr = *out = xmalloc (current_address);
for (lst = lst0; lst; lst = lst->next)
if (lst->state)
{
memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size));
ptr += grub_target_to_host32 (lst->b.block_size);
}
assert ((current_address + (grub_uint8_t *) *out) == ptr);
}
for (lst = lst0; lst; )
{
struct fixup_block_list *next;
next = lst->next;
free (lst);
lst = next;
}
return current_address;
return finish_reloc_translation (&ctx, out, image_target);
}
/* Determine if this section is a text section. Return false if this