From b754f74df907af05d57d4b805123498563580554 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 23 Jan 2025 13:03:08 +0000 Subject: [PATCH] Add an option to objcopy that creates padding sections that eliminate gaps between segments. Resolves: RHEL-60807 --- binutils-rhivos-segment-gap.patch | 253 ++++++++++++++++++++++++++++++ binutils.spec | 9 +- 2 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 binutils-rhivos-segment-gap.patch diff --git a/binutils-rhivos-segment-gap.patch b/binutils-rhivos-segment-gap.patch new file mode 100644 index 0000000..4612ce9 --- /dev/null +++ b/binutils-rhivos-segment-gap.patch @@ -0,0 +1,253 @@ +diff -rup binutils-2.41/binutils/doc/binutils.texi /home/nickc/binutils-2.41/binutils/doc/binutils.texi +--- binutils-2.41/binutils/doc/binutils.texi 2025-01-21 13:16:01.970763573 +0000 ++++ /home/nickc/binutils-2.41/binutils/doc/binutils.texi 2025-01-21 12:22:23.561279546 +0000 +@@ -1285,6 +1285,7 @@ objcopy [@option{-F} @var{bfdname}|@opti + [@option{--debugging}] + [@option{--gap-fill=}@var{val}] + [@option{--pad-to=}@var{address}] ++ [@option{--add-segment-padding-sections}] + [@option{--set-start=}@var{val}] + [@option{--adjust-start=}@var{incr}] + [@option{--change-addresses=}@var{incr}] +@@ -1666,6 +1667,18 @@ Pad the output file up to the load addre + done by increasing the size of the last section. The extra space is + filled in with the value specified by @option{--gap-fill} (default zero). + ++@item --add-segment-padding-sections ++Add empty sections that eliminate any gaps between loadable segments. ++This option only works with ELF format files that contains both ++sections and segments. The added sections will have the SHT_NOBITS ++type and permissions that match the segment that they are padding. ++The sections names will be of the form .segment.pad. where is ++the number of the load segment that is being padded. ++ ++Note - this option should not be used in conjunction with any other ++option that adds or removes sections, or changes their size in any ++way. ++ + @item --set-start @var{val} + Set the start address (also known as the entry address) of the new + file to @var{val}. Not all object file formats support setting the +--- /dev/null 2025-01-21 09:02:16.359001262 +0000 ++++ binutils-2.41/binutils/testsuite/binutils-all/add-segment-padding-sections.d 2025-01-21 13:13:49.615269853 +0000 +@@ -0,0 +1,10 @@ ++#PROG: objcopy ++#name: objcopy --add-segment-padding-sections ++#source: bintest.s ++#ld: -e 0 --defsym external_symbol=0 ++#objcopy: --add-segment-padding-sections ++#readelf: -lW ++ ++#... ++[ ]+LOAD[ ]+0x[0-9a-f]+[ ]+0x[0-9a-f]+[ ]+0x[0-9a-f]+[ ]+0x[0-9a-f]+[ ]+0x[0-9a-f]+000.* ++#pass +--- binutils.orig/binutils/testsuite/binutils-all/objcopy.exp 2025-01-23 10:46:24.867490584 +0000 ++++ binutils-2.35.2/binutils/testsuite/binutils-all/objcopy.exp 2025-01-23 10:48:05.957176799 +0000 +@@ -1356,3 +1356,7 @@ if { [istarget pdp11-*-*] } { + } + + objcopy_test "pr25662" $src executable "" "-T$srcdir/$subdir/pr25662.ld" ++ ++if [is_elf_format] { ++ run_dump_test "add-segment-padding-sections" ++} +--- binutils.orig/binutils/objcopy.c 2025-01-23 10:46:24.874490631 +0000 ++++ binutils-2.35.2/binutils/objcopy.c 2025-01-23 10:54:02.220653906 +0000 +@@ -242,6 +242,9 @@ static bfd_boolean change_leading_char = + /* Whether to remove the leading character from global symbol names. */ + static bfd_boolean remove_leading_char = FALSE; + ++/* If true add sections that pad loadable segments so that there are no gaps between them. */ ++static bfd_boolean add_segment_padding_sections = FALSE; ++ + /* Whether to permit wildcard in symbol comparison. */ + static bfd_boolean wildcard = FALSE; + +@@ -306,6 +309,7 @@ enum command_line_switch + { + OPTION_ADD_SECTION=150, + OPTION_ADD_GNU_DEBUGLINK, ++ OPTION_ADD_SEGMENT_PADDING_SECTIONS, + OPTION_ADD_SYMBOL, + OPTION_ALT_MACH_CODE, + OPTION_CHANGE_ADDRESSES, +@@ -417,6 +421,7 @@ static struct option copy_options[] = + { + {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK}, + {"add-section", required_argument, 0, OPTION_ADD_SECTION}, ++ {"add-segment-padding-sections", no_argument, 0, OPTION_ADD_SEGMENT_PADDING_SECTIONS}, + {"add-symbol", required_argument, 0, OPTION_ADD_SYMBOL}, + {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, + {"adjust-start", required_argument, 0, OPTION_CHANGE_START}, +@@ -610,6 +615,7 @@ copy_usage (FILE *stream, int exit_statu + -b --byte Select byte in every interleaved block\n\ + --gap-fill Fill gaps between sections with \n\ + --pad-to Pad the last section up to address \n\ ++ --add-segment-padding-sections Add padding sections so that load segments do not have gaps\n\ + --set-start Set the start address to \n\ + {--change-start|--adjust-start} \n\ + Add to the start address\n\ +@@ -2569,6 +2575,142 @@ check_new_section_flags (flagword flags, + return flags; + } + ++static bfd_boolean ++is_loadable_segment (const Elf_Internal_Phdr * phdr) ++{ ++ return phdr->p_type == PT_LOAD || phdr->p_type == PT_TLS; ++} ++ ++static bfd_vma ++page_align_down (bfd_vma pagesize, bfd_vma addr) ++{ ++ return addr & ~ (pagesize - 1); ++} ++ ++static void ++add_padding_sections (bfd *ibfd, bfd *obfd) ++{ ++ if (obfd == NULL) /* Paranoia. */ ++ return; ++ ++ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour ++ || bfd_get_flavour (obfd) != bfd_target_elf_flavour) ++ { ++ non_fatal (_("the --add-segment-padding-sections option only works with ELF format files\n")); ++ return; ++ } ++ ++ if (add_sections != NULL || update_sections != NULL || gap_fill_set || pad_to_set) ++ { ++ non_fatal (_("the --add-segment-padding-sections option does not work with other paddding/modifying options\n")); ++ return; ++ } ++ ++ const struct elf_backend_data * bed = get_elf_backend_data (ibfd); ++ const struct elf_obj_tdata * tdata = elf_tdata (ibfd); ++ const Elf_Internal_Ehdr * ehdr = elf_elfheader (ibfd); ++ ++ if (bed == NULL || tdata == NULL || ehdr == NULL) ++ { ++ non_fatal ("could not find ELF data\n"); ++ return; ++ } ++ ++ const Elf_Internal_Phdr * prev = NULL; ++ unsigned int i; ++ bfd_boolean sections_added = FALSE; ++ ++ for (i = 1; i < ehdr->e_phnum; i++) ++ { ++ const Elf_Internal_Phdr * current = tdata->phdr + i; ++ ++ if (! is_loadable_segment (current)) ++ continue; ++ ++ /* If this is the first loadable segment, just record it. */ ++ if (prev == NULL) ++ { ++ prev = current; ++ continue; ++ } ++ ++ bfd_vma prev_end = prev->p_vaddr + prev->p_memsz; ++ bfd_vma current_start = page_align_down (bed->commonpagesize, current->p_vaddr); ++ ++ /* If the segments are not ordered by increasing p_vaddr then abort. ++ Note: the ELF standard requires that segments be sorted by p_vaddr, ++ but linker scripts are able to override this. */ ++ if (current_start < prev_end) ++ break; ++ ++ /* If the previous segment ended at the start of the ++ current segment then there is nothing to do. */ ++ if (prev_end == current_start) ++ { ++ prev = current; ++ continue; ++ } ++ ++ flagword flags = SEC_LINKER_CREATED | SEC_ALLOC; ++ ++ /* We do not add SEC_HAS_CONTENTS because we want to create a SHT_NOBITS ++ section. That way we will not take up (much) extra space in the file. */ ++ ++ if (prev->p_flags & PF_X) ++ flags |= SEC_CODE | SEC_READONLY; ++ else if (prev->p_flags & PF_R) ++ flags |= SEC_DATA | SEC_READONLY; ++ else if (prev->p_flags & PF_W) ++ flags |= SEC_DATA; ++ else ++ { ++ prev = current; ++ continue; ++ } ++ ++#define SEGMENT_PADDING_SECTION_NAME ".segment.pad" ++ char * new_name; ++ if (asprintf (& new_name, SEGMENT_PADDING_SECTION_NAME ".%u", i - 1) < 1) ++ { ++ non_fatal ("unable to construct padding section name\n"); ++ break; ++ } ++ ++ asection * new_section = bfd_make_section_with_flags (obfd, new_name, flags); ++ ++ if (new_section == NULL) ++ { ++ free (new_name); ++ non_fatal ("unable to make padding section\n"); ++ break; ++ } ++ ++ bfd_vma new_size = (current_start - prev->p_vaddr) - prev->p_memsz; ++ ++ if (! bfd_set_section_size (new_section, new_size)) ++ { ++ bfd_nonfatal_message (NULL, obfd, new_section, NULL); ++ break; ++ } ++ ++ if (! bfd_set_section_vma (new_section, prev_end)) ++ { ++ bfd_nonfatal_message (NULL, obfd, new_section, NULL); ++ break; ++ } ++ ++ /* Do not free the name - it is used later on. */ ++ ++ sections_added = TRUE; ++ prev = current; ++ } ++ ++ /* If we have added any sections, remove the section ++ to segment map so that it is regenerated. */ ++ if (sections_added) ++ elf_seg_map (obfd) = NULL; ++} ++ + /* Copy object file IBFD onto OBFD. + Returns TRUE upon success, FALSE otherwise. */ + +@@ -3175,6 +3317,9 @@ copy_object (bfd *ibfd, bfd *obfd, const + } + } + ++ if (add_segment_padding_sections) ++ add_padding_sections (ibfd, obfd); ++ + /* Symbol filtering must happen after the output sections + have been created, but before their contents are set. */ + dhandle = NULL; +@@ -5548,6 +5693,10 @@ copy_main (int argc, char *argv[]) + pad_to_set = TRUE; + break; + ++ case OPTION_ADD_SEGMENT_PADDING_SECTIONS: ++ add_segment_padding_sections = TRUE; ++ break; ++ + case OPTION_REMOVE_LEADING_CHAR: + remove_leading_char = TRUE; + break; diff --git a/binutils.spec b/binutils.spec index 29a7291..742734f 100644 --- a/binutils.spec +++ b/binutils.spec @@ -2,7 +2,7 @@ Summary: A GNU collection of binary utilities Name: binutils%{?_with_debug:-debug} Version: 2.35.2 -Release: 60%{?dist} +Release: 61%{?dist} License: GPLv3+ URL: https://sourceware.org/binutils @@ -506,6 +506,10 @@ Patch90: binutils-s390-arch15-gas-tests-fixes.patch # Lifetime: Fixed in 2.44 Patch91: binutils-linker-diagnostic-message.patch +# Purpose: Add option to objcopy to pad segments eliminating gaps. +# Lifetime: Permanent +Patch92: binutils-rhivos-segment-gap.patch + #---------------------------------------------------------------------------- Provides: bundled(libiberty) @@ -1365,6 +1369,9 @@ exit 0 #---------------------------------------------------------------------------- %changelog +* Thu Jan 23 2025 Nick Clifton - 2.35.2-61 +- Add an option to objcopy that creates padding sections that eliminate gaps between segments. (RHEL-60807) + * Mon Jan 06 2025 Nick Clifton - 2.35.2-60 - Add a helpful linker diagnostic message about missing static libraries. (RHEL-69758)