752ceb1640
Signed-off-by: Peter Jones <pjones@redhat.com>
161 lines
6.5 KiB
Diff
161 lines
6.5 KiB
Diff
From ebc825b5491185b39ecd24b1674a76f60492dc60 Mon Sep 17 00:00:00 2001
|
|
From: Peter Jones <pjones@redhat.com>
|
|
Date: Wed, 21 Feb 2018 15:20:28 -0500
|
|
Subject: [PATCH] mkimage: avoid copying relocations for sections that won't be
|
|
copied.
|
|
|
|
Some versions of gcc include a plugin called "annobin", and in some
|
|
build systems this is enabled by default. This plugin creates special
|
|
ELF note sections to track which ABI-breaking features are used by a
|
|
binary, as well as a series of relocations to annotate where.
|
|
|
|
If grub is compiled with this feature, then when grub-mkimage translates
|
|
the binary to another file format which does not strongly associate
|
|
relocation data with sections (i.e. when platform is *-efi), these
|
|
relocations appear to be against the .text section rather than the
|
|
original note section. When the binary is loaded by the PE runtime
|
|
loader, hilarity ensues.
|
|
|
|
This issue is not necessarily limited to the annobin, but could arise
|
|
any time there are relocations in sections that are not represented in
|
|
grub-mkimage's output.
|
|
|
|
This patch seeks to avoid this issue by only including relocations that
|
|
refer to sections which will be included in the final binary.
|
|
|
|
As an aside, this should also obviate the need to avoid -funwind-tables,
|
|
-fasynchronous-unwind-tables, and any sections similar to .eh_frame in
|
|
the future. I've tested it on x86-64-efi with the following gcc command
|
|
line options (as recorded by -grecord-gcc-flags), but I still need to
|
|
test the result on some other platforms that have been problematic in
|
|
the past (especially ARM Aarch64) before I feel comfortable making
|
|
changes to the configure.ac bits:
|
|
|
|
GNU C11 7.2.1 20180116 (Red Hat 7.2.1-7) -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -msoft-float -mno-stack-arg-probe -mcmodel=large -mno-red-zone -m64 -mtune=generic -march=x86-64 -g3 -Os -freg-struct-return -fno-stack-protector -ffreestanding -funwind-tables -fasynchronous-unwind-tables -fno-strict-aliasing -fstack-clash-protection -fno-ident -fplugin=annobin
|
|
|
|
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
|
---
|
|
util/grub-mkimagexx.c | 80 +++++++++++++++++++++++++++++++++++++++++++++------
|
|
1 file changed, 72 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
|
|
index 5de34d53cb7..11d05d7a8ec 100644
|
|
--- a/util/grub-mkimagexx.c
|
|
+++ b/util/grub-mkimagexx.c
|
|
@@ -725,6 +725,12 @@ arm_get_trampoline_size (Elf_Ehdr *e,
|
|
}
|
|
#endif
|
|
|
|
+static int
|
|
+SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target);
|
|
+static int
|
|
+SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target,
|
|
+ struct section_metadata *smd);
|
|
+
|
|
/* Deal with relocation information. This function relocates addresses
|
|
within the virtual address space starting from 0. So only relative
|
|
addresses can be fully resolved. Absolute addresses must be relocated
|
|
@@ -759,6 +765,14 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd,
|
|
Elf_Shdr *target_section;
|
|
Elf_Word j;
|
|
|
|
+ if (!SUFFIX (is_kept_section) (s, image_target) &&
|
|
+ !SUFFIX (is_kept_reloc_section) (s, image_target, smd))
|
|
+ {
|
|
+ grub_util_info ("not translating relocations for omitted section %s",
|
|
+ smd->strtab + grub_le_to_cpu32 (s->sh_name));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
target_section_index = grub_target_to_host32 (s->sh_info);
|
|
target_section_addr = smd->addrs[target_section_index];
|
|
target_section = (Elf_Shdr *) ((char *) smd->sections
|
|
@@ -1664,6 +1678,13 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
|
|
Elf_Addr section_address;
|
|
Elf_Word j;
|
|
|
|
+ if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd))
|
|
+ {
|
|
+ grub_util_info ("not translating the skipped relocation section %s",
|
|
+ smd->strtab + grub_le_to_cpu32 (s->sh_name));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
grub_util_info ("translating the relocation section %s",
|
|
smd->strtab + grub_le_to_cpu32 (s->sh_name));
|
|
|
|
@@ -1739,6 +1760,56 @@ SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_des
|
|
== SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
|
|
}
|
|
|
|
+/* Determine if a section is going to be in the final output */
|
|
+static int
|
|
+SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
|
|
+{
|
|
+ /* We keep .text and .data */
|
|
+ if (SUFFIX (is_text_section) (s, image_target)
|
|
+ || SUFFIX (is_data_section) (s, image_target))
|
|
+ return 1;
|
|
+
|
|
+ /*
|
|
+ * And we keep .bss if we're producing PE binaries or the target doesn't
|
|
+ * have a relocating loader. Platforms other than EFI and U-boot shouldn't
|
|
+ * have .bss in their binaries as we build with -Wl,-Ttext.
|
|
+ */
|
|
+ if (SUFFIX (is_bss_section) (s, image_target)
|
|
+ && (image_target->id == IMAGE_EFI || !is_relocatable (image_target)))
|
|
+ return 1;
|
|
+
|
|
+ /* Otherwise this is not a section we're keeping in the final output. */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target,
|
|
+ struct section_metadata *smd)
|
|
+{
|
|
+ int i;
|
|
+ int r = 0;
|
|
+ const char *name = smd->strtab + grub_host_to_target32 (s->sh_name);
|
|
+
|
|
+ if (!strncmp (name, ".rela.", 6))
|
|
+ name += 5;
|
|
+ else if (!strncmp (name, ".rel.", 5))
|
|
+ name += 4;
|
|
+ else
|
|
+ return 1;
|
|
+
|
|
+ for (i = 0, s = smd->sections; i < smd->num_sections;
|
|
+ i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
|
|
+ {
|
|
+ const char *sname = smd->strtab + grub_host_to_target32 (s->sh_name);
|
|
+ if (strcmp (sname, name))
|
|
+ continue;
|
|
+
|
|
+ return SUFFIX (is_kept_section) (s, image_target);
|
|
+ }
|
|
+
|
|
+ return r;
|
|
+}
|
|
+
|
|
/* Return if the ELF header is valid. */
|
|
static int
|
|
SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
|
|
@@ -2063,14 +2134,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
|
|
for (i = 0, s = smd.sections;
|
|
i < smd.num_sections;
|
|
i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
|
|
- if (SUFFIX (is_data_section) (s, image_target)
|
|
- /* Explicitly initialize BSS
|
|
- when producing PE32 to avoid a bug in EFI implementations.
|
|
- Platforms other than EFI and U-boot shouldn't have .bss in
|
|
- their binaries as we build with -Wl,-Ttext.
|
|
- */
|
|
- || (SUFFIX (is_bss_section) (s, image_target) && (image_target->id == IMAGE_EFI || !is_relocatable (image_target)))
|
|
- || SUFFIX (is_text_section) (s, image_target))
|
|
+ if (SUFFIX (is_kept_section) (s, image_target))
|
|
{
|
|
if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
|
|
memset (out_img + smd.addrs[i], 0,
|