216 kx /* grub-mkimage.c - make a bootable image */
216 kx /*
216 kx * GRUB -- GRand Unified Bootloader
216 kx * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
216 kx *
216 kx * GRUB is free software: you can redistribute it and/or modify
216 kx * it under the terms of the GNU General Public License as published by
216 kx * the Free Software Foundation, either version 3 of the License, or
216 kx * (at your option) any later version.
216 kx *
216 kx * GRUB is distributed in the hope that it will be useful,
216 kx * but WITHOUT ANY WARRANTY; without even the implied warranty of
216 kx * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
216 kx * GNU General Public License for more details.
216 kx *
216 kx * You should have received a copy of the GNU General Public License
216 kx * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
216 kx */
216 kx
216 kx #include <config.h>
216 kx #include <grub/types.h>
216 kx #include <grub/elf.h>
216 kx #include <grub/aout.h>
216 kx #include <grub/i18n.h>
216 kx #include <grub/kernel.h>
216 kx #include <grub/disk.h>
216 kx #include <grub/emu/misc.h>
216 kx #include <grub/util/misc.h>
216 kx #include <grub/util/resolve.h>
216 kx #include <grub/misc.h>
216 kx #include <grub/offsets.h>
216 kx #include <grub/crypto.h>
216 kx #include <grub/dl.h>
216 kx #include <time.h>
216 kx #include <multiboot.h>
216 kx
216 kx #include <stdio.h>
216 kx #include <unistd.h>
216 kx #include <string.h>
216 kx #include <stdlib.h>
216 kx #include <assert.h>
216 kx #include <grub/efi/pe32.h>
216 kx #include <grub/uboot/image.h>
216 kx #include <grub/arm/reloc.h>
216 kx #include <grub/arm64/reloc.h>
216 kx #include <grub/ia64/reloc.h>
216 kx #include <grub/osdep/hostfile.h>
216 kx #include <grub/util/install.h>
216 kx #include <grub/util/mkimage.h>
216 kx
216 kx #include <xen/elfnote.h>
216 kx
216 kx #pragma GCC diagnostic ignored "-Wcast-align"
216 kx
216 kx #define GRUB_MKIMAGEXX
216 kx #if !defined(MKIMAGE_ELF32) && !defined(MKIMAGE_ELF64)
216 kx #if __SIZEOF_POINTER__ == 8
216 kx #include "grub-mkimage64.c"
216 kx #else
216 kx #include "grub-mkimage32.c"
216 kx #endif
216 kx #endif
216 kx
216 kx /* These structures are defined according to the CHRP binding to IEEE1275,
216 kx "Client Program Format" section. */
216 kx
216 kx struct grub_ieee1275_note_desc
216 kx {
216 kx grub_uint32_t real_mode;
216 kx grub_uint32_t real_base;
216 kx grub_uint32_t real_size;
216 kx grub_uint32_t virt_base;
216 kx grub_uint32_t virt_size;
216 kx grub_uint32_t load_base;
216 kx };
216 kx
216 kx #define GRUB_IEEE1275_NOTE_NAME "PowerPC"
216 kx #define GRUB_IEEE1275_NOTE_TYPE 0x1275
216 kx
216 kx struct grub_ieee1275_note
216 kx {
216 kx Elf32_Nhdr header;
216 kx char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)];
216 kx struct grub_ieee1275_note_desc descriptor;
216 kx };
216 kx
216 kx #define GRUB_XEN_NOTE_NAME "Xen"
216 kx
216 kx struct fixup_block_list
216 kx {
216 kx struct fixup_block_list *next;
216 kx int state;
216 kx struct grub_pe32_fixup_block b;
216 kx };
216 kx
216 kx #define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
216 kx
216 kx struct section_metadata
216 kx {
216 kx Elf_Half num_sections;
216 kx Elf_Shdr *sections;
216 kx Elf_Addr *addrs;
216 kx Elf_Addr *vaddrs;
216 kx Elf_Half section_entsize;
216 kx Elf_Shdr *symtab;
216 kx const char *strtab;
216 kx };
216 kx
216 kx static int
216 kx is_relocatable (const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT
216 kx || (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM);
216 kx }
216 kx
216 kx #ifdef MKIMAGE_ELF32
216 kx
216 kx /*
216 kx * R_ARM_THM_CALL/THM_JUMP24
216 kx *
216 kx * Relocate Thumb (T32) instruction set relative branches:
216 kx * B.W, BL and BLX
216 kx */
216 kx static grub_err_t
216 kx grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr)
216 kx {
216 kx grub_int32_t offset;
216 kx
216 kx offset = grub_arm_thm_call_get_offset (target);
216 kx
216 kx grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr);
216 kx
216 kx offset += sym_addr;
216 kx
216 kx grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n",
216 kx target, sym_addr, offset);
216 kx
216 kx /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel
216 kx is bigger than 2M (currently under 150K) then we probably have a problem
216 kx somewhere else. */
216 kx if (offset < -0x200000 || offset >= 0x200000)
216 kx return grub_error (GRUB_ERR_BAD_MODULE,
216 kx "THM_CALL Relocation out of range.");
216 kx
216 kx grub_dprintf ("dl", " relative destination = %p",
216 kx (char *) target + offset);
216 kx
216 kx return grub_arm_thm_call_set_offset (target, offset);
216 kx }
216 kx
216 kx /*
216 kx * R_ARM_THM_JUMP19
216 kx *
216 kx * Relocate conditional Thumb (T32) B<c>.W
216 kx */
216 kx static grub_err_t
216 kx grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr)
216 kx {
216 kx grub_int32_t offset;
216 kx
216 kx if (!(sym_addr & 1))
216 kx return grub_error (GRUB_ERR_BAD_MODULE,
216 kx "Relocation targeting wrong execution state");
216 kx
216 kx offset = grub_arm_thm_jump19_get_offset (target);
216 kx
216 kx /* Adjust and re-truncate offset */
216 kx offset += sym_addr;
216 kx
216 kx if (!grub_arm_thm_jump19_check_offset (offset))
216 kx return grub_error (GRUB_ERR_BAD_MODULE,
216 kx "THM_JUMP19 Relocation out of range.");
216 kx
216 kx grub_arm_thm_jump19_set_offset (target, offset);
216 kx
216 kx return GRUB_ERR_NONE;
216 kx }
216 kx
216 kx /*
216 kx * R_ARM_JUMP24
216 kx *
216 kx * Relocate ARM (A32) B
216 kx */
216 kx static grub_err_t
216 kx grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
216 kx {
216 kx grub_int32_t offset;
216 kx
216 kx if (sym_addr & 1)
216 kx return grub_error (GRUB_ERR_BAD_MODULE,
216 kx "Relocation targeting wrong execution state");
216 kx
216 kx offset = grub_arm_jump24_get_offset (target);
216 kx offset += sym_addr;
216 kx
216 kx if (!grub_arm_jump24_check_offset (offset))
216 kx return grub_error (GRUB_ERR_BAD_MODULE,
216 kx "JUMP24 Relocation out of range.");
216 kx
216 kx
216 kx grub_arm_jump24_set_offset (target, offset);
216 kx
216 kx return GRUB_ERR_NONE;
216 kx }
216 kx
216 kx #endif
216 kx
216 kx void
216 kx SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
216 kx int note, char **core_img, size_t *core_size,
216 kx Elf_Addr target_addr,
216 kx struct grub_mkimage_layout *layout)
216 kx {
216 kx char *elf_img;
216 kx size_t program_size;
216 kx Elf_Ehdr *ehdr;
216 kx Elf_Phdr *phdr;
216 kx Elf_Shdr *shdr;
216 kx int header_size, footer_size = 0;
216 kx int phnum = 1;
216 kx int shnum = 4;
216 kx int string_size = sizeof (".text") + sizeof ("mods") + 1;
216 kx
216 kx if (image_target->id != IMAGE_LOONGSON_ELF)
216 kx phnum += 2;
216 kx
216 kx if (note)
216 kx {
216 kx phnum++;
216 kx footer_size += sizeof (struct grub_ieee1275_note);
216 kx }
216 kx if (image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH)
216 kx {
216 kx phnum++;
216 kx shnum++;
216 kx string_size += sizeof (".xen");
216 kx footer_size += (image_target->id == IMAGE_XEN) ? XEN_NOTE_SIZE : XEN_PVH_NOTE_SIZE;
216 kx }
216 kx header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr)
216 kx + shnum * sizeof (*shdr) + string_size, layout->align);
216 kx
216 kx program_size = ALIGN_ADDR (*core_size);
216 kx
216 kx elf_img = xmalloc (program_size + header_size + footer_size);
216 kx memset (elf_img, 0, program_size + header_size + footer_size);
216 kx memcpy (elf_img + header_size, *core_img, *core_size);
216 kx ehdr = (void *) elf_img;
216 kx phdr = (void *) (elf_img + sizeof (*ehdr));
216 kx shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr));
216 kx memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
216 kx ehdr->e_ident[EI_CLASS] = ELFCLASSXX;
216 kx if (!image_target->bigendian)
216 kx ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
216 kx else
216 kx ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
216 kx ehdr->e_ident[EI_VERSION] = EV_CURRENT;
216 kx ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
216 kx ehdr->e_type = grub_host_to_target16 (ET_EXEC);
216 kx ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
216 kx ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
216 kx
216 kx ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
216 kx ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
216 kx ehdr->e_phnum = grub_host_to_target16 (phnum);
216 kx
216 kx ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr
216 kx - (grub_uint8_t *) ehdr);
216 kx if (image_target->id == IMAGE_LOONGSON_ELF)
216 kx ehdr->e_shentsize = grub_host_to_target16 (0);
216 kx else
216 kx ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr));
216 kx ehdr->e_shnum = grub_host_to_target16 (shnum);
216 kx ehdr->e_shstrndx = grub_host_to_target16 (1);
216 kx
216 kx ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
216 kx
216 kx phdr->p_type = grub_host_to_target32 (PT_LOAD);
216 kx phdr->p_offset = grub_host_to_target32 (header_size);
216 kx phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
216 kx
216 kx ehdr->e_entry = grub_host_to_target32 (target_addr);
216 kx phdr->p_vaddr = grub_host_to_target32 (target_addr);
216 kx phdr->p_paddr = grub_host_to_target32 (target_addr);
216 kx phdr->p_align = grub_host_to_target32 (layout->align > image_target->link_align ?
216 kx layout->align : image_target->link_align);
216 kx if (image_target->id == IMAGE_LOONGSON_ELF)
216 kx ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER
216 kx | EF_MIPS_PIC | EF_MIPS_CPIC);
216 kx else
216 kx ehdr->e_flags = 0;
216 kx if (image_target->id == IMAGE_LOONGSON_ELF)
216 kx {
216 kx phdr->p_filesz = grub_host_to_target32 (*core_size);
216 kx phdr->p_memsz = grub_host_to_target32 (*core_size);
216 kx }
216 kx else
216 kx {
216 kx grub_uint32_t target_addr_mods;
216 kx phdr->p_filesz = grub_host_to_target32 (layout->kernel_size);
216 kx if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM)
216 kx phdr->p_memsz = grub_host_to_target32 (layout->kernel_size);
216 kx else
216 kx phdr->p_memsz = grub_host_to_target32 (layout->kernel_size + layout->bss_size);
216 kx
216 kx phdr++;
216 kx phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
216 kx phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size);
216 kx phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
216 kx phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
216 kx phdr->p_align = grub_host_to_target32 (image_target->link_align);
216 kx
216 kx phdr++;
216 kx phdr->p_type = grub_host_to_target32 (PT_LOAD);
216 kx phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size);
216 kx phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
216 kx phdr->p_filesz = phdr->p_memsz
216 kx = grub_host_to_target32 (*core_size - layout->kernel_size);
216 kx
216 kx if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_386)
216 kx target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
216 kx else if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM)
216 kx target_addr_mods = ALIGN_UP (target_addr + layout->end
216 kx + image_target->mod_gap,
216 kx image_target->mod_align);
216 kx else
216 kx target_addr_mods = ALIGN_UP (target_addr + layout->kernel_size + layout->bss_size
216 kx + image_target->mod_gap,
216 kx image_target->mod_align);
216 kx phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods);
216 kx phdr->p_paddr = grub_host_to_target_addr (target_addr_mods);
216 kx phdr->p_align = grub_host_to_target32 (image_target->link_align);
216 kx }
216 kx
216 kx if (image_target->id == IMAGE_XEN)
216 kx {
216 kx char *note_start = (elf_img + program_size + header_size);
216 kx Elf_Nhdr *note_ptr;
216 kx char *ptr = (char *) note_start;
216 kx
216 kx grub_util_info ("adding XEN NOTE segment");
216 kx
216 kx /* Guest OS. */
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (sizeof (PACKAGE_NAME));
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_GUEST_OS);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memcpy (ptr, PACKAGE_NAME, sizeof (PACKAGE_NAME));
216 kx ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4);
216 kx
216 kx /* Loader. */
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (sizeof ("generic"));
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_LOADER);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memcpy (ptr, "generic", sizeof ("generic"));
216 kx ptr += ALIGN_UP (sizeof ("generic"), 4);
216 kx
216 kx /* Version. */
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (sizeof ("xen-3.0"));
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_XEN_VERSION);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memcpy (ptr, "xen-3.0", sizeof ("xen-3.0"));
216 kx ptr += ALIGN_UP (sizeof ("xen-3.0"), 4);
216 kx
216 kx /* Entry. */
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_ENTRY);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memset (ptr, 0, image_target->voidp_sizeof);
216 kx ptr += image_target->voidp_sizeof;
216 kx
216 kx /* Virt base. */
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_VIRT_BASE);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memset (ptr, 0, image_target->voidp_sizeof);
216 kx ptr += image_target->voidp_sizeof;
216 kx
216 kx /* PAE. */
216 kx if (image_target->elf_target == EM_386)
216 kx {
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal"));
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_PAE_MODE);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memcpy (ptr, "yes", sizeof ("yes"));
216 kx ptr += ALIGN_UP (sizeof ("yes"), 4);
216 kx }
216 kx
216 kx assert (XEN_NOTE_SIZE == (ptr - note_start));
216 kx
216 kx phdr++;
216 kx phdr->p_type = grub_host_to_target32 (PT_NOTE);
216 kx phdr->p_flags = grub_host_to_target32 (PF_R);
216 kx phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx phdr->p_vaddr = 0;
216 kx phdr->p_paddr = 0;
216 kx phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE);
216 kx phdr->p_memsz = 0;
216 kx phdr->p_offset = grub_host_to_target32 (header_size + program_size);
216 kx }
216 kx
216 kx if (image_target->id == IMAGE_XEN_PVH)
216 kx {
216 kx char *note_start = (elf_img + program_size + header_size);
216 kx Elf_Nhdr *note_ptr;
216 kx char *ptr = (char *) note_start;
216 kx
216 kx grub_util_info ("adding XEN NOTE segment");
216 kx
216 kx /* Phys32 Entry. */
216 kx note_ptr = (Elf_Nhdr *) ptr;
216 kx note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
216 kx note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_PHYS32_ENTRY);
216 kx ptr += sizeof (Elf_Nhdr);
216 kx memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
216 kx ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
216 kx memset (ptr, 0, image_target->voidp_sizeof);
216 kx *(grub_uint32_t *) ptr = GRUB_KERNEL_I386_XEN_PVH_LINK_ADDR;
216 kx ptr += image_target->voidp_sizeof;
216 kx
216 kx assert (XEN_PVH_NOTE_SIZE == (ptr - note_start));
216 kx
216 kx phdr++;
216 kx phdr->p_type = grub_host_to_target32 (PT_NOTE);
216 kx phdr->p_flags = grub_host_to_target32 (PF_R);
216 kx phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx phdr->p_vaddr = 0;
216 kx phdr->p_paddr = 0;
216 kx phdr->p_filesz = grub_host_to_target32 (XEN_PVH_NOTE_SIZE);
216 kx phdr->p_memsz = 0;
216 kx phdr->p_offset = grub_host_to_target32 (header_size + program_size);
216 kx }
216 kx
216 kx if (note)
216 kx {
216 kx int note_size = sizeof (struct grub_ieee1275_note);
216 kx struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *)
216 kx (elf_img + program_size + header_size);
216 kx
216 kx grub_util_info ("adding CHRP NOTE segment");
216 kx
216 kx note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
216 kx note_ptr->header.n_descsz = grub_host_to_target32 (sizeof (struct grub_ieee1275_note_desc));
216 kx note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
216 kx strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME);
216 kx note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
216 kx note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
216 kx note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
216 kx note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
216 kx note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
216 kx note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
216 kx
216 kx phdr++;
216 kx phdr->p_type = grub_host_to_target32 (PT_NOTE);
216 kx phdr->p_flags = grub_host_to_target32 (PF_R);
216 kx phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx phdr->p_vaddr = 0;
216 kx phdr->p_paddr = 0;
216 kx phdr->p_filesz = grub_host_to_target32 (note_size);
216 kx phdr->p_memsz = 0;
216 kx phdr->p_offset = grub_host_to_target32 (header_size + program_size);
216 kx }
216 kx
216 kx {
216 kx char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
216 kx + shnum * sizeof (*shdr));
216 kx char *ptr = str_start + 1;
216 kx
216 kx shdr++;
216 kx
216 kx shdr->sh_name = grub_host_to_target32 (0);
216 kx shdr->sh_type = grub_host_to_target32 (SHT_STRTAB);
216 kx shdr->sh_addr = grub_host_to_target_addr (0);
216 kx shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img);
216 kx shdr->sh_size = grub_host_to_target32 (string_size);
216 kx shdr->sh_link = grub_host_to_target32 (0);
216 kx shdr->sh_info = grub_host_to_target32 (0);
216 kx shdr->sh_addralign = grub_host_to_target32 (layout->align);
216 kx shdr->sh_entsize = grub_host_to_target32 (0);
216 kx shdr++;
216 kx
216 kx memcpy (ptr, ".text", sizeof (".text"));
216 kx
216 kx shdr->sh_name = grub_host_to_target32 (ptr - str_start);
216 kx ptr += sizeof (".text");
216 kx shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
216 kx shdr->sh_addr = grub_host_to_target_addr (target_addr);
216 kx shdr->sh_offset = grub_host_to_target_addr (header_size);
216 kx shdr->sh_size = grub_host_to_target32 (layout->kernel_size);
216 kx shdr->sh_link = grub_host_to_target32 (0);
216 kx shdr->sh_info = grub_host_to_target32 (0);
216 kx shdr->sh_addralign = grub_host_to_target32 (layout->align);
216 kx shdr->sh_entsize = grub_host_to_target32 (0);
216 kx shdr++;
216 kx
216 kx memcpy (ptr, "mods", sizeof ("mods"));
216 kx shdr->sh_name = grub_host_to_target32 (ptr - str_start);
216 kx ptr += sizeof ("mods");
216 kx shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
216 kx shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size);
216 kx shdr->sh_offset = grub_host_to_target_addr (header_size + layout->kernel_size);
216 kx shdr->sh_size = grub_host_to_target32 (*core_size - layout->kernel_size);
216 kx shdr->sh_link = grub_host_to_target32 (0);
216 kx shdr->sh_info = grub_host_to_target32 (0);
216 kx shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx shdr->sh_entsize = grub_host_to_target32 (0);
216 kx shdr++;
216 kx
216 kx if (image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH)
216 kx {
216 kx memcpy (ptr, ".xen", sizeof (".xen"));
216 kx shdr->sh_name = grub_host_to_target32 (ptr - str_start);
216 kx ptr += sizeof (".xen");
216 kx shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
216 kx shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size);
216 kx shdr->sh_offset = grub_host_to_target_addr (program_size + header_size);
216 kx if (image_target->id == IMAGE_XEN)
216 kx shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE);
216 kx else
216 kx shdr->sh_size = grub_host_to_target32 (XEN_PVH_NOTE_SIZE);
216 kx shdr->sh_link = grub_host_to_target32 (0);
216 kx shdr->sh_info = grub_host_to_target32 (0);
216 kx shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
216 kx shdr->sh_entsize = grub_host_to_target32 (0);
216 kx shdr++;
216 kx }
216 kx }
216 kx
216 kx free (*core_img);
216 kx *core_img = elf_img;
216 kx *core_size = program_size + header_size + footer_size;
216 kx }
216 kx
216 kx /* Relocate symbols; note that this function overwrites the symbol table.
216 kx Return the address of a start symbol. */
216 kx static Elf_Addr
216 kx SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd,
216 kx void *jumpers, Elf_Addr jumpers_addr,
216 kx Elf_Addr bss_start, Elf_Addr end,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx Elf_Word symtab_size, sym_size, num_syms;
216 kx Elf_Off symtab_offset;
216 kx Elf_Addr start_address = (Elf_Addr) -1;
216 kx Elf_Sym *sym;
216 kx Elf_Word i;
216 kx Elf_Shdr *symtab_section;
216 kx const char *symtab;
216 kx grub_uint64_t *jptr = jumpers;
216 kx
216 kx symtab_section = (Elf_Shdr *) ((char *) smd->sections
216 kx + grub_target_to_host32 (smd->symtab->sh_link)
216 kx * smd->section_entsize);
216 kx symtab = (char *) e + grub_target_to_host (symtab_section->sh_offset);
216 kx
216 kx symtab_size = grub_target_to_host (smd->symtab->sh_size);
216 kx sym_size = grub_target_to_host (smd->symtab->sh_entsize);
216 kx symtab_offset = grub_target_to_host (smd->symtab->sh_offset);
216 kx num_syms = symtab_size / sym_size;
216 kx
216 kx for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
216 kx i < num_syms;
216 kx i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
216 kx {
216 kx Elf_Section cur_index;
216 kx const char *name;
216 kx
216 kx name = symtab + grub_target_to_host32 (sym->st_name);
216 kx
216 kx cur_index = grub_target_to_host16 (sym->st_shndx);
216 kx if (cur_index == STN_ABS)
216 kx {
216 kx continue;
216 kx }
216 kx else if (cur_index == STN_UNDEF)
216 kx {
216 kx if (sym->st_name && grub_strcmp (name, "__bss_start") == 0)
216 kx sym->st_value = bss_start;
216 kx else if (sym->st_name && grub_strcmp (name, "_end") == 0)
216 kx sym->st_value = end;
216 kx else if (sym->st_name)
216 kx grub_util_error ("undefined symbol %s", name);
216 kx else
216 kx continue;
216 kx }
216 kx else if (cur_index >= smd->num_sections)
216 kx grub_util_error ("section %d does not exist", cur_index);
216 kx else
216 kx {
216 kx sym->st_value = (grub_target_to_host (sym->st_value)
216 kx + smd->vaddrs[cur_index]);
216 kx }
216 kx
216 kx if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
216 kx == STT_FUNC)
216 kx {
216 kx *jptr = grub_host_to_target64 (sym->st_value);
216 kx sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr;
216 kx jptr++;
216 kx *jptr = 0;
216 kx jptr++;
216 kx }
216 kx grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG
216 kx " (0x%" GRUB_HOST_PRIxLONG_LONG ")", name,
216 kx (unsigned long long) sym->st_value,
216 kx (unsigned long long) smd->vaddrs[cur_index]);
216 kx
216 kx if (start_address == (Elf_Addr)-1)
216 kx if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
216 kx start_address = sym->st_value;
216 kx }
216 kx
216 kx return start_address;
216 kx }
216 kx
216 kx /* Return the address of a symbol at the index I in the section S. */
216 kx static Elf_Addr
216 kx SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx Elf_Sym *sym;
216 kx
216 kx sym = (Elf_Sym *) ((char *) e
216 kx + grub_target_to_host (s->sh_offset)
216 kx + i * grub_target_to_host (s->sh_entsize));
216 kx return sym->st_value;
216 kx }
216 kx
216 kx /* Return the address of a modified value. */
216 kx static Elf_Addr *
216 kx SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
216 kx }
216 kx
216 kx #ifdef MKIMAGE_ELF64
216 kx static Elf_Addr
216 kx SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx Elf_Word symtab_size, sym_size, num_syms;
216 kx Elf_Off symtab_offset;
216 kx Elf_Sym *sym;
216 kx Elf_Word i;
216 kx int ret = 0;
216 kx
216 kx symtab_size = grub_target_to_host (symtab_section->sh_size);
216 kx sym_size = grub_target_to_host (symtab_section->sh_entsize);
216 kx symtab_offset = grub_target_to_host (symtab_section->sh_offset);
216 kx num_syms = symtab_size / sym_size;
216 kx
216 kx for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
216 kx i < num_syms;
216 kx i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
216 kx if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
216 kx ret++;
216 kx
216 kx return ret;
216 kx }
216 kx #endif
216 kx
216 kx #ifdef MKIMAGE_ELF32
216 kx /* Deal with relocation information. This function relocates addresses
216 kx within the virtual address space starting from 0. So only relative
216 kx addresses can be fully resolved. Absolute addresses must be relocated
216 kx again by a PE32 relocator when loaded. */
216 kx static grub_size_t
216 kx arm_get_trampoline_size (Elf_Ehdr *e,
216 kx Elf_Shdr *sections,
216 kx Elf_Half section_entsize,
216 kx Elf_Half num_sections,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx Elf_Half i;
216 kx Elf_Shdr *s;
216 kx grub_size_t ret = 0;
216 kx
216 kx for (i = 0, s = sections;
216 kx i < num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
216 kx if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
216 kx (s->sh_type == grub_host_to_target32 (SHT_RELA)))
216 kx {
216 kx Elf_Rela *r;
216 kx Elf_Word rtab_size, r_size, num_rs;
216 kx Elf_Off rtab_offset;
216 kx Elf_Shdr *symtab_section;
216 kx Elf_Word j;
216 kx
216 kx symtab_section = (Elf_Shdr *) ((char *) sections
216 kx + (grub_target_to_host32 (s->sh_link)
216 kx * section_entsize));
216 kx
216 kx rtab_size = grub_target_to_host (s->sh_size);
216 kx r_size = grub_target_to_host (s->sh_entsize);
216 kx rtab_offset = grub_target_to_host (s->sh_offset);
216 kx num_rs = rtab_size / r_size;
216 kx
216 kx for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
216 kx j < num_rs;
216 kx j++, r = (Elf_Rela *) ((char *) r + r_size))
216 kx {
216 kx Elf_Addr info;
216 kx Elf_Addr sym_addr;
216 kx
216 kx info = grub_target_to_host (r->r_info);
216 kx sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
216 kx ELF_R_SYM (info), image_target);
216 kx
216 kx sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
216 kx grub_target_to_host (r->r_addend) : 0;
216 kx
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_ARM_ABS32:
216 kx case R_ARM_V4BX:
216 kx break;
216 kx case R_ARM_THM_CALL:
216 kx case R_ARM_THM_JUMP24:
216 kx case R_ARM_THM_JUMP19:
216 kx if (!(sym_addr & 1))
216 kx ret += 8;
216 kx break;
216 kx
216 kx case R_ARM_CALL:
216 kx case R_ARM_JUMP24:
216 kx if (sym_addr & 1)
216 kx ret += 16;
216 kx break;
216 kx
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx }
216 kx }
216 kx return ret;
216 kx }
216 kx #endif
216 kx
216 kx static int
216 kx SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target);
216 kx static int
216 kx SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target,
216 kx struct section_metadata *smd);
216 kx
216 kx /* Deal with relocation information. This function relocates addresses
216 kx within the virtual address space starting from 0. So only relative
216 kx addresses can be fully resolved. Absolute addresses must be relocated
216 kx again by a PE32 relocator when loaded. */
216 kx static void
216 kx SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd,
216 kx char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx Elf_Half i;
216 kx Elf_Shdr *s;
216 kx #ifdef MKIMAGE_ELF64
216 kx struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
216 kx grub_uint64_t *gpptr = (void *) (pe_target + got_off);
216 kx unsigned unmatched_adr_got_page = 0;
216 kx #define MASK19 ((1 << 19) - 1)
216 kx #else
216 kx grub_uint32_t *tr = (void *) (pe_target + tramp_off);
216 kx #endif
216 kx
216 kx for (i = 0, s = smd->sections;
216 kx i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
216 kx (s->sh_type == grub_host_to_target32 (SHT_RELA)))
216 kx {
216 kx Elf_Rela *r;
216 kx Elf_Word rtab_size, r_size, num_rs;
216 kx Elf_Off rtab_offset;
216 kx Elf_Word target_section_index;
216 kx Elf_Addr target_section_addr;
216 kx Elf_Shdr *target_section;
216 kx Elf_Word j;
216 kx
216 kx if (!SUFFIX (is_kept_section) (s, image_target) &&
216 kx !SUFFIX (is_kept_reloc_section) (s, image_target, smd))
216 kx {
216 kx grub_util_info ("not translating relocations for omitted section %s",
216 kx smd->strtab + grub_le_to_cpu32 (s->sh_name));
216 kx continue;
216 kx }
216 kx
216 kx target_section_index = grub_target_to_host32 (s->sh_info);
216 kx target_section_addr = smd->addrs[target_section_index];
216 kx target_section = (Elf_Shdr *) ((char *) smd->sections
216 kx + (target_section_index
216 kx * smd->section_entsize));
216 kx
216 kx grub_util_info ("dealing with the relocation section %s for %s",
216 kx smd->strtab + grub_target_to_host32 (s->sh_name),
216 kx smd->strtab + grub_target_to_host32 (target_section->sh_name));
216 kx
216 kx rtab_size = grub_target_to_host (s->sh_size);
216 kx r_size = grub_target_to_host (s->sh_entsize);
216 kx rtab_offset = grub_target_to_host (s->sh_offset);
216 kx num_rs = rtab_size / r_size;
216 kx
216 kx for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
216 kx j < num_rs;
216 kx j++, r = (Elf_Rela *) ((char *) r + r_size))
216 kx {
216 kx Elf_Addr info;
216 kx Elf_Addr offset;
216 kx Elf_Addr sym_addr;
216 kx Elf_Addr *target;
216 kx Elf_Addr addend;
216 kx
216 kx offset = grub_target_to_host (r->r_offset);
216 kx target = SUFFIX (get_target_address) (e, target_section,
216 kx offset, image_target);
216 kx info = grub_target_to_host (r->r_info);
216 kx sym_addr = SUFFIX (get_symbol_address) (e, smd->symtab,
216 kx ELF_R_SYM (info), image_target);
216 kx
216 kx addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
216 kx grub_target_to_host (r->r_addend) : 0;
216 kx
216 kx switch (image_target->elf_target)
216 kx {
216 kx case EM_386:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_386_NONE:
216 kx break;
216 kx
216 kx case R_386_32:
216 kx /* This is absolute. */
216 kx *target = grub_host_to_target32 (grub_target_to_host32 (*target)
216 kx + addend + sym_addr);
216 kx grub_util_info ("relocating an R_386_32 entry to 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) *target,
216 kx (unsigned long long) offset);
216 kx break;
216 kx
216 kx case R_386_PC32:
216 kx /* This is relative. */
216 kx *target = grub_host_to_target32 (grub_target_to_host32 (*target)
216 kx + addend + sym_addr
216 kx - target_section_addr - offset
216 kx - image_target->vaddr_offset);
216 kx grub_util_info ("relocating an R_386_PC32 entry to 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) *target,
216 kx (unsigned long long) offset);
216 kx break;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx #ifdef MKIMAGE_ELF64
216 kx case EM_X86_64:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx
216 kx case R_X86_64_NONE:
216 kx break;
216 kx
216 kx case R_X86_64_64:
216 kx *target = grub_host_to_target64 (grub_target_to_host64 (*target)
216 kx + addend + sym_addr);
216 kx grub_util_info ("relocating an R_X86_64_64 entry to 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) *target,
216 kx (unsigned long long) offset);
216 kx break;
216 kx
216 kx case R_X86_64_PC32:
216 kx case R_X86_64_PLT32:
216 kx {
216 kx grub_uint32_t *t32 = (grub_uint32_t *) target;
216 kx *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
216 kx + addend + sym_addr
216 kx - target_section_addr - offset
216 kx - image_target->vaddr_offset);
216 kx grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx *t32, (unsigned long long) offset);
216 kx break;
216 kx }
216 kx
216 kx case R_X86_64_PC64:
216 kx {
216 kx *target = grub_host_to_target64 (grub_target_to_host64 (*target)
216 kx + addend + sym_addr
216 kx - target_section_addr - offset
216 kx - image_target->vaddr_offset);
216 kx grub_util_info ("relocating an R_X86_64_PC64 entry to 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) *target,
216 kx (unsigned long long) offset);
216 kx break;
216 kx }
216 kx
216 kx case R_X86_64_32:
216 kx case R_X86_64_32S:
216 kx {
216 kx grub_uint32_t *t32 = (grub_uint32_t *) target;
216 kx *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
216 kx + addend + sym_addr);
216 kx grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx *t32, (unsigned long long) offset);
216 kx break;
216 kx }
216 kx
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx case EM_IA_64:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_IA64_PCREL21B:
216 kx {
216 kx grub_uint64_t noff;
216 kx grub_ia64_make_trampoline (tr, addend + sym_addr);
216 kx noff = ((char *) tr - (char *) pe_target
216 kx - target_section_addr - (offset & ~3)) >> 4;
216 kx tr++;
216 kx if (noff & ~MASK19)
216 kx grub_util_error ("trampoline offset too big (%"
216 kx GRUB_HOST_PRIxLONG_LONG ")",
216 kx (unsigned long long) noff);
216 kx grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff);
216 kx }
216 kx break;
216 kx
216 kx case R_IA64_LTOFF22X:
216 kx case R_IA64_LTOFF22:
216 kx {
216 kx Elf_Sym *sym;
216 kx
216 kx sym = (Elf_Sym *) ((char *) e
216 kx + grub_target_to_host (smd->symtab->sh_offset)
216 kx + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize));
216 kx if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
216 kx sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
216 kx + sym->st_value
216 kx - image_target->vaddr_offset));
216 kx }
216 kx /* FALLTHROUGH */
216 kx case R_IA64_LTOFF_FPTR22:
216 kx *gpptr = grub_host_to_target64 (addend + sym_addr);
216 kx grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
216 kx (char *) gpptr - (char *) pe_target
216 kx + image_target->vaddr_offset);
216 kx gpptr++;
216 kx break;
216 kx
216 kx case R_IA64_GPREL22:
216 kx grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
216 kx addend + sym_addr);
216 kx break;
216 kx case R_IA64_GPREL64I:
216 kx grub_ia64_set_immu64 ((grub_addr_t) target,
216 kx addend + sym_addr);
216 kx break;
216 kx case R_IA64_PCREL64LSB:
216 kx *target = grub_host_to_target64 (grub_target_to_host64 (*target)
216 kx + addend + sym_addr
216 kx - target_section_addr - offset
216 kx - image_target->vaddr_offset);
216 kx break;
216 kx
216 kx case R_IA64_SEGREL64LSB:
216 kx *target = grub_host_to_target64 (grub_target_to_host64 (*target)
216 kx + addend + sym_addr - target_section_addr);
216 kx break;
216 kx case R_IA64_DIR64LSB:
216 kx case R_IA64_FPTR64LSB:
216 kx *target = grub_host_to_target64 (grub_target_to_host64 (*target)
216 kx + addend + sym_addr);
216 kx grub_util_info ("relocating a direct entry to 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG " at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long)
216 kx grub_target_to_host64 (*target),
216 kx (unsigned long long) offset);
216 kx break;
216 kx
216 kx /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
216 kx case R_IA64_LDXMOV:
216 kx break;
216 kx
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx case EM_AARCH64:
216 kx {
216 kx sym_addr += addend;
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_AARCH64_ABS64:
216 kx {
216 kx *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
216 kx }
216 kx break;
216 kx case R_AARCH64_PREL32:
216 kx {
216 kx grub_uint32_t *t32 = (grub_uint32_t *) target;
216 kx *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
216 kx + sym_addr
216 kx - target_section_addr - offset
216 kx - image_target->vaddr_offset);
216 kx grub_util_info ("relocating an R_AARCH64_PREL32 entry to 0x%x at the offset 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx *t32, (unsigned long long) offset);
216 kx break;
216 kx }
216 kx case R_AARCH64_ADD_ABS_LO12_NC:
216 kx grub_arm64_set_abs_lo12 ((grub_uint32_t *) target,
216 kx sym_addr);
216 kx break;
216 kx case R_AARCH64_LDST64_ABS_LO12_NC:
216 kx grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) target,
216 kx sym_addr);
216 kx break;
216 kx case R_AARCH64_JUMP26:
216 kx case R_AARCH64_CALL26:
216 kx {
216 kx sym_addr -= offset;
216 kx sym_addr -= target_section_addr + image_target->vaddr_offset;
216 kx if (!grub_arm_64_check_xxxx26_offset (sym_addr))
216 kx grub_util_error ("%s", "CALL26 Relocation out of range");
216 kx
216 kx grub_arm64_set_xxxx26_offset((grub_uint32_t *)target,
216 kx sym_addr);
216 kx }
216 kx break;
216 kx case R_AARCH64_ADR_GOT_PAGE:
216 kx {
216 kx Elf64_Rela *rel2;
216 kx grub_int64_t gpoffset = (((char *) gpptr - (char *) pe_target + image_target->vaddr_offset) & ~0xfffULL)
216 kx - ((offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL);
216 kx unsigned k;
216 kx *gpptr = grub_host_to_target64 (sym_addr);
216 kx unmatched_adr_got_page++;
216 kx if (!grub_arm64_check_hi21_signed (gpoffset))
216 kx grub_util_error ("HI21 out of range");
216 kx grub_arm64_set_hi21((grub_uint32_t *)target,
216 kx gpoffset);
216 kx for (k = 0, rel2 = (Elf_Rela *) ((char *) r + r_size);
216 kx k < num_rs;
216 kx k++, rel2 = (Elf_Rela *) ((char *) rel2 + r_size))
216 kx if (ELF_R_SYM (rel2->r_info)
216 kx == ELF_R_SYM (r->r_info)
216 kx && r->r_addend == rel2->r_addend
216 kx && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC)
216 kx {
216 kx grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) SUFFIX (get_target_address) (e, target_section,
216 kx grub_target_to_host (rel2->r_offset), image_target),
216 kx ((char *) gpptr - (char *) pe_target + image_target->vaddr_offset));
216 kx break;
216 kx }
216 kx if (k >= num_rs)
216 kx grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC");
216 kx gpptr++;
216 kx }
216 kx break;
216 kx case R_AARCH64_LD64_GOT_LO12_NC:
216 kx if (unmatched_adr_got_page == 0)
216 kx grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE");
216 kx unmatched_adr_got_page--;
216 kx break;
216 kx case R_AARCH64_ADR_PREL_PG_HI21:
216 kx {
216 kx sym_addr &= ~0xfffULL;
216 kx sym_addr -= (offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL;
216 kx if (!grub_arm64_check_hi21_signed (sym_addr))
216 kx grub_util_error ("%s", "CALL26 Relocation out of range");
216 kx
216 kx grub_arm64_set_hi21((grub_uint32_t *)target,
216 kx sym_addr);
216 kx }
216 kx break;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx }
216 kx #endif
216 kx #if defined(MKIMAGE_ELF32)
216 kx case EM_ARM:
216 kx {
216 kx sym_addr += addend;
216 kx sym_addr -= image_target->vaddr_offset;
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_ARM_ABS32:
216 kx {
216 kx grub_util_info (" ABS32:\toffset=%d\t(0x%08x)",
216 kx (int) sym_addr, (int) sym_addr);
216 kx /* Data will be naturally aligned */
216 kx if (image_target->id == IMAGE_EFI)
216 kx sym_addr += GRUB_PE32_SECTION_ALIGNMENT;
216 kx *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr);
216 kx }
216 kx break;
216 kx /* Happens when compiled with -march=armv4.
216 kx Since currently we need at least armv5, keep bx as-is.
216 kx */
216 kx case R_ARM_V4BX:
216 kx break;
216 kx case R_ARM_THM_CALL:
216 kx case R_ARM_THM_JUMP24:
216 kx case R_ARM_THM_JUMP19:
216 kx {
216 kx grub_err_t err;
216 kx Elf_Sym *sym;
216 kx grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)",
216 kx (unsigned long) ((char *) target
216 kx - (char *) e),
216 kx sym_addr);
216 kx sym = (Elf_Sym *) ((char *) e
216 kx + grub_target_to_host (smd->symtab->sh_offset)
216 kx + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize));
216 kx if (ELF_ST_TYPE (sym->st_info) != STT_FUNC)
216 kx sym_addr |= 1;
216 kx if (!(sym_addr & 1))
216 kx {
216 kx grub_uint32_t tr_addr;
216 kx grub_int32_t new_offset;
216 kx tr_addr = (char *) tr - (char *) pe_target
216 kx - target_section_addr;
216 kx new_offset = sym_addr - tr_addr - 12;
216 kx
216 kx if (!grub_arm_jump24_check_offset (new_offset))
216 kx return grub_util_error ("jump24 relocation out of range");
216 kx
216 kx tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop */
216 kx tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */
216 kx tr += 2;
216 kx sym_addr = tr_addr | 1;
216 kx }
216 kx sym_addr -= offset;
216 kx /* Thumb instructions can be 16-bit aligned */
216 kx if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19)
216 kx err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
216 kx else
216 kx err = grub_arm_reloc_thm_call ((grub_uint16_t *) target,
216 kx sym_addr);
216 kx if (err)
216 kx grub_util_error ("%s", grub_errmsg);
216 kx }
216 kx break;
216 kx
216 kx case R_ARM_CALL:
216 kx case R_ARM_JUMP24:
216 kx {
216 kx grub_err_t err;
216 kx grub_util_info (" JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), sym_addr);
216 kx if (sym_addr & 1)
216 kx {
216 kx grub_uint32_t tr_addr;
216 kx grub_int32_t new_offset;
216 kx tr_addr = (char *) tr - (char *) pe_target
216 kx - target_section_addr;
216 kx new_offset = sym_addr - tr_addr - 12;
216 kx
216 kx /* There is no immediate version of bx, only register one... */
216 kx tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr ip, [pc, #4] */
216 kx tr[1] = grub_host_to_target32 (0xe08cc00f); /* add ip, ip, pc */
216 kx tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx ip */
216 kx tr[3] = grub_host_to_target32 (new_offset | 1);
216 kx tr += 4;
216 kx sym_addr = tr_addr;
216 kx }
216 kx sym_addr -= offset;
216 kx err = grub_arm_reloc_jump24 (target,
216 kx sym_addr);
216 kx if (err)
216 kx grub_util_error ("%s", grub_errmsg);
216 kx }
216 kx break;
216 kx
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx }
216 kx #endif /* MKIMAGE_ELF32 */
216 kx case EM_RISCV:
216 kx {
216 kx grub_uint64_t *t64 = (grub_uint64_t *) target;
216 kx grub_uint32_t *t32 = (grub_uint32_t *) target;
216 kx grub_uint16_t *t16 = (grub_uint16_t *) target;
216 kx grub_uint8_t *t8 = (grub_uint8_t *) target;
216 kx grub_int64_t off;
216 kx
216 kx /*
216 kx * Instructions and instruction encoding are documented in the RISC-V
216 kx * specification. This file is based on version 2.2:
216 kx *
216 kx * https://github.com/riscv/riscv-isa-manual/blob/master/release/riscv-spec-v2.2.pdf
216 kx */
216 kx
216 kx sym_addr += addend;
216 kx off = sym_addr - target_section_addr - offset - image_target->vaddr_offset;
216 kx
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_RISCV_ADD8:
216 kx *t8 = *t8 + sym_addr;
216 kx break;
216 kx case R_RISCV_ADD16:
216 kx *t16 = grub_host_to_target16 (grub_target_to_host16 (*t16) + sym_addr);
216 kx break;
216 kx case R_RISCV_32:
216 kx case R_RISCV_ADD32:
216 kx *t32 = grub_host_to_target32 (grub_target_to_host32 (*t32) + sym_addr);
216 kx break;
216 kx case R_RISCV_64:
216 kx case R_RISCV_ADD64:
216 kx *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) + sym_addr);
216 kx break;
216 kx
216 kx case R_RISCV_SUB8:
216 kx *t8 = sym_addr - *t8;
216 kx break;
216 kx case R_RISCV_SUB16:
216 kx *t16 = grub_host_to_target16 (grub_target_to_host16 (*t16) - sym_addr);
216 kx break;
216 kx case R_RISCV_SUB32:
216 kx *t32 = grub_host_to_target32 (grub_target_to_host32 (*t32) - sym_addr);
216 kx break;
216 kx case R_RISCV_SUB64:
216 kx *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) - sym_addr);
216 kx break;
216 kx case R_RISCV_BRANCH:
216 kx {
216 kx grub_uint32_t imm12 = (off & 0x1000) << (31 - 12);
216 kx grub_uint32_t imm11 = (off & 0x800) >> (11 - 7);
216 kx grub_uint32_t imm10_5 = (off & 0x7e0) << (30 - 10);
216 kx grub_uint32_t imm4_1 = (off & 0x1e) << (11 - 4);
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f)
216 kx | imm12 | imm11 | imm10_5 | imm4_1);
216 kx }
216 kx break;
216 kx case R_RISCV_JAL:
216 kx {
216 kx grub_uint32_t imm20 = (off & 0x100000) << (31 - 20);
216 kx grub_uint32_t imm19_12 = (off & 0xff000);
216 kx grub_uint32_t imm11 = (off & 0x800) << (20 - 11);
216 kx grub_uint32_t imm10_1 = (off & 0x7fe) << (30 - 10);
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff)
216 kx | imm20 | imm19_12 | imm11 | imm10_1);
216 kx }
216 kx break;
216 kx case R_RISCV_CALL:
216 kx case R_RISCV_CALL_PLT:
216 kx {
216 kx grub_uint32_t hi20, lo12;
216 kx
216 kx if (off != (grub_int32_t)off)
216 kx grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e));
216 kx
216 kx hi20 = (off + 0x800) & 0xfffff000;
216 kx lo12 = (off - hi20) & 0xfff;
216 kx t32[0] = grub_host_to_target32 ((grub_target_to_host32 (t32[0]) & 0xfff) | hi20);
216 kx t32[1] = grub_host_to_target32 ((grub_target_to_host32 (t32[1]) & 0xfffff) | (lo12 << 20));
216 kx }
216 kx break;
216 kx case R_RISCV_RVC_BRANCH:
216 kx {
216 kx grub_uint16_t imm8 = (off & 0x100) << (12 - 8);
216 kx grub_uint16_t imm7_6 = (off & 0xc0) >> (6 - 5);
216 kx grub_uint16_t imm5 = (off & 0x20) >> (5 - 2);
216 kx grub_uint16_t imm4_3 = (off & 0x18) << (12 - 5);
216 kx grub_uint16_t imm2_1 = (off & 0x6) << (12 - 10);
216 kx *t16 = grub_host_to_target16 ((grub_target_to_host16 (*t16) & 0xe383)
216 kx | imm8 | imm7_6 | imm5 | imm4_3 | imm2_1);
216 kx }
216 kx break;
216 kx case R_RISCV_RVC_JUMP:
216 kx {
216 kx grub_uint16_t imm11 = (off & 0x800) << (12 - 11);
216 kx grub_uint16_t imm10 = (off & 0x400) >> (10 - 8);
216 kx grub_uint16_t imm9_8 = (off & 0x300) << (12 - 11);
216 kx grub_uint16_t imm7 = (off & 0x80) >> (7 - 6);
216 kx grub_uint16_t imm6 = (off & 0x40) << (12 - 11);
216 kx grub_uint16_t imm5 = (off & 0x20) >> (5 - 2);
216 kx grub_uint16_t imm4 = (off & 0x10) << (12 - 5);
216 kx grub_uint16_t imm3_1 = (off & 0xe) << (12 - 10);
216 kx *t16 = grub_host_to_target16 ((grub_target_to_host16 (*t16) & 0xe003)
216 kx | imm11 | imm10 | imm9_8 | imm7 | imm6
216 kx | imm5 | imm4 | imm3_1);
216 kx }
216 kx break;
216 kx case R_RISCV_PCREL_HI20:
216 kx {
216 kx grub_int32_t hi20;
216 kx
216 kx if (off != (grub_int32_t)off)
216 kx grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e));
216 kx
216 kx hi20 = (off + 0x800) & 0xfffff000;
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) | hi20);
216 kx }
216 kx break;
216 kx case R_RISCV_PCREL_LO12_I:
216 kx case R_RISCV_PCREL_LO12_S:
216 kx {
216 kx Elf_Rela *rel2;
216 kx Elf_Word k;
216 kx /* Search backwards for matching HI20 reloc. */
216 kx for (k = j, rel2 = (Elf_Rela *) ((char *) r - r_size);
216 kx k > 0;
216 kx k--, rel2 = (Elf_Rela *) ((char *) rel2 - r_size))
216 kx {
216 kx Elf_Addr rel2_info;
216 kx Elf_Addr rel2_offset;
216 kx Elf_Addr rel2_sym_addr;
216 kx Elf_Addr rel2_addend;
216 kx Elf_Addr rel2_loc;
216 kx grub_int64_t rel2_off;
216 kx
216 kx rel2_offset = grub_target_to_host (rel2->r_offset);
216 kx rel2_info = grub_target_to_host (rel2->r_info);
216 kx rel2_loc = target_section_addr + rel2_offset + image_target->vaddr_offset;
216 kx
216 kx if (ELF_R_TYPE (rel2_info) == R_RISCV_PCREL_HI20
216 kx && rel2_loc == sym_addr)
216 kx {
216 kx rel2_sym_addr = SUFFIX (get_symbol_address)
216 kx (e, smd->symtab, ELF_R_SYM (rel2_info),
216 kx image_target);
216 kx rel2_addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
216 kx grub_target_to_host (rel2->r_addend) : 0;
216 kx rel2_off = rel2_sym_addr + rel2_addend - rel2_loc;
216 kx off = rel2_off - ((rel2_off + 0x800) & 0xfffff000);
216 kx
216 kx if (ELF_R_TYPE (info) == R_RISCV_PCREL_LO12_I)
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfffff) | (off & 0xfff) << 20);
216 kx else
216 kx {
216 kx grub_uint32_t imm11_5 = (off & 0xfe0) << (31 - 11);
216 kx grub_uint32_t imm4_0 = (off & 0x1f) << (11 - 4);
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) | imm11_5 | imm4_0);
216 kx }
216 kx break;
216 kx }
216 kx }
216 kx if (k == 0)
216 kx grub_util_error ("cannot find matching HI20 relocation");
216 kx }
216 kx break;
216 kx case R_RISCV_HI20:
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) | (((grub_int32_t) sym_addr + 0x800) & 0xfffff000));
216 kx break;
216 kx case R_RISCV_LO12_I:
216 kx {
216 kx grub_int32_t lo12 = (grub_int32_t) sym_addr - (((grub_int32_t) sym_addr + 0x800) & 0xfffff000);
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfffff) | ((lo12 & 0xfff) << 20));
216 kx }
216 kx break;
216 kx case R_RISCV_LO12_S:
216 kx {
216 kx grub_int32_t lo12 = (grub_int32_t) sym_addr - (((grub_int32_t) sym_addr + 0x800) & 0xfffff000);
216 kx grub_uint32_t imm11_5 = (lo12 & 0xfe0) << (31 - 11);
216 kx grub_uint32_t imm4_0 = (lo12 & 0x1f) << (11 - 4);
216 kx *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) | imm11_5 | imm4_0);
216 kx }
216 kx break;
216 kx case R_RISCV_RELAX:
216 kx break;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx }
216 kx default:
216 kx grub_util_error ("unknown architecture type %d",
216 kx image_target->elf_target);
216 kx }
216 kx }
216 kx }
216 kx }
216 kx
216 kx /* Add a PE32's fixup entry for a relocation. Return the resulting address
216 kx after having written to the file OUT. */
216 kx static Elf_Addr
216 kx add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
216 kx Elf_Addr addr, int flush, Elf_Addr current_address,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx struct grub_pe32_fixup_block *b;
216 kx
216 kx b = &((*cblock)->b);
216 kx
216 kx /* First, check if it is necessary to write out the current block. */
216 kx if ((*cblock)->state)
216 kx {
216 kx if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr)
216 kx {
216 kx grub_uint32_t size;
216 kx
216 kx if (flush)
216 kx {
216 kx /* Add as much padding as necessary to align the address
216 kx with a section boundary. */
216 kx Elf_Addr next_address;
216 kx unsigned padding_size;
216 kx size_t cur_index;
216 kx
216 kx next_address = current_address + b->block_size;
216 kx padding_size = ((ALIGN_UP (next_address, image_target->section_align)
216 kx - next_address)
216 kx >> 1);
216 kx cur_index = ((b->block_size - sizeof (*b)) >> 1);
216 kx grub_util_info ("adding %d padding fixup entries", padding_size);
216 kx while (padding_size--)
216 kx {
216 kx b->entries[cur_index++] = 0;
216 kx b->block_size += 2;
216 kx }
216 kx }
216 kx else while (b->block_size & (8 - 1))
216 kx {
216 kx /* If not aligned with a 32-bit boundary, add
216 kx a padding entry. */
216 kx size_t cur_index;
216 kx
216 kx grub_util_info ("adding a padding fixup entry");
216 kx cur_index = ((b->block_size - sizeof (*b)) >> 1);
216 kx b->entries[cur_index] = 0;
216 kx b->block_size += 2;
216 kx }
216 kx
216 kx /* Flush it. */
216 kx grub_util_info ("writing %d bytes of a fixup block starting at 0x%x",
216 kx b->block_size, b->page_rva);
216 kx size = b->block_size;
216 kx current_address += size;
216 kx b->page_rva = grub_host_to_target32 (b->page_rva);
216 kx b->block_size = grub_host_to_target32 (b->block_size);
216 kx (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000);
216 kx memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000);
216 kx *cblock = (*cblock)->next;
216 kx }
216 kx }
216 kx
216 kx b = &((*cblock)->b);
216 kx
216 kx if (! flush)
216 kx {
216 kx grub_uint16_t entry;
216 kx size_t cur_index;
216 kx
216 kx /* If not allocated yet, allocate a block with enough entries. */
216 kx if (! (*cblock)->state)
216 kx {
216 kx (*cblock)->state = 1;
216 kx
216 kx /* The spec does not mention the requirement of a Page RVA.
216 kx Here, align the address with a 4K boundary for safety. */
216 kx b->page_rva = (addr & ~(0x1000 - 1));
216 kx b->block_size = sizeof (*b);
216 kx }
216 kx
216 kx /* Sanity check. */
216 kx if (b->block_size >= sizeof (*b) + 2 * 0x1000)
216 kx grub_util_error ("too many fixup entries");
216 kx
216 kx /* Add a new entry. */
216 kx cur_index = ((b->block_size - sizeof (*b)) >> 1);
216 kx entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
216 kx b->entries[cur_index] = grub_host_to_target16 (entry);
216 kx b->block_size += 2;
216 kx }
216 kx
216 kx return current_address;
216 kx }
216 kx
216 kx struct raw_reloc
216 kx {
216 kx struct raw_reloc *next;
216 kx grub_uint32_t offset;
216 kx enum raw_reloc_type {
216 kx RAW_RELOC_NONE = -1,
216 kx RAW_RELOC_32 = 0,
216 kx RAW_RELOC_MAX = 1,
216 kx } type;
216 kx };
216 kx
216 kx struct translate_context
216 kx {
216 kx /* PE */
216 kx struct fixup_block_list *lst, *lst0;
216 kx Elf_Addr current_address;
216 kx
216 kx /* Raw */
216 kx struct raw_reloc *raw_relocs;
216 kx };
216 kx
216 kx static void
216 kx translate_reloc_start (struct translate_context *ctx,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx grub_memset (ctx, 0, sizeof (*ctx));
216 kx if (image_target->id == IMAGE_EFI)
216 kx {
216 kx ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000);
216 kx memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000);
216 kx ctx->current_address = 0;
216 kx }
216 kx }
216 kx
216 kx static void
216 kx translate_relocation_pe (struct translate_context *ctx,
216 kx Elf_Addr addr,
216 kx Elf_Addr info,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx /* Necessary to relocate only absolute addresses. */
216 kx switch (image_target->elf_target)
216 kx {
216 kx case EM_386:
216 kx if (ELF_R_TYPE (info) == R_386_32)
216 kx {
216 kx grub_util_info ("adding a relocation entry for 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) addr);
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_HIGHLOW,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx case EM_X86_64:
216 kx if ((ELF_R_TYPE (info) == R_X86_64_32) ||
216 kx (ELF_R_TYPE (info) == R_X86_64_32S))
216 kx {
216 kx grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)");
216 kx }
216 kx else if (ELF_R_TYPE (info) == R_X86_64_64)
216 kx {
216 kx grub_util_info ("adding a relocation entry for 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) addr);
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_DIR64,
216 kx addr,
216 kx 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx case EM_IA_64:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_IA64_PCREL64LSB:
216 kx case R_IA64_LDXMOV:
216 kx case R_IA64_PCREL21B:
216 kx case R_IA64_LTOFF_FPTR22:
216 kx case R_IA64_LTOFF22X:
216 kx case R_IA64_LTOFF22:
216 kx case R_IA64_GPREL22:
216 kx case R_IA64_GPREL64I:
216 kx case R_IA64_SEGREL64LSB:
216 kx break;
216 kx
216 kx case R_IA64_FPTR64LSB:
216 kx case R_IA64_DIR64LSB:
216 kx #if 1
216 kx {
216 kx grub_util_info ("adding a relocation entry for 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx (unsigned long long) addr);
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_DIR64,
216 kx addr,
216 kx 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx #endif
216 kx break;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx case EM_AARCH64:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_AARCH64_ABS64:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_DIR64,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx /* Relative relocations do not require fixup entries. */
216 kx case R_AARCH64_CALL26:
216 kx case R_AARCH64_JUMP26:
216 kx case R_AARCH64_PREL32:
216 kx break;
216 kx /* Page-relative relocations do not require fixup entries. */
216 kx case R_AARCH64_ADR_PREL_PG_HI21:
216 kx /* We page-align the whole kernel, so no need
216 kx for fixup entries.
216 kx */
216 kx case R_AARCH64_ADD_ABS_LO12_NC:
216 kx case R_AARCH64_LDST64_ABS_LO12_NC:
216 kx break;
216 kx
216 kx /* GOT is relocated separately. */
216 kx case R_AARCH64_ADR_GOT_PAGE:
216 kx case R_AARCH64_LD64_GOT_LO12_NC:
216 kx break;
216 kx
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx break;
216 kx #if defined(MKIMAGE_ELF32)
216 kx case EM_ARM:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_ARM_V4BX:
216 kx /* Relative relocations do not require fixup entries. */
216 kx case R_ARM_JUMP24:
216 kx case R_ARM_THM_CALL:
216 kx case R_ARM_THM_JUMP19:
216 kx case R_ARM_THM_JUMP24:
216 kx case R_ARM_CALL:
216 kx {
216 kx grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address);
216 kx }
216 kx break;
216 kx /* Create fixup entry for PE/COFF loader */
216 kx case R_ARM_ABS32:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_HIGHLOW,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx #endif /* defined(MKIMAGE_ELF32) */
216 kx case EM_RISCV:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_RISCV_32:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_HIGHLOW,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx case R_RISCV_64:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_DIR64,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx /* Relative relocations do not require fixup entries. */
216 kx case R_RISCV_BRANCH:
216 kx case R_RISCV_JAL:
216 kx case R_RISCV_CALL:
216 kx case R_RISCV_CALL_PLT:
216 kx case R_RISCV_PCREL_HI20:
216 kx case R_RISCV_PCREL_LO12_I:
216 kx case R_RISCV_PCREL_LO12_S:
216 kx case R_RISCV_RVC_BRANCH:
216 kx case R_RISCV_RVC_JUMP:
216 kx case R_RISCV_ADD32:
216 kx case R_RISCV_SUB32:
216 kx grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address);
216 kx break;
216 kx case R_RISCV_HI20:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_RISCV_HI20,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx case R_RISCV_LO12_I:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_RISCV_LOW12I,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx case R_RISCV_LO12_S:
216 kx {
216 kx ctx->current_address
216 kx = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_RISCV_LOW12S,
216 kx addr, 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx break;
216 kx case R_RISCV_RELAX:
216 kx break;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx default:
216 kx grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
216 kx }
216 kx }
216 kx
216 kx static enum raw_reloc_type
216 kx classify_raw_reloc (Elf_Addr info,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx /* Necessary to relocate only absolute addresses. */
216 kx switch (image_target->elf_target)
216 kx {
216 kx case EM_ARM:
216 kx switch (ELF_R_TYPE (info))
216 kx {
216 kx case R_ARM_V4BX:
216 kx case R_ARM_JUMP24:
216 kx case R_ARM_THM_CALL:
216 kx case R_ARM_THM_JUMP19:
216 kx case R_ARM_THM_JUMP24:
216 kx case R_ARM_CALL:
216 kx return RAW_RELOC_NONE;
216 kx case R_ARM_ABS32:
216 kx return RAW_RELOC_32;
216 kx default:
216 kx grub_util_error (_("relocation 0x%x is not implemented yet"),
216 kx (unsigned int) ELF_R_TYPE (info));
216 kx break;
216 kx }
216 kx break;
216 kx default:
216 kx grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
216 kx }
216 kx }
216 kx
216 kx static void
216 kx translate_relocation_raw (struct translate_context *ctx,
216 kx Elf_Addr addr,
216 kx Elf_Addr info,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx enum raw_reloc_type class = classify_raw_reloc (info, image_target);
216 kx struct raw_reloc *rel;
216 kx if (class == RAW_RELOC_NONE)
216 kx return;
216 kx rel = xmalloc (sizeof (*rel));
216 kx rel->next = ctx->raw_relocs;
216 kx rel->type = class;
216 kx rel->offset = addr;
216 kx ctx->raw_relocs = rel;
216 kx }
216 kx
216 kx static void
216 kx translate_relocation (struct translate_context *ctx,
216 kx Elf_Addr addr,
216 kx Elf_Addr info,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx if (image_target->id == IMAGE_EFI)
216 kx translate_relocation_pe (ctx, addr, info, image_target);
216 kx else
216 kx translate_relocation_raw (ctx, addr, info, image_target);
216 kx }
216 kx
216 kx static void
216 kx finish_reloc_translation_pe (struct translate_context *ctx, struct grub_mkimage_layout *layout,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target);
216 kx
216 kx {
216 kx grub_uint8_t *ptr;
216 kx layout->reloc_section = ptr = xmalloc (ctx->current_address);
216 kx for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next)
216 kx if (ctx->lst->state)
216 kx {
216 kx memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size));
216 kx ptr += grub_target_to_host32 (ctx->lst->b.block_size);
216 kx }
216 kx assert ((ctx->current_address + (grub_uint8_t *) layout->reloc_section) == ptr);
216 kx }
216 kx
216 kx for (ctx->lst = ctx->lst0; ctx->lst; )
216 kx {
216 kx struct fixup_block_list *next;
216 kx next = ctx->lst->next;
216 kx free (ctx->lst);
216 kx ctx->lst = next;
216 kx }
216 kx
216 kx layout->reloc_size = ctx->current_address;
216 kx if (image_target->elf_target == EM_ARM && layout->reloc_size > GRUB_KERNEL_ARM_STACK_SIZE)
216 kx grub_util_error ("Reloc section (%d) is bigger than stack size (%d). "
216 kx "This breaks assembly assumptions. Please increase stack size",
216 kx (int) layout->reloc_size,
216 kx (int) GRUB_KERNEL_ARM_STACK_SIZE);
216 kx }
216 kx
216 kx /*
216 kx Layout:
216 kx <type 0 relocations>
216 kx <fffffffe>
216 kx <type 1 relocations>
216 kx <fffffffe>
216 kx ...
216 kx <type n relocations>
216 kx <ffffffff>
216 kx each relocation starts with 32-bit offset. Rest depends on relocation.
216 kx mkimage stops when it sees first unknown type or end marker.
216 kx This allows images to be created with mismatched mkimage and
216 kx kernel as long as no relocations are present in kernel that mkimage
216 kx isn't aware of (in which case mkimage aborts).
216 kx This also allows simple assembly to do the relocs.
216 kx */
216 kx
216 kx #define RAW_SEPARATOR 0xfffffffe
216 kx #define RAW_END_MARKER 0xffffffff
216 kx
216 kx static void
216 kx finish_reloc_translation_raw (struct translate_context *ctx, struct grub_mkimage_layout *layout,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx size_t count = 0, sz;
216 kx enum raw_reloc_type highest = RAW_RELOC_NONE;
216 kx enum raw_reloc_type curtype;
216 kx struct raw_reloc *cur;
216 kx grub_uint32_t *p;
216 kx if (!ctx->raw_relocs)
216 kx {
216 kx layout->reloc_section = p = xmalloc (sizeof (grub_uint32_t));
216 kx p[0] = RAW_END_MARKER;
216 kx layout->reloc_size = sizeof (grub_uint32_t);
216 kx return;
216 kx }
216 kx for (cur = ctx->raw_relocs; cur; cur = cur->next)
216 kx {
216 kx count++;
216 kx if (cur->type > highest)
216 kx highest = cur->type;
216 kx }
216 kx /* highest separators, count relocations and one end marker. */
216 kx sz = (highest + count + 1) * sizeof (grub_uint32_t);
216 kx layout->reloc_section = p = xmalloc (sz);
216 kx for (curtype = 0; curtype <= highest; curtype++)
216 kx {
216 kx /* Support for special cases would go here. */
216 kx for (cur = ctx->raw_relocs; cur; cur = cur->next)
216 kx if (cur->type == curtype)
216 kx {
216 kx *p++ = cur->offset;
216 kx }
216 kx *p++ = RAW_SEPARATOR;
216 kx }
216 kx *--p = RAW_END_MARKER;
216 kx layout->reloc_size = sz;
216 kx }
216 kx
216 kx static void
216 kx finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_layout *layout,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx if (image_target->id == IMAGE_EFI)
216 kx finish_reloc_translation_pe (ctx, layout, image_target);
216 kx else
216 kx finish_reloc_translation_raw (ctx, layout, image_target);
216 kx }
216 kx
216 kx
216 kx static void
216 kx create_u64_fixups (struct translate_context *ctx,
216 kx Elf_Addr jumpers, grub_size_t njumpers,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx unsigned i;
216 kx assert (image_target->id == IMAGE_EFI);
216 kx for (i = 0; i < njumpers; i++)
216 kx ctx->current_address = add_fixup_entry (&ctx->lst,
216 kx GRUB_PE32_REL_BASED_DIR64,
216 kx jumpers + 8 * i,
216 kx 0, ctx->current_address,
216 kx image_target);
216 kx }
216 kx
216 kx /* Make a .reloc section. */
216 kx static void
216 kx make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
216 kx struct section_metadata *smd,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx unsigned i;
216 kx Elf_Shdr *s;
216 kx struct translate_context ctx;
216 kx
216 kx translate_reloc_start (&ctx, image_target);
216 kx
216 kx for (i = 0, s = smd->sections; i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
216 kx (grub_target_to_host32 (s->sh_type) == SHT_RELA))
216 kx {
216 kx Elf_Rel *r;
216 kx Elf_Word rtab_size, r_size, num_rs;
216 kx Elf_Off rtab_offset;
216 kx Elf_Addr section_address;
216 kx Elf_Word j;
216 kx
216 kx if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd))
216 kx {
216 kx grub_util_info ("not translating the skipped relocation section %s",
216 kx smd->strtab + grub_le_to_cpu32 (s->sh_name));
216 kx continue;
216 kx }
216 kx
216 kx grub_util_info ("translating the relocation section %s",
216 kx smd->strtab + grub_le_to_cpu32 (s->sh_name));
216 kx
216 kx rtab_size = grub_target_to_host (s->sh_size);
216 kx r_size = grub_target_to_host (s->sh_entsize);
216 kx rtab_offset = grub_target_to_host (s->sh_offset);
216 kx num_rs = rtab_size / r_size;
216 kx
216 kx section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)];
216 kx
216 kx for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
216 kx j < num_rs;
216 kx j++, r = (Elf_Rel *) ((char *) r + r_size))
216 kx {
216 kx Elf_Addr info;
216 kx Elf_Addr offset;
216 kx Elf_Addr addr;
216 kx
216 kx offset = grub_target_to_host (r->r_offset);
216 kx info = grub_target_to_host (r->r_info);
216 kx
216 kx addr = section_address + offset;
216 kx
216 kx translate_relocation (&ctx, addr, info, image_target);
216 kx }
216 kx }
216 kx
216 kx if (image_target->elf_target == EM_IA_64)
216 kx create_u64_fixups (&ctx,
216 kx layout->ia64jmp_off
216 kx + image_target->vaddr_offset,
216 kx 2 * layout->ia64jmpnum,
216 kx image_target);
216 kx if (image_target->elf_target == EM_IA_64 || image_target->elf_target == EM_AARCH64)
216 kx create_u64_fixups (&ctx,
216 kx layout->got_off
216 kx + image_target->vaddr_offset,
216 kx (layout->got_size / 8),
216 kx image_target);
216 kx
216 kx finish_reloc_translation (&ctx, layout, image_target);
216 kx }
216 kx
216 kx /* Determine if this section is a text section. Return false if this
216 kx section is not allocated. */
216 kx static int
216 kx SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx if (!is_relocatable (image_target)
216 kx && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
216 kx return 0;
216 kx return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
216 kx == (SHF_EXECINSTR | SHF_ALLOC));
216 kx }
216 kx
216 kx /* Determine if this section is a data section. */
216 kx static int
216 kx SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx if (!is_relocatable (image_target)
216 kx && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
216 kx return 0;
216 kx return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
216 kx == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
216 kx }
216 kx
216 kx static int
216 kx SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx if (!is_relocatable (image_target))
216 kx return 0;
216 kx return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
216 kx == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
216 kx }
216 kx
216 kx /* Determine if a section is going to be in the final output */
216 kx static int
216 kx SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx /* We keep .text and .data */
216 kx if (SUFFIX (is_text_section) (s, image_target)
216 kx || SUFFIX (is_data_section) (s, image_target))
216 kx return 1;
216 kx
216 kx /*
216 kx * And we keep .bss if we're producing PE binaries or the target doesn't
216 kx * have a relocating loader. Platforms other than EFI and U-boot shouldn't
216 kx * have .bss in their binaries as we build with -Wl,-Ttext.
216 kx */
216 kx if (SUFFIX (is_bss_section) (s, image_target)
216 kx && (image_target->id == IMAGE_EFI || !is_relocatable (image_target)))
216 kx return 1;
216 kx
216 kx /* Otherwise this is not a section we're keeping in the final output. */
216 kx return 0;
216 kx }
216 kx
216 kx static int
216 kx SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target,
216 kx struct section_metadata *smd)
216 kx {
216 kx int i;
216 kx int r = 0;
216 kx const char *name = smd->strtab + grub_host_to_target32 (s->sh_name);
216 kx
216 kx if (!strncmp (name, ".rela.", 6))
216 kx name += 5;
216 kx else if (!strncmp (name, ".rel.", 5))
216 kx name += 4;
216 kx else
216 kx return 1;
216 kx
216 kx for (i = 0, s = smd->sections; i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx {
216 kx const char *sname = smd->strtab + grub_host_to_target32 (s->sh_name);
216 kx if (strcmp (sname, name))
216 kx continue;
216 kx
216 kx return SUFFIX (is_kept_section) (s, image_target);
216 kx }
216 kx
216 kx return r;
216 kx }
216 kx
216 kx /* Return if the ELF header is valid. */
216 kx static int
216 kx SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx if (size < sizeof (*e)
216 kx || e->e_ident[EI_MAG0] != ELFMAG0
216 kx || e->e_ident[EI_MAG1] != ELFMAG1
216 kx || e->e_ident[EI_MAG2] != ELFMAG2
216 kx || e->e_ident[EI_MAG3] != ELFMAG3
216 kx || e->e_ident[EI_VERSION] != EV_CURRENT
216 kx || e->e_ident[EI_CLASS] != ELFCLASSXX
216 kx || e->e_version != grub_host_to_target32 (EV_CURRENT))
216 kx return 0;
216 kx
216 kx return 1;
216 kx }
216 kx
216 kx static Elf_Addr
216 kx SUFFIX (put_section) (Elf_Shdr *s, int i,
216 kx Elf_Addr current_address,
216 kx struct section_metadata *smd,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
216 kx const char *name = smd->strtab + grub_host_to_target32 (s->sh_name);
216 kx
216 kx if (align)
216 kx current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
216 kx align)
216 kx - image_target->vaddr_offset;
216 kx
216 kx grub_util_info ("locating the section %s at 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx name, (unsigned long long) current_address);
216 kx if (!is_relocatable (image_target))
216 kx current_address = grub_host_to_target_addr (s->sh_addr)
216 kx - image_target->link_addr;
216 kx smd->addrs[i] = current_address;
216 kx current_address += grub_host_to_target_addr (s->sh_size);
216 kx return current_address;
216 kx }
216 kx
216 kx /*
216 kx * Locate section addresses by merging code sections and data sections
216 kx * into .text and .data, respectively.
216 kx */
216 kx static void
216 kx SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
216 kx struct section_metadata *smd,
216 kx struct grub_mkimage_layout *layout,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx int i;
216 kx Elf_Shdr *s;
216 kx
216 kx layout->align = 1;
216 kx /* Page-aligning simplifies relocation handling. */
216 kx if (image_target->elf_target == EM_AARCH64)
216 kx layout->align = 4096;
216 kx
216 kx layout->kernel_size = 0;
216 kx
216 kx for (i = 0, s = smd->sections;
216 kx i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC)
216 kx && grub_host_to_target32 (s->sh_addralign) > layout->align)
216 kx layout->align = grub_host_to_target32 (s->sh_addralign);
216 kx
216 kx /* .text */
216 kx for (i = 0, s = smd->sections;
216 kx i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx if (SUFFIX (is_text_section) (s, image_target))
216 kx {
216 kx layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size,
216 kx smd, image_target);
216 kx if (!is_relocatable (image_target) &&
216 kx grub_host_to_target_addr (s->sh_addr) != image_target->link_addr)
216 kx {
216 kx char *msg
216 kx = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx"
216 kx " instead of 0x%llx: ld.gold bug?"),
216 kx kernel_path,
216 kx (unsigned long long) grub_host_to_target_addr (s->sh_addr),
216 kx (unsigned long long) image_target->link_addr);
216 kx grub_util_error ("%s", msg);
216 kx }
216 kx }
216 kx
216 kx #ifdef MKIMAGE_ELF32
216 kx if (image_target->elf_target == EM_ARM)
216 kx {
216 kx grub_size_t tramp;
216 kx
216 kx layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
216 kx
216 kx tramp = arm_get_trampoline_size (e, smd->sections, smd->section_entsize,
216 kx smd->num_sections, image_target);
216 kx
216 kx layout->tramp_off = layout->kernel_size;
216 kx layout->kernel_size += ALIGN_UP (tramp, 16);
216 kx }
216 kx #endif
216 kx
216 kx layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset,
216 kx image_target->section_align)
216 kx - image_target->vaddr_offset;
216 kx layout->exec_size = layout->kernel_size;
216 kx
216 kx /* .data */
216 kx for (i = 0, s = smd->sections;
216 kx i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx if (SUFFIX (is_data_section) (s, image_target))
216 kx layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, smd,
216 kx image_target);
216 kx
216 kx layout->bss_start = layout->kernel_size;
216 kx layout->end = layout->kernel_size;
216 kx
216 kx /* .bss */
216 kx for (i = 0, s = smd->sections;
216 kx i < smd->num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
216 kx {
216 kx if (SUFFIX (is_bss_section) (s, image_target))
216 kx layout->end = SUFFIX (put_section) (s, i, layout->end, smd, image_target);
216 kx
216 kx /*
216 kx * This must to be in the last time this function passes through the loop.
216 kx */
216 kx smd->vaddrs[i] = smd->addrs[i] + image_target->vaddr_offset;
216 kx }
216 kx
216 kx layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset,
216 kx image_target->section_align) - image_target->vaddr_offset;
216 kx /* Explicitly initialize BSS
216 kx when producing PE32 to avoid a bug in EFI implementations.
216 kx Platforms other than EFI and U-boot shouldn't have .bss in
216 kx their binaries as we build with -Wl,-Ttext.
216 kx */
216 kx if (image_target->id == IMAGE_EFI || !is_relocatable (image_target))
216 kx layout->kernel_size = layout->end;
216 kx }
216 kx
216 kx char *
216 kx SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
216 kx size_t total_module_size,
216 kx struct grub_mkimage_layout *layout,
216 kx const struct grub_install_image_target_desc *image_target)
216 kx {
216 kx char *kernel_img, *out_img;
216 kx struct section_metadata smd = { 0, 0, 0, 0, 0, 0, 0 };
216 kx Elf_Ehdr *e;
216 kx int i;
216 kx Elf_Shdr *s;
216 kx Elf_Off section_offset;
216 kx grub_size_t kernel_size;
216 kx
216 kx grub_memset (layout, 0, sizeof (*layout));
216 kx
216 kx layout->start_address = 0;
216 kx
216 kx kernel_size = grub_util_get_image_size (kernel_path);
216 kx kernel_img = xmalloc (kernel_size);
216 kx grub_util_load_image (kernel_path, kernel_img);
216 kx
216 kx e = (Elf_Ehdr *) kernel_img;
216 kx if (! SUFFIX (check_elf_header) (e, kernel_size, image_target))
216 kx grub_util_error ("invalid ELF header");
216 kx
216 kx section_offset = grub_target_to_host (e->e_shoff);
216 kx smd.section_entsize = grub_target_to_host16 (e->e_shentsize);
216 kx smd.num_sections = grub_target_to_host16 (e->e_shnum);
216 kx
216 kx if (kernel_size < section_offset
216 kx + (grub_uint32_t) smd.section_entsize * smd.num_sections)
216 kx grub_util_error (_("premature end of file %s"), kernel_path);
216 kx
216 kx smd.sections = (Elf_Shdr *) (kernel_img + section_offset);
216 kx
216 kx /* Relocate sections then symbols in the virtual address space. */
216 kx s = (Elf_Shdr *) ((char *) smd.sections
216 kx + grub_host_to_target16 (e->e_shstrndx) * smd.section_entsize);
216 kx smd.strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
216 kx
216 kx smd.addrs = xcalloc (smd.num_sections, sizeof (*smd.addrs));
216 kx smd.vaddrs = xcalloc (smd.num_sections, sizeof (*smd.vaddrs));
216 kx
216 kx SUFFIX (locate_sections) (e, kernel_path, &smd, layout, image_target);
216 kx
216 kx if (!is_relocatable (image_target))
216 kx {
216 kx Elf_Addr current_address = layout->kernel_size;
216 kx
216 kx for (i = 0, s = smd.sections;
216 kx i < smd.num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
216 kx if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
216 kx {
216 kx Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
216 kx const char *name = smd.strtab + grub_host_to_target32 (s->sh_name);
216 kx
216 kx if (sec_align)
216 kx current_address = ALIGN_UP (current_address
216 kx + image_target->vaddr_offset,
216 kx sec_align)
216 kx - image_target->vaddr_offset;
216 kx
216 kx grub_util_info ("locating the section %s at 0x%"
216 kx GRUB_HOST_PRIxLONG_LONG,
216 kx name, (unsigned long long) current_address);
216 kx if (!is_relocatable (image_target))
216 kx current_address = grub_host_to_target_addr (s->sh_addr)
216 kx - image_target->link_addr;
216 kx
216 kx smd.vaddrs[i] = current_address
216 kx + image_target->vaddr_offset;
216 kx current_address += grub_host_to_target_addr (s->sh_size);
216 kx }
216 kx current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
216 kx image_target->section_align)
216 kx - image_target->vaddr_offset;
216 kx layout->bss_size = current_address - layout->kernel_size;
216 kx }
216 kx else
216 kx layout->bss_size = 0;
216 kx
216 kx if (image_target->id == IMAGE_SPARC64_AOUT
216 kx || image_target->id == IMAGE_SPARC64_RAW
216 kx || image_target->id == IMAGE_UBOOT
216 kx || image_target->id == IMAGE_COREBOOT
216 kx || image_target->id == IMAGE_SPARC64_CDCORE)
216 kx layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align);
216 kx
216 kx if (is_relocatable (image_target))
216 kx {
216 kx smd.symtab = NULL;
216 kx for (i = 0, s = smd.sections;
216 kx i < smd.num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
216 kx if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
216 kx {
216 kx smd.symtab = s;
216 kx break;
216 kx }
216 kx if (! smd.symtab)
216 kx grub_util_error ("%s", _("no symbol table"));
216 kx #ifdef MKIMAGE_ELF64
216 kx if (image_target->elf_target == EM_IA_64)
216 kx {
216 kx grub_size_t tramp;
216 kx
216 kx layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
216 kx
216 kx grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
216 kx
216 kx layout->tramp_off = layout->kernel_size;
216 kx layout->kernel_size += ALIGN_UP (tramp, 16);
216 kx
216 kx layout->ia64jmp_off = layout->kernel_size;
216 kx layout->ia64jmpnum = SUFFIX (count_funcs) (e, smd.symtab,
216 kx image_target);
216 kx layout->kernel_size += 16 * layout->ia64jmpnum;
216 kx
216 kx layout->got_off = layout->kernel_size;
216 kx layout->kernel_size += ALIGN_UP (layout->got_size, 16);
216 kx }
216 kx if (image_target->elf_target == EM_AARCH64)
216 kx {
216 kx grub_size_t tramp;
216 kx
216 kx layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
216 kx
216 kx grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
216 kx
216 kx layout->got_off = layout->kernel_size;
216 kx layout->kernel_size += ALIGN_UP (layout->got_size, 16);
216 kx }
216 kx #endif
216 kx
216 kx if (image_target->id == IMAGE_EFI)
216 kx layout->kernel_size = ALIGN_UP (layout->kernel_size,
216 kx GRUB_PE32_FILE_ALIGNMENT);
216 kx }
216 kx else
216 kx {
216 kx layout->reloc_size = 0;
216 kx layout->reloc_section = NULL;
216 kx }
216 kx
216 kx out_img = xmalloc (layout->kernel_size + total_module_size);
216 kx memset (out_img, 0, layout->kernel_size + total_module_size);
216 kx
216 kx if (is_relocatable (image_target))
216 kx {
216 kx layout->start_address = SUFFIX (relocate_symbols) (e, &smd,
216 kx (char *) out_img + layout->ia64jmp_off,
216 kx layout->ia64jmp_off + image_target->vaddr_offset,
216 kx layout->bss_start, layout->end, image_target);
216 kx
216 kx if (layout->start_address == (Elf_Addr) -1)
216 kx grub_util_error ("start symbol is not defined");
216 kx
216 kx /* Resolve addrs in the virtual address space. */
216 kx SUFFIX (relocate_addrs) (e, &smd, out_img, layout->tramp_off,
216 kx layout->got_off, image_target);
216 kx
216 kx make_reloc_section (e, layout, &smd, image_target);
216 kx if (image_target->id != IMAGE_EFI)
216 kx {
216 kx out_img = xrealloc (out_img, layout->kernel_size + total_module_size
216 kx + ALIGN_UP (layout->reloc_size, image_target->mod_align));
216 kx memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size);
216 kx memset (out_img + layout->kernel_size + layout->reloc_size, 0,
216 kx total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size);
216 kx layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align);
216 kx }
216 kx }
216 kx
216 kx for (i = 0, s = smd.sections;
216 kx i < smd.num_sections;
216 kx i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
216 kx if (SUFFIX (is_kept_section) (s, image_target))
216 kx {
216 kx if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
216 kx memset (out_img + smd.addrs[i], 0,
216 kx grub_host_to_target_addr (s->sh_size));
216 kx else
216 kx memcpy (out_img + smd.addrs[i],
216 kx kernel_img + grub_host_to_target_addr (s->sh_offset),
216 kx grub_host_to_target_addr (s->sh_size));
216 kx }
216 kx free (kernel_img);
216 kx
216 kx free (smd.vaddrs);
216 kx smd.vaddrs = NULL;
216 kx free (smd.addrs);
216 kx smd.addrs = NULL;
216 kx
216 kx return out_img;
216 kx }