Add an option to objcopy that creates padding sections that eliminate gaps between segments.
Resolves: RHEL-60807
This commit is contained in:
parent
ba8d9ed4da
commit
b754f74df9
253
binutils-rhivos-segment-gap.patch
Normal file
253
binutils-rhivos-segment-gap.patch
Normal file
@ -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.<N> where <N> 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 <num> Select byte <num> in every interleaved block\n\
|
||||
--gap-fill <val> Fill gaps between sections with <val>\n\
|
||||
--pad-to <addr> Pad the last section up to address <addr>\n\
|
||||
+ --add-segment-padding-sections Add padding sections so that load segments do not have gaps\n\
|
||||
--set-start <addr> Set the start address to <addr>\n\
|
||||
{--change-start|--adjust-start} <incr>\n\
|
||||
Add <incr> 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;
|
@ -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 <nickc@redhat.com> - 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 <nickc@redhat.com> - 2.35.2-60
|
||||
- Add a helpful linker diagnostic message about missing static libraries. (RHEL-69758)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user