To do so support the specification of a "target_address" (which must be 0 for image types which do not have this flag) and a new image flag to signal the need for absolute relocation. If this flag is present then image->link_addr is the default target.
Account for the target address when relocating. Fabricate correct addresses for absolute symbols relating to the bss ("__bss_start" and "_end"). This functionality is not yet used by any image type and is connected only to grub-mkimage ("-T option) and not yet to grub-install. Signed-off-by: Ian Campbell <i...@hellion.org.uk> --- include/grub/util/install.h | 2 +- util/grub-install-common.c | 4 +-- util/grub-mkimage.c | 7 +++++ util/grub-mkimagexx.c | 74 +++++++++++++++++++++++++++++++-------------- util/mkimage.c | 24 ++++++++++++--- 5 files changed, 81 insertions(+), 30 deletions(-) diff --git a/include/grub/util/install.h b/include/grub/util/install.h index bc987aa..b7ecf27 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -167,7 +167,7 @@ struct grub_install_image_target_desc; void grub_install_generate_image (const char *dir, const char *prefix, - FILE *out, + FILE *out, grub_uint64_t target_address, const char *outname, char *mods[], char *memdisk_path, char **pubkey_paths, size_t npubkeys, diff --git a/util/grub-install-common.c b/util/grub-install-common.c index ae26875..82a44f2 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -495,8 +495,8 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, if (!tgt) grub_util_error (_("unknown target format %s\n"), mkimage_target); - grub_install_generate_image (dir, prefix, fp, outname, - modules.entries, memdisk_path, + grub_install_generate_image (dir, prefix, fp, 0, + outname, modules.entries, memdisk_path, pubkeys, npubkeys, config_path, tgt, note, compression); while (dc--) diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index a2bd4c1..267beaa 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -65,6 +65,7 @@ static struct argp_option options[] = { /* TRANSLATORS: platform here isn't identifier. It can be translated. */ N_("use images and modules under DIR [default=%s/<platform>]"), 0}, {"prefix", 'p', N_("DIR"), 0, N_("set prefix directory [default=%s]"), 0}, + {"target-address", 'T', N_("ADDR"), 0, N_("set kernel target address [default=%d]"), 0}, {"memdisk", 'm', N_("FILE"), 0, /* TRANSLATORS: "memdisk" here isn't an identifier, it can be translated. "embed" is a verb (command description). "*/ @@ -126,6 +127,7 @@ struct arguments int note; const struct grub_install_image_target_desc *image_target; grub_compression_t comp; + grub_uint64_t target_address; }; static error_t @@ -217,6 +219,10 @@ argp_parser (int key, char *arg, struct argp_state *state) arguments->prefix = xstrdup (arg); break; + case 'T': + arguments->target_address = strtoull (arg, NULL, 0); + break; + case 'v': verbosity++; break; @@ -289,6 +295,7 @@ main (int argc, char *argv[]) grub_install_generate_image (arguments.dir, arguments.prefix ? : DEFAULT_DIRECTORY, fp, + arguments.target_address, arguments.output, arguments.modules, arguments.memdisk, arguments.pubkeys, arguments.npubkeys, arguments.config, diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index b4216ff..186d259 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -378,6 +378,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Shdr *symtab_section, Elf_Addr *section_addresses, Elf_Half section_entsize, Elf_Half num_sections, void *jumpers, Elf_Addr jumpers_addr, + Elf_Addr bss_addr, size_t bss_size, const struct grub_install_image_target_desc *image_target) { Elf_Word symtab_size, sym_size, num_syms; @@ -416,10 +417,14 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, } else if (cur_index == STN_UNDEF) { - if (sym->st_name) + if (strcmp (name, "__bss_start") == 0 && bss_addr) + sym->st_value = bss_addr; + else if (strcmp (name, "_end") == 0 && bss_addr) + sym->st_value = bss_addr + bss_size; + else if (sym->st_name) grub_util_error ("undefined symbol %s", name); - else - continue; + + continue; } else if (cur_index >= num_sections) grub_util_error ("section %d does not exist", cur_index); @@ -584,7 +589,7 @@ static void SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Addr *section_addresses, Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab, + const char *strtab, grub_uint64_t target_address, char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off, const struct grub_install_image_target_desc *image_target) @@ -867,6 +872,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, { case R_ARM_ABS32: { + sym_addr += target_address; grub_util_info (" ABS32:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), @@ -928,7 +934,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, grub_uint32_t tr_addr; grub_int32_t new_offset; tr_addr = (char *) tr - (char *) pe_target - - target_section_addr; + - (target_address - target_section_addr); new_offset = sym_addr - tr_addr - 12; /* There is no immediate version of bx, only register one... */ @@ -1337,6 +1343,7 @@ static Elf_Addr * SUFFIX (locate_sections) (const char *kernel_path, Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, const char *strtab, + grub_uint64_t target_address, size_t *exec_size, size_t *kernel_sz, size_t *all_align, const struct grub_install_image_target_desc *image_target) @@ -1351,7 +1358,7 @@ SUFFIX (locate_sections) (const char *kernel_path, section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); - current_address = 0; + current_address = target_address; for (i = 0, s = sections; i < num_sections; @@ -1391,6 +1398,15 @@ SUFFIX (locate_sections) (const char *kernel_path, grub_util_error ("%s", msg); } } + else if (!grub_image_needs_abs_reloc(image_target)) + { + if (grub_host_to_target_addr (s->sh_addr)) + grub_util_error (_("`%s' is miscompiled: its start address is 0x%llx" + " but this platform uses late relocation"), + kernel_path, + (unsigned long long) grub_host_to_target_addr (s->sh_addr)); + } + section_addresses[i] = current_address; current_address += grub_host_to_target_addr (s->sh_size); } @@ -1398,7 +1414,7 @@ SUFFIX (locate_sections) (const char *kernel_path, current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - *exec_size = current_address; + *exec_size = current_address - target_address; /* .data */ for (i = 0, s = sections; @@ -1426,14 +1442,15 @@ SUFFIX (locate_sections) (const char *kernel_path, current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - *kernel_sz = current_address; + *kernel_sz = current_address - target_address; return section_addresses; } static char * SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, size_t *kernel_sz, size_t *bss_size, - size_t total_module_size, grub_uint64_t *start, + size_t total_module_size, grub_uint64_t target_address, + grub_uint64_t *start, void **reloc_section, size_t *reloc_size, size_t *align, const struct grub_install_image_target_desc *image_target) @@ -1444,6 +1461,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, Elf_Shdr *sections; Elf_Addr *section_addresses; Elf_Addr *section_vaddresses; + Elf_Addr bss_addr = 0; int i; Elf_Shdr *s; Elf_Half num_sections; @@ -1455,6 +1473,9 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, Elf_Shdr *symtab_section = 0; grub_size_t got = 0; + if (target_address && !grub_image_needs_abs_reloc(image_target)) + grub_util_error("cannot perform absolute relocation for this image type"); + *start = 0; kernel_size = grub_util_get_image_size (kernel_path); @@ -1481,7 +1502,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, section_addresses = SUFFIX (locate_sections) (kernel_path, sections, section_entsize, - num_sections, strtab, + num_sections, strtab, target_address, exec_size, kernel_sz, align, image_target); @@ -1530,9 +1551,9 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, for (i = 0; i < num_sections; i++) section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; - if (!grub_image_needs_reloc(image_target)) + if (!grub_image_needs_reloc(image_target) || grub_image_needs_abs_reloc(image_target)) { - Elf_Addr current_address = *kernel_sz; + Elf_Addr current_address = target_address + *kernel_sz; for (i = 0, s = sections; i < num_sections; @@ -1558,11 +1579,16 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, section_vaddresses[i] = current_address + image_target->vaddr_offset; current_address += grub_host_to_target_addr (s->sh_size); + + if (!bss_addr) + bss_addr = section_vaddresses[i]; } current_address = ALIGN_UP (current_address + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - *bss_size = current_address - *kernel_sz; + *bss_size = current_address - *kernel_sz - target_address; + grub_util_info ("locating bss at 0x%x-0x%x (0x%x bytes)", + (int)bss_addr, (int)(bss_addr + *bss_size), (int)*bss_size); } else *bss_size = 0; @@ -1603,6 +1629,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, (char *) out_img + ia64jmp_off, ia64jmp_off + image_target->vaddr_offset, + bss_addr, *bss_size, image_target); if (*start == INVALID_START_ADDR) grub_util_error ("start symbol is not defined"); @@ -1612,17 +1639,18 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, /* Resolve addresses in the virtual address space. */ SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize, - num_sections, strtab, + num_sections, strtab, target_address, out_img, tramp_off, ia64_got_off, image_target); - *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, - section_vaddresses, sections, - section_entsize, num_sections, - strtab, ia64jmp_off - + image_target->vaddr_offset, - 2 * ia64jmpnum + (got / 8), - image_target); + if (!grub_image_needs_abs_reloc(image_target)) + *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, + section_vaddresses, sections, + section_entsize, num_sections, + strtab, ia64jmp_off + + image_target->vaddr_offset, + 2 * ia64jmpnum + (got / 8), + image_target); } for (i = 0, s = sections; @@ -1632,10 +1660,10 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size, || SUFFIX (is_text_section) (s, image_target)) { if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) - memset (out_img + section_addresses[i], 0, + memset (out_img + section_addresses[i] - target_address, 0, grub_host_to_target_addr (s->sh_size)); else - memcpy (out_img + section_addresses[i], + memcpy (out_img + section_addresses[i] - target_address, kernel_img + grub_host_to_target_addr (s->sh_offset), grub_host_to_target_addr (s->sh_size)); } diff --git a/util/mkimage.c b/util/mkimage.c index 645e296..7b29acf 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -74,6 +74,7 @@ struct grub_install_image_target_desc PLATFORM_FLAGS_NONE = 0, PLATFORM_FLAGS_DECOMPRESSORS = 2, PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4, + PLATFORM_FLAGS_ABS_RELOC = 8, } flags; unsigned total_module_size; unsigned decompressor_compressed_size; @@ -922,11 +923,16 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) return GRUB_ERR_NONE; } +static int grub_image_needs_abs_reloc(const struct grub_install_image_target_desc *target) +{ + return target->flags & PLATFORM_FLAGS_ABS_RELOC; +} + static int grub_image_needs_reloc(const struct grub_install_image_target_desc *target) { if (target->id == IMAGE_EFI) return 1; - return 0; + return grub_image_needs_abs_reloc(target); } #pragma GCC diagnostic ignored "-Wcast-align" @@ -987,7 +993,8 @@ grub_install_get_image_targets_string (void) void grub_install_generate_image (const char *dir, const char *prefix, - FILE *out, const char *outname, char *mods[], + FILE *out, grub_uint64_t target_address, + const char *outname, char *mods[], char *memdisk_path, char **pubkey_paths, size_t npubkeys, char *config_path, const struct grub_install_image_target_desc *image_target, @@ -1024,6 +1031,13 @@ grub_install_generate_image (const char *dir, const char *prefix, else total_module_size = sizeof (struct grub_module_info32); + if (!target_address && grub_image_needs_abs_reloc(image_target)) + { + grub_util_info ("Using default target address 0x%llx", + (unsigned long long)image_target->link_addr); + target_address = image_target->link_addr; + } + { size_t i; for (i = 0; i < npubkeys; i++) @@ -1069,11 +1083,13 @@ grub_install_generate_image (const char *dir, const char *prefix, if (image_target->voidp_sizeof == 4) kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, - total_module_size, &start_address, &rel_section, + total_module_size, target_address, + &start_address, &rel_section, &reloc_size, &align, image_target); else kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, - total_module_size, &start_address, &rel_section, + total_module_size, target_address, + &start_address, &rel_section, &reloc_size, &align, image_target); if (image_target->id == IMAGE_XEN && align < 4096) align = 4096; -- 1.8.4.rc3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel