aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2019-10-25 16:46:07 +0100
committerNick Clifton <nickc@redhat.com>2019-10-25 16:46:07 +0100
commit5c49f2cd78c69d50bc7c7119596a226f05939d06 (patch)
tree9576132049dfa4a3fdf2cd5e4697d04c8bed02b6
parent27cee81d06fcff87d9c026a571db58c29c489dfa (diff)
downloadgdb-5c49f2cd78c69d50bc7c7119596a226f05939d06.zip
gdb-5c49f2cd78c69d50bc7c7119596a226f05939d06.tar.gz
gdb-5c49f2cd78c69d50bc7c7119596a226f05939d06.tar.bz2
Improve objcopy's note mergeing capabilities.
* objcopy.c (struct merged_note_section): New structure. Used to chain together details of mergeable note sections. (is_merged_note_section): Rename to is_megreable_note_section and return true for note sections that use GNU_BUILD_ATTRS_SECTION_NAME as a prefix. (num_bytes): Delete (objcoopy_internal_note): Add padded_namesz field. (DEBUG_MERGE): New macro. Set to non-zero to enable debugging of the note merging code. (gap_exists): Rename to overlaps_or_adjoins and return TRUE for overlapping notes or adjoining notes. (contained_by, is_deleted_note, is_version_note) (compare_gnu_build_notes, sort_gnu_build_notes): New functions. (merge_gnu_build_notes): Rework. Sort notes into a mergeable order first. Merge them. Then sort them into an ascending address order before writing them out. (copy_object): Handle more than one mergeable note section. * testsuite/binutils-all/note-2-32.d: Update for new merging behaviour. * testsuite/binutils-all/note-2-32.s: Likewise. * testsuite/binutils-all/note-2-64.d: Likewise. * testsuite/binutils-all/note-2-64.s: Likewise. * testsuite/binutils-all/note-3-32.d: Likewise. * testsuite/binutils-all/note-3-32.s: Likewise. * testsuite/binutils-all/note-3-64.d: Likewise. * testsuite/binutils-all/note-3-64.s: Likewise. * testsuite/binutils-all/note-4-32.d: Likewise. * testsuite/binutils-all/note-4-32.s: Likewise. * testsuite/binutils-all/note-4-64.d: Likewise. * testsuite/binutils-all/note-4-64.s: Likewise. * testsuite/binutils-all/note-6-32.s: New test source file. * testsuite/binutils-all/note-6-64.s: New test source file. * testsuite/binutils-all/note-6-32.d: New test driver file. * testsuite/binutils-all/note-6-64.d: New test driver file. * testsuite/binutils-all/objcopy.exp: Run the new test.
-rw-r--r--binutils/ChangeLog38
-rw-r--r--binutils/objcopy.c761
-rw-r--r--binutils/testsuite/binutils-all/note-2-32.d15
-rw-r--r--binutils/testsuite/binutils-all/note-2-32.s76
-rw-r--r--binutils/testsuite/binutils-all/note-2-64.d15
-rw-r--r--binutils/testsuite/binutils-all/note-2-64.s78
-rw-r--r--binutils/testsuite/binutils-all/note-3-32.d10
-rw-r--r--binutils/testsuite/binutils-all/note-3-32.s15
-rw-r--r--binutils/testsuite/binutils-all/note-3-64.d10
-rw-r--r--binutils/testsuite/binutils-all/note-3-64.s14
-rw-r--r--binutils/testsuite/binutils-all/note-4-32.d8
-rw-r--r--binutils/testsuite/binutils-all/note-4-32.s14
-rw-r--r--binutils/testsuite/binutils-all/note-4-64.d10
-rw-r--r--binutils/testsuite/binutils-all/note-4-64.s14
-rw-r--r--binutils/testsuite/binutils-all/note-6-32.d20
-rw-r--r--binutils/testsuite/binutils-all/note-6-32.s145
-rw-r--r--binutils/testsuite/binutils-all/note-6-64.d20
-rw-r--r--binutils/testsuite/binutils-all/note-6-64.s145
-rw-r--r--binutils/testsuite/binutils-all/objcopy.exp2
19 files changed, 985 insertions, 425 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index f1b3c0e..224ebeb 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,41 @@
+2019-10-25 Nick Clifton <nickc@redhat.com>
+
+ * objcopy.c (struct merged_note_section): New structure. Used to
+ chain together details of mergeable note sections.
+ (is_merged_note_section): Rename to is_megreable_note_section and
+ return true for note sections that use GNU_BUILD_ATTRS_SECTION_NAME
+ as a prefix.
+ (num_bytes): Delete
+ (objcoopy_internal_note): Add padded_namesz field.
+ (DEBUG_MERGE): New macro. Set to non-zero to enable debugging of
+ the note merging code.
+ (gap_exists): Rename to overlaps_or_adjoins and return TRUE for
+ overlapping notes or adjoining notes.
+ (contained_by, is_deleted_note, is_version_note)
+ (compare_gnu_build_notes, sort_gnu_build_notes): New functions.
+ (merge_gnu_build_notes): Rework. Sort notes into a mergeable
+ order first. Merge them. Then sort them into an ascending
+ address order before writing them out.
+ (copy_object): Handle more than one mergeable note section.
+ * testsuite/binutils-all/note-2-32.d: Update for new merging
+ behaviour.
+ * testsuite/binutils-all/note-2-32.s: Likewise.
+ * testsuite/binutils-all/note-2-64.d: Likewise.
+ * testsuite/binutils-all/note-2-64.s: Likewise.
+ * testsuite/binutils-all/note-3-32.d: Likewise.
+ * testsuite/binutils-all/note-3-32.s: Likewise.
+ * testsuite/binutils-all/note-3-64.d: Likewise.
+ * testsuite/binutils-all/note-3-64.s: Likewise.
+ * testsuite/binutils-all/note-4-32.d: Likewise.
+ * testsuite/binutils-all/note-4-32.s: Likewise.
+ * testsuite/binutils-all/note-4-64.d: Likewise.
+ * testsuite/binutils-all/note-4-64.s: Likewise.
+ * testsuite/binutils-all/note-6-32.s: New test source file.
+ * testsuite/binutils-all/note-6-64.s: New test source file.
+ * testsuite/binutils-all/note-6-32.d: New test driver file.
+ * testsuite/binutils-all/note-6-64.d: New test driver file.
+ * testsuite/binutils-all/objcopy.exp: Run the new test.
+
2019-10-25 Alan Modra <amodra@gmail.com>
* readelf.c (process_program_headers): Check PT_PHDR p_offset
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index bc9d75d..47c5310 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -97,8 +97,14 @@ static int deterministic = -1; /* Enable deterministic archives. */
static int status = 0; /* Exit status. */
static bfd_boolean merge_notes = FALSE; /* Merge note sections. */
-static bfd_byte * merged_notes = NULL; /* Contents on note section undergoing a merge. */
-static bfd_size_type merged_size = 0; /* New, smaller size of the merged note section. */
+
+typedef struct merged_note_section
+{
+ asection * sec; /* The section that is being merged. */
+ bfd_byte * contents;/* New contents of the section. */
+ bfd_size_type size; /* New size of the section. */
+ struct merged_note_section * next; /* Link to next merged note section. */
+} merged_note_section;
enum strip_action
{
@@ -1283,7 +1289,7 @@ is_update_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
}
static bfd_boolean
-is_merged_note_section (bfd * abfd, asection * sec)
+is_mergeable_note_section (bfd * abfd, asection * sec)
{
if (merge_notes
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour
@@ -1292,9 +1298,9 @@ is_merged_note_section (bfd * abfd, asection * sec)
We should add support for more note types. */
&& ((elf_section_data (sec)->this_hdr.sh_flags & SHF_GNU_BUILD_NOTE) != 0
/* Old versions of GAS (prior to 2.27) could not set the section
- flags to OS-specific values, so we also accept sections with the
- expected name. */
- || (strcmp (sec->name, GNU_BUILD_ATTRS_SECTION_NAME) == 0)))
+ flags to OS-specific values, so we also accept sections that
+ start with the expected name. */
+ || (CONST_STRNEQ (sec->name, GNU_BUILD_ATTRS_SECTION_NAME))))
return TRUE;
return FALSE;
@@ -1917,56 +1923,81 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
return TRUE;
}
-/* Returns the number of bytes needed to store VAL. */
-
-static inline unsigned int
-num_bytes (unsigned long val)
-{
- unsigned int count = 0;
-
- /* FIXME: There must be a faster way to do this. */
- while (val)
- {
- count ++;
- val >>= 8;
- }
- return count;
-}
-
typedef struct objcopy_internal_note
{
Elf_Internal_Note note;
+ unsigned long padded_namesz;
bfd_vma start;
bfd_vma end;
- bfd_boolean modified;
} objcopy_internal_note;
-/* Returns TRUE if a gap does, or could, exist between the address range
- covered by PNOTE1 and PNOTE2. */
+#define DEBUG_MERGE 0
+
+#if DEBUG_MERGE
+#define merge_debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
+#else
+#define merge_debug(format, ...)
+#endif
+
+/* Returns TRUE iff PNOTE1 overlaps or adjoins PNOTE2. */
static bfd_boolean
-gap_exists (objcopy_internal_note * pnote1,
- objcopy_internal_note * pnote2)
+overlaps_or_adjoins (objcopy_internal_note * pnote1,
+ objcopy_internal_note * pnote2)
{
- /* Without range end notes, we assume that a gap might exist. */
- if (pnote1->end == 0 || pnote2->end == 0)
+ if (pnote1->end < pnote2->start)
+ /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
+ Really we should extract the alignment of the section
+ covered by the notes. */
+ return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+
+ if (pnote2->end < pnote2->start)
+ return BFD_ALIGN (pnote2->end, 16) < pnote1->start;
+
+ if (pnote1->end < pnote2->end)
+ return TRUE;
+
+ if (pnote2->end < pnote1->end)
return TRUE;
- /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
- Really we should extract the alignment of the section covered by the notes. */
- return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+ return FALSE;
+}
+
+/* Returns TRUE iff NEEDLE is fully contained by HAYSTACK. */
+
+static bfd_boolean
+contained_by (objcopy_internal_note * needle,
+ objcopy_internal_note * haystack)
+{
+ return needle->start >= haystack->start && needle->end <= haystack->end;
}
static bfd_boolean
is_open_note (objcopy_internal_note * pnote)
{
- return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN);
+ return pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
}
static bfd_boolean
is_func_note (objcopy_internal_note * pnote)
{
- return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC);
+ return pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC;
+}
+
+static bfd_boolean
+is_deleted_note (objcopy_internal_note * pnote)
+{
+ return pnote->note.type == 0;
+}
+
+static bfd_boolean
+is_version_note (objcopy_internal_note * pnote)
+{
+ return (pnote->note.namesz > 4
+ && pnote->note.namedata[0] == 'G'
+ && pnote->note.namedata[1] == 'A'
+ && pnote->note.namedata[2] == '$'
+ && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION);
}
static bfd_boolean
@@ -1979,11 +2010,97 @@ is_64bit (bfd * abfd)
return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64;
}
+/* This sorting function is used to get the notes into an order
+ that makes merging easy. */
+
+static int
+compare_gnu_build_notes (const void * data1, const void * data2)
+{
+ objcopy_internal_note * pnote1 = (objcopy_internal_note *) data1;
+ objcopy_internal_note * pnote2 = (objcopy_internal_note *) data2;
+
+ /* Sort notes based upon the attribute they record. */
+ int cmp = memcmp (pnote1->note.namedata + 3,
+ pnote2->note.namedata + 3,
+ pnote1->note.namesz < pnote2->note.namesz ?
+ pnote1->note.namesz - 3 : pnote2->note.namesz - 3);
+ if (cmp)
+ return cmp;
+
+ if (pnote1->end < pnote2->start)
+ return -1;
+ if (pnote1->start > pnote2->end)
+ return 1;
+
+ /* Overlaps - we should merge the two ranges. */
+ if (pnote1->start < pnote2->start)
+ return -1;
+ if (pnote1->end > pnote2->end)
+ return 1;
+
+ /* Put OPEN notes before function notes. */
+ if (is_open_note (pnote1) && ! is_open_note (pnote2))
+ return -1;
+ if (! is_open_note (pnote1) && is_open_note (pnote2))
+ return 1;
+
+ return 0;
+}
+
+/* This sorting function is used to get the notes into an order
+ that makes eliminating address ranges easier. */
+
+static int
+sort_gnu_build_notes (const void * data1, const void * data2)
+{
+ objcopy_internal_note * pnote1 = (objcopy_internal_note *) data1;
+ objcopy_internal_note * pnote2 = (objcopy_internal_note *) data2;
+
+ if (pnote1->note.type != pnote2->note.type)
+ {
+ /* Move deleted notes to the end. */
+ if (is_deleted_note (pnote1)) /* 1: OFD 2: OFD */
+ return 1;
+
+ /* Move OPEN notes to the start. */
+ if (is_open_note (pnote1)) /* 1: OF 2: OFD */
+ return -1;
+
+ if (is_deleted_note (pnote2)) /* 1: F 2: O D */
+ return 1;
+
+ return 1; /* 1: F 2: O */
+ }
+
+ /* Sort by starting address. */
+ if (pnote1->start < pnote2->start)
+ return -1;
+ if (pnote1->start > pnote2->start)
+ return 1;
+
+ /* Then by end address (bigger range first). */
+ if (pnote1->end > pnote2->end)
+ return -1;
+ if (pnote1->end < pnote2->end)
+ return 1;
+
+ /* Then by attribute type. */
+ if (pnote1->note.namesz > 4
+ && pnote2->note.namesz > 4
+ && pnote1->note.namedata[3] != pnote2->note.namedata[3])
+ return pnote1->note.namedata[3] - pnote2->note.namedata[3];
+
+ return 0;
+}
+
/* Merge the notes on SEC, removing redundant entries.
Returns the new, smaller size of the section upon success. */
static bfd_size_type
-merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte * contents)
+merge_gnu_build_notes (bfd * abfd,
+ asection * sec,
+ bfd_size_type size,
+ bfd_byte * contents)
{
objcopy_internal_note * pnotes_end;
objcopy_internal_note * pnotes = NULL;
@@ -1992,11 +2109,8 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
unsigned version_1_seen = 0;
unsigned version_2_seen = 0;
unsigned version_3_seen = 0;
- bfd_boolean duplicate_found = FALSE;
const char * err = NULL;
bfd_byte * in = contents;
- int attribute_type_byte;
- int val_start;
unsigned long previous_func_start = 0;
unsigned long previous_open_start = 0;
unsigned long previous_func_end = 0;
@@ -2015,20 +2129,33 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
free (relpp);
if (relcount != 0)
- goto done;
+ {
+ if (! is_strip)
+ non_fatal (_("%s[%s]: Cannot merge - there are relocations against this section"),
+ bfd_get_filename (abfd), bfd_section_name (sec));
+ goto done;
+ }
}
/* Make a copy of the notes and convert to our internal format.
Minimum size of a note is 12 bytes. Also locate the version
notes and check them. */
- pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote));
+ pnote = pnotes = (objcopy_internal_note *)
+ xcalloc ((size / 12), sizeof (* pnote));
while (remain >= 12)
{
bfd_vma start, end;
- pnote->note.namesz = (bfd_get_32 (abfd, in ) + 3) & ~3;
- pnote->note.descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
- pnote->note.type = bfd_get_32 (abfd, in + 8);
+ pnote->note.namesz = bfd_get_32 (abfd, in);
+ pnote->note.descsz = bfd_get_32 (abfd, in + 4);
+ pnote->note.type = bfd_get_32 (abfd, in + 8);
+ pnote->padded_namesz = (pnote->note.namesz + 3) & ~3;
+
+ if (((pnote->note.descsz + 3) & ~3) != pnote->note.descsz)
+ {
+ err = _("corrupt GNU build attribute note: description size not a factor of 4");
+ goto done;
+ }
if (pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_OPEN
&& pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
@@ -2037,7 +2164,7 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
goto done;
}
- if (pnote->note.namesz + pnote->note.descsz + 12 > remain)
+ if (pnote->padded_namesz + pnote->note.descsz + 12 > remain)
{
err = _("corrupt GNU build attribute note: note too big");
goto done;
@@ -2050,21 +2177,17 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
}
pnote->note.namedata = (char *)(in + 12);
- pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz);
+ pnote->note.descdata = (char *)(in + 12 + pnote->padded_namesz);
- remain -= 12 + pnote->note.namesz + pnote->note.descsz;
- in += 12 + pnote->note.namesz + pnote->note.descsz;
+ remain -= 12 + pnote->padded_namesz + pnote->note.descsz;
+ in += 12 + pnote->padded_namesz + pnote->note.descsz;
if (pnote->note.namesz > 2
&& pnote->note.namedata[0] == '$'
&& pnote->note.namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
&& pnote->note.namedata[2] == '1')
++ version_1_seen;
- else if (pnote->note.namesz > 4
- && pnote->note.namedata[0] == 'G'
- && pnote->note.namedata[1] == 'A'
- && pnote->note.namedata[2] == '$'
- && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION)
+ else if (is_version_note (pnote))
{
if (pnote->note.namedata[4] == '2')
++ version_2_seen;
@@ -2170,11 +2293,18 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
{
+#if 0
err = _("bad GNU build attribute notes: no known versions detected");
goto done;
+#else
+ /* This happens with glibc. No idea why. */
+ non_fatal (_("%s[%s]: Warning: version note missing - assuming version 3"),
+ bfd_get_filename (abfd), bfd_section_name (sec));
+ version_3_seen = 2;
+#endif
}
- if ((version_1_seen > 0 && version_2_seen > 0)
+ if ( (version_1_seen > 0 && version_2_seen > 0)
|| (version_1_seen > 0 && version_3_seen > 0)
|| (version_2_seen > 0 && version_3_seen > 0))
{
@@ -2182,270 +2312,215 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
goto done;
}
- /* Merging is only needed if there is more than one version note... */
- if (version_1_seen == 1 || version_2_seen == 1 || version_3_seen == 1)
- goto done;
+ /* We are now only supporting the merging v3+ notes
+ - it makes things much simpler. */
+ if (version_3_seen == 0)
+ {
+ merge_debug ("%s: skipping merge - not using v3 notes", bfd_section_name (sec));
+ goto done;
+ }
+
+ merge_debug ("Merging section %s which contains %ld notes\n",
+ sec->name, pnotes_end - pnotes);
- attribute_type_byte = version_1_seen ? 1 : 3;
- val_start = attribute_type_byte + 1;
+ /* Sort the notes. */
+ qsort (pnotes, pnotes_end - pnotes, sizeof (* pnotes),
+ compare_gnu_build_notes);
- /* We used to require that the first note be a version note,
- but this is no longer enforced. Due to the problems with
- linking sections with the same name (eg .gnu.build.note.hot)
- we cannot guarantee that the first note will be a version note. */
+#if DEBUG_MERGE
+ merge_debug ("Results of initial sort:\n");
+ for (pnote = pnotes; pnote < pnotes_end; pnote ++)
+ merge_debug ("offset %#08lx range %#08lx..%#08lx type %ld attribute %d namesz %ld\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ pnote->start, pnote->end,
+ pnote->note.type,
+ pnote->note.namedata[3],
+ pnote->note.namesz
+ );
+#endif
/* Now merge the notes. The rules are:
- 1. Preserve the ordering of the notes.
- 2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
- 3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
- full name field as the immediately preceeding note with the same type
- of name and whose address ranges coincide.
- IE - if there are gaps in the coverage of the notes, then these gaps
- must be preserved.
- 4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
- of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
- 5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
- its description field is empty then the nearest preceeding OPEN note
- with a non-empty description field must also be preserved *OR* the
- description field of the note must be changed to contain the starting
- address to which it refers.
- 6. Notes with the same start and end address can be deleted.
- 7. FIXME: Elminate duplicate version notes - even function specific ones ? */
+ 1. If a note has a zero range, it can be eliminated.
+ 2. If two notes have the same namedata then:
+ 2a. If one note's range is fully covered by the other note
+ then it can be deleted.
+ 2b. If one note's range partially overlaps or adjoins the
+ other note then if they are both of the same type (open
+ or func) then they can be merged and one deleted. If
+ they are of different types then they cannot be merged. */
for (pnote = pnotes; pnote < pnotes_end; pnote ++)
{
- int note_type;
- objcopy_internal_note * back;
- objcopy_internal_note * prev_open_with_range = NULL;
+ /* Skip already deleted notes.
+ FIXME: Can this happen ? We are scanning forwards and
+ deleting backwards after all. */
+ if (is_deleted_note (pnote))
+ continue;
- /* Rule 6 - delete 0-range notes. */
+ /* Rule 1 - delete 0-range notes. */
if (pnote->start == pnote->end)
{
- duplicate_found = TRUE;
+ merge_debug ("Delete note at offset %#08lx - empty range\n",
+ (pnote->note.namedata - (char *) contents) - 12);
pnote->note.type = 0;
continue;
}
- /* Rule 2 - preserve function notes. */
- if (! is_open_note (pnote))
- {
- int iter;
-
- /* Check to see if there is an identical previous function note.
- This can happen with overlays for example. */
- for (iter = 0, back = pnote -1; back >= pnotes; back --)
- {
- if (back->start == pnote->start
- && back->end == pnote->end
- && back->note.namesz == pnote->note.namesz
- && memcmp (back->note.namedata, pnote->note.namedata, pnote->note.namesz) == 0)
- {
- duplicate_found = TRUE;
- pnote->note.type = 0;
- break;
- }
-
- /* Don't scan too far back however. */
- if (iter ++ > 16)
- break;
- }
- continue;
- }
-
- note_type = pnote->note.namedata[attribute_type_byte];
+ int iter;
+ objcopy_internal_note * back;
- /* Scan backwards from pnote, looking for duplicates.
- Clear the type field of any found - but do not delete them just yet. */
- for (back = pnote - 1; back >= pnotes; back --)
+ /* Rule 2: Check to see if there is an identical previous note. */
+ for (iter = 0, back = pnote - 1; back >= pnotes; back --)
{
- int back_type = back->note.namedata[attribute_type_byte];
-
- /* If this is the first open note with an address
- range that we have encountered then record it. */
- if (prev_open_with_range == NULL
- && back->note.descsz > 0
- && ! is_func_note (back))
- prev_open_with_range = back;
-
- if (! is_open_note (back))
- continue;
-
- /* If the two notes are different then keep on searching. */
- if (back_type != note_type)
+ if (is_deleted_note (back))
continue;
- /* Rule 4 - combine stack size notes. */
- if (back_type == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
+ /* Our sorting function should have placed all identically
+ attributed notes together, so if we see a note of a different
+ attribute type stop searching. */
+ if (back->note.namesz != pnote->note.namesz
+ || memcmp (back->note.namedata,
+ pnote->note.namedata, pnote->note.namesz) != 0)
+ break;
+
+ if (back->start == pnote->start
+ && back->end == pnote->end)
{
- unsigned char * name;
- unsigned long note_val;
- unsigned long back_val;
- unsigned int shift;
- unsigned int bytes;
- unsigned long byte;
-
- for (shift = 0, note_val = 0,
- bytes = pnote->note.namesz - val_start,
- name = (unsigned char *) pnote->note.namedata + val_start;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- note_val |= byte << shift;
- shift += 8;
- }
-
- for (shift = 0, back_val = 0,
- bytes = back->note.namesz - val_start,
- name = (unsigned char *) back->note.namedata + val_start;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- back_val |= byte << shift;
- shift += 8;
- }
-
- back_val += note_val;
- if (num_bytes (back_val) >= back->note.namesz - val_start)
- {
- /* We have a problem - the new value requires more bytes of
- storage in the name field than are available. Currently
- we have no way of fixing this, so we just preserve both
- notes. */
- continue;
- }
-
- /* Write the new val into back. */
- name = (unsigned char *) back->note.namedata + val_start;
- while (name < (unsigned char *) back->note.namedata
- + back->note.namesz)
- {
- byte = back_val & 0xff;
- * name ++ = byte;
- if (back_val == 0)
- break;
- back_val >>= 8;
- }
-
- duplicate_found = TRUE;
+ merge_debug ("Delete note at offset %#08lx - duplicate of note at offset %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ (back->note.namedata - (char *) contents) - 12);
pnote->note.type = 0;
break;
}
- /* Rule 3 - combine identical open notes. */
- if (back->note.namesz == pnote->note.namesz
- && memcmp (back->note.namedata,
- pnote->note.namedata, back->note.namesz) == 0
- && ! gap_exists (back, pnote))
+ /* Rule 2a. */
+ if (contained_by (pnote, back))
{
- duplicate_found = TRUE;
+ merge_debug ("Delete note at offset %#08lx - fully contained by note at %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ (back->note.namedata - (char *) contents) - 12);
pnote->note.type = 0;
-
- if (pnote->end > back->end)
- back->end = pnote->end;
-
- if (version_3_seen)
- back->modified = TRUE;
break;
}
- /* Rule 5 - Since we are keeping this note we must check to see
- if its description refers back to an earlier OPEN version
- note that has been scheduled for deletion. If so then we
- must make sure that version note is also preserved. */
- if (version_3_seen)
+#if DEBUG_MERGE
+ /* This should not happen as we have sorted the
+ notes with earlier starting addresses first. */
+ if (contained_by (back, pnote))
+ merge_debug ("ERROR: UNEXPECTED CONTAINMENT\n");
+#endif
+
+ /* Rule 2b. */
+ if (overlaps_or_adjoins (back, pnote)
+ && is_func_note (back) == is_func_note (pnote))
{
- /* As of version 3 we can just
- move the range into the note. */
- pnote->modified = TRUE;
- pnote->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
- back->modified = TRUE;
- back->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+ merge_debug ("Delete note at offset %#08lx - merge into note at %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ (back->note.namedata - (char *) contents) - 12);
+
+ back->end = back->end > pnote->end ? back->end : pnote->end;
+ back->start = back->start < pnote->start ? back->start : pnote->start;
+ pnote->note.type = 0;
+ break;
}
- else
+
+ /* Don't scan too far back however. */
+ if (iter ++ > 16)
{
- if (pnote->note.descsz == 0
- && prev_open_with_range != NULL
- && prev_open_with_range->note.type == 0)
- prev_open_with_range->note.type = NT_GNU_BUILD_ATTRIBUTE_OPEN;
+ /* FIXME: Not sure if this can ever be triggered. */
+ merge_debug ("ITERATION LIMIT REACHED\n");
+ break;
}
-
- /* We have found a similar attribute but the details do not match.
- Stop searching backwards. */
- break;
}
+#if DEBUG_MERGE
+ if (! is_deleted_note (pnote))
+ merge_debug ("Unable to do anything with note at %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12);
+#endif
}
- if (duplicate_found)
+ /* Resort the notes. */
+ merge_debug ("Final sorting of notes\n");
+ qsort (pnotes, pnotes_end - pnotes, sizeof (* pnotes), sort_gnu_build_notes);
+
+ /* Reconstruct the ELF notes. */
+ bfd_byte * new_contents;
+ bfd_byte * old;
+ bfd_byte * new;
+ bfd_size_type new_size;
+ bfd_vma prev_start = 0;
+ bfd_vma prev_end = 0;
+
+ new = new_contents = xmalloc (size);
+ for (pnote = pnotes, old = contents;
+ pnote < pnotes_end;
+ pnote ++)
{
- bfd_byte * new_contents;
- bfd_byte * old;
- bfd_byte * new;
- bfd_size_type new_size;
- bfd_vma prev_start = 0;
- bfd_vma prev_end = 0;
-
- /* Eliminate the duplicates. */
- new = new_contents = xmalloc (size);
- for (pnote = pnotes, old = contents;
- pnote < pnotes_end;
- pnote ++)
- {
- bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz;
+ bfd_size_type note_size = 12 + pnote->padded_namesz + pnote->note.descsz;
- if (pnote->note.type != 0)
+ if (! is_deleted_note (pnote))
+ {
+ /* Create the note, potentially using the
+ address range of the previous note. */
+ if (pnote->start == prev_start && pnote->end == prev_end)
+ {
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, 0, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ if (pnote->note.namesz < pnote->padded_namesz)
+ memset (new + pnote->note.namesz, 0, pnote->padded_namesz - pnote->note.namesz);
+ new += pnote->padded_namesz;
+ }
+ else
{
- if (pnote->modified)
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ if (pnote->note.namesz < pnote->padded_namesz)
+ memset (new + pnote->note.namesz, 0, pnote->padded_namesz - pnote->note.namesz);
+ new += pnote->padded_namesz;
+ if (is_64bit (abfd))
{
- /* If the note has been modified then we must copy it by
- hand, potentially adding in a new description field. */
- if (pnote->start == prev_start && pnote->end == prev_end)
- {
- bfd_put_32 (abfd, pnote->note.namesz, new);
- bfd_put_32 (abfd, 0, new + 4);
- bfd_put_32 (abfd, pnote->note.type, new + 8);
- new += 12;
- memcpy (new, pnote->note.namedata, pnote->note.namesz);
- new += pnote->note.namesz;
- }
- else
- {
- bfd_put_32 (abfd, pnote->note.namesz, new);
- bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
- bfd_put_32 (abfd, pnote->note.type, new + 8);
- new += 12;
- memcpy (new, pnote->note.namedata, pnote->note.namesz);
- new += pnote->note.namesz;
- if (is_64bit (abfd))
- {
- bfd_put_64 (abfd, pnote->start, new);
- bfd_put_64 (abfd, pnote->end, new + 8);
- new += 16;
- }
- else
- {
- bfd_put_32 (abfd, pnote->start, new);
- bfd_put_32 (abfd, pnote->end, new + 4);
- new += 8;
- }
- }
+ bfd_put_64 (abfd, pnote->start, new);
+ bfd_put_64 (abfd, pnote->end, new + 8);
+ new += 16;
}
else
{
- memcpy (new, old, note_size);
- new += note_size;
+ bfd_put_32 (abfd, pnote->start, new);
+ bfd_put_32 (abfd, pnote->end, new + 4);
+ new += 8;
}
+
prev_start = pnote->start;
prev_end = pnote->end;
}
-
- old += note_size;
}
- new_size = new - new_contents;
- memcpy (contents, new_contents, new_size);
- size = new_size;
- free (new_contents);
+ old += note_size;
}
+#if DEBUG_MERGE
+ merge_debug ("Results of merge:\n");
+ for (pnote = pnotes; pnote < pnotes_end; pnote ++)
+ if (! is_deleted_note (pnote))
+ merge_debug ("offset %#08lx range %#08lx..%#08lx type %ld attribute %d namesz %ld\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ pnote->start, pnote->end,
+ pnote->note.type,
+ pnote->note.namedata[3],
+ pnote->note.namesz
+ );
+#endif
+
+ new_size = new - new_contents;
+ memcpy (contents, new_contents, new_size);
+ size = new_size;
+ free (new_contents);
+
done:
if (err)
{
@@ -2783,53 +2858,62 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
}
}
+ merged_note_section * merged_note_sections = NULL;
if (merge_notes)
{
/* This palaver is necessary because we must set the output
section size first, before its contents are ready. */
- osec = bfd_get_section_by_name (ibfd, GNU_BUILD_ATTRS_SECTION_NAME);
- if (osec && is_merged_note_section (ibfd, osec))
+ for (osec = ibfd->sections; osec != NULL; osec = osec->next)
{
- bfd_size_type size;
-
- size = bfd_section_size (osec);
+ if (! is_mergeable_note_section (ibfd, osec))
+ continue;
+
+ bfd_size_type size = bfd_section_size (osec);
+
if (size == 0)
{
- bfd_nonfatal_message (NULL, ibfd, osec, _("warning: note section is empty"));
- merge_notes = FALSE;
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("warning: note section is empty"));
+ continue;
}
- else if (! bfd_get_full_section_contents (ibfd, osec, & merged_notes))
+
+ merged_note_section * merged = xmalloc (sizeof * merged);
+ merged->contents = NULL;
+ if (! bfd_get_full_section_contents (ibfd, osec, & merged->contents))
{
- bfd_nonfatal_message (NULL, ibfd, osec, _("warning: could not load note section"));
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("warning: could not load note section"));
+ free (merged->contents);
+ free (merged);
+ continue;
}
- else
+
+ merged->size = merge_gnu_build_notes (ibfd, osec, size,
+ merged->contents);
+ if (merged->size == size)
{
- merged_size = merge_gnu_build_notes (ibfd, osec, size, merged_notes);
- if (merged_size == size)
- {
- /* Merging achieves nothing. */
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
- merged_size = 0;
- }
- else
- {
- if (osec->output_section == NULL
- || !bfd_set_section_size (osec->output_section,
- merged_size))
- {
- bfd_nonfatal_message (NULL, obfd, osec, _("warning: failed to set merged notes size"));
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
- merged_size = 0;
- }
- }
+ /* Merging achieves nothing. */
+ merge_debug ("Merge of section %s achieved nothing - skipping\n",
+ bfd_section_name (osec));
+ free (merged->contents);
+ free (merged);
+ continue;
}
+
+ if (osec->output_section == NULL
+ || !bfd_set_section_size (osec->output_section, merged->size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec,
+ _("warning: failed to set merged notes size"));
+ free (merged->contents);
+ free (merged);
+ continue;
+ }
+
+ /* Add section to list of merged sections. */
+ merged->sec = osec;
+ merged->next = merged_note_sections;
+ merged_note_sections = merged;
}
}
@@ -3154,23 +3238,72 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
}
}
- if (merge_notes)
+ if (merged_note_sections != NULL)
{
- osec = bfd_get_section_by_name (obfd, GNU_BUILD_ATTRS_SECTION_NAME);
- if (osec && is_merged_note_section (obfd, osec))
+ merged_note_section * merged = NULL;
+
+ for (osec = obfd->sections; osec != NULL; osec = osec->next)
{
- if (! bfd_set_section_contents (obfd, osec, merged_notes, 0, merged_size))
+ if (! is_mergeable_note_section (obfd, osec))
+ continue;
+
+ if (merged == NULL)
+ merged = merged_note_sections;
+
+ /* It is likely that output sections are in the same order
+ as the input sections, but do not assume that this is
+ the case. */
+ if (strcmp (bfd_section_name (merged->sec),
+ bfd_section_name (osec)) != 0)
{
- bfd_nonfatal_message (NULL, obfd, osec, _("error: failed to copy merged notes into output"));
+ for (merged = merged_note_sections;
+ merged != NULL;
+ merged = merged->next)
+ if (strcmp (bfd_section_name (merged->sec),
+ bfd_section_name (osec)) == 0)
+ break;
+
+ if (merged == NULL)
+ {
+ bfd_nonfatal_message
+ (NULL, obfd, osec,
+ _("error: failed to copy merged notes into output"));
+ continue;
+ }
+ }
+
+ if (! is_mergeable_note_section (obfd, osec))
+ {
+ bfd_nonfatal_message
+ (NULL, obfd, osec,
+ _("error: failed to copy merged notes into output"));
+ continue;
+ }
+
+ if (! bfd_set_section_contents (obfd, osec, merged->contents, 0,
+ merged->size))
+ {
+ bfd_nonfatal_message
+ (NULL, obfd, osec,
+ _("error: failed to copy merged notes into output"));
return FALSE;
}
+
+ merged = merged->next;
+ }
+
+ /* Free the memory. */
+ merged_note_section * next;
+ for (merged = merged_note_sections; merged != NULL; merged = next)
+ {
+ next = merged->next;
+ free (merged->contents);
+ free (merged);
}
- else if (! is_strip)
- bfd_nonfatal_message (NULL, obfd, osec, _("could not find any mergeable note sections"));
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
}
+ else if (merge_notes && ! is_strip)
+ non_fatal (_("%s: Could not find any mergeable note sections"),
+ bfd_get_filename (ibfd));
if (gnu_debuglink_filename != NULL)
{
@@ -3959,7 +4092,7 @@ skip_section (bfd *ibfd, sec_ptr isection, bfd_boolean skip_copy)
/* When merging a note section we skip the copying of the contents,
but not the copying of the relocs associated with the contents. */
- if (skip_copy && is_merged_note_section (ibfd, isection))
+ if (skip_copy && is_mergeable_note_section (ibfd, isection))
return TRUE;
flags = bfd_section_flags (isection);
diff --git a/binutils/testsuite/binutils-all/note-2-32.d b/binutils/testsuite/binutils-all/note-2-32.d
index 923cf7c..1412ad7 100644
--- a/binutils/testsuite/binutils-all/note-2-32.d
+++ b/binutils/testsuite/binutils-all/note-2-32.d
@@ -6,12 +6,11 @@
#...
[ ]+Owner[ ]+Data size[ ]+Description
-[ ]+\$<version>1[ ]+0x00000004[ ]+OPEN[ ]+Applies to region from 0x100 \(note1.s\)
-[ ]+\$<tool>gcc 7.0.1[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\+<stack prot>true[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\*<PIC>static[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\*<ABI>0x0[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\$<version>1[ ]+0x00000004[ ]+OPEN[ ]+Applies to region from 0x104 \(note2.s\)
-[ ]+!<stack prot>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x104
-[ ]+\*<PIC>pic[ ]+0x00000004[ ]+func[ ]+Applies to region from 0x104 \(func1\)
+[ ]+GA\$<version>3p1[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x100 to 0x10b \(note1.s\)
+[ ]+GA\$<tool>gcc 7.0.1[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x10b
+[ ]+GA\*<ABI>0x0[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x100 to 0x108 \(note1.s\)
+[ ]+GA\+<stack prot>true[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x100 to 0x104 \(note1.s\)
+[ ]+GA\*<PIC>static[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x104
+[ ]+GA!<stack prot>false[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x104 to 0x108 \(note2.s\)
+[ ]+GA\*<PIC>pic[ ]+0x00000008[ ]+func[ ]+Applies to region from 0x104 to 0x106 \(func1\)
#...
diff --git a/binutils/testsuite/binutils-all/note-2-32.s b/binutils/testsuite/binutils-all/note-2-32.s
index 7b025ae..ccb6cec 100644
--- a/binutils/testsuite/binutils-all/note-2-32.s
+++ b/binutils/testsuite/binutils-all/note-2-32.s
@@ -6,32 +6,37 @@ note1.s:
.pushsection .gnu.build.attributes, "0x100000", %note
.balign 4
- .dc.l 4
- .dc.l 4
+ .dc.l 8
+ .dc.l 8
.dc.l 0x100
- .asciz "$1"
+ .asciz "GA$3p1"
.dc.l 0x100
+ .dc.l 0x104
- .dc.l 12
+ .dc.l 14
.dc.l 0
.dc.l 0x100
- .asciz "$gcc 7.0.1"
+ .asciz "GA$gcc 7.0.1"
+ .dc.b 0,0
- .dc.l 3
+ .dc.l 5
.dc.l 0
.dc.l 0x100
- .dc.b 0x2b, 0x2, 0
- .dc.b 0
+ .dc.b 0x47, 0x41, 0x2b, 0x2, 0
+ .dc.b 0,0,0
- .dc.l 4
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2a, 0x7, 0, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0, 0
+ .dc.b 0,0
- .dc.l 4
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2a, 0x6, 0, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0, 0
+ .dc.b 0,0
+
.popsection
@@ -42,33 +47,38 @@ func1:
.dc.l 0x100
.pushsection .gnu.build.attributes, "0x100000", %note
- .dc.l 4
- .dc.l 4
+ .dc.l 8
+ .dc.l 8
.dc.l 0x100
- .asciz "$1"
+ .asciz "GA$3p1"
.dc.l 0x104
-
- .dc.l 12
+ .dc.l 0x108
+
+ .dc.l 14
.dc.l 0
.dc.l 0x100
- .asciz "$gcc 7.0.1"
+ .asciz "GA$gcc 7.0.1"
+ .dc.b 0,0
- .dc.l 3
+ .dc.l 5
.dc.l 0
.dc.l 0x100
- .dc.b 0x21, 0x2, 0
- .dc.b 0
+ .dc.b 0x47, 0x41, 0x21, 0x2, 0
+ .dc.b 0,0,0
- .dc.l 4
- .dc.l 4
+ .dc.l 6
+ .dc.l 8
.dc.l 0x101
- .dc.b 0x2a, 0x7, 1, 0
- .dc.l 0x104
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 1, 0
+ .dc.b 0,0
+ .dc.l 0x104
+ .dc.l 0x106
- .dc.l 4
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2a, 0x6, 0, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0, 0
+ .dc.b 0,0
.popsection
@@ -77,16 +87,18 @@ note3.s:
.dc.l 0x100
.pushsection .gnu.build.attributes, "0x100000", %note
- .dc.l 4
- .dc.l 4
+ .dc.l 8
+ .dc.l 8
.dc.l 0x100
- .asciz "$1"
+ .asciz "GA$3p1"
.dc.l 0x108
+ .dc.l 0x10b
- .dc.l 12
+ .dc.l 14
.dc.l 0
.dc.l 0x100
- .asciz "$gcc 7.0.1"
+ .asciz "GA$gcc 7.0.1"
+ .dc.b 0,0
.popsection
diff --git a/binutils/testsuite/binutils-all/note-2-64.d b/binutils/testsuite/binutils-all/note-2-64.d
index 1c73083..26a0231 100644
--- a/binutils/testsuite/binutils-all/note-2-64.d
+++ b/binutils/testsuite/binutils-all/note-2-64.d
@@ -10,12 +10,11 @@
#...
[ ]+Owner[ ]+Data size[ ]+Description
-[ ]+\$<version>1[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x100 \(note1.s\)
-[ ]+\$<tool>gcc 7.0.1[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\+<stack prot>true[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\*<PIC>static[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\*<ABI>0x0[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100
-[ ]+\$<version>1[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x104 \(note2.s\)
-[ ]+!<stack prot>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x104
-[ ]+\*<PIC>pic[ ]+0x00000008[ ]+func[ ]+Applies to region from 0x104 \(func1\)
+[ ]+GA\$<version>3p1[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x100 to 0x10b \(note1.s\)
+[ ]+GA\$<tool>gcc 7.0.1[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x10b
+[ ]+GA\*<ABI>0x0[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x100 to 0x108 \(note1.s\)
+[ ]+GA\+<stack prot>true[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x100 to 0x104 \(note1.s\)
+[ ]+GA\*<PIC>static[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x104
+[ ]+GA!<stack prot>false[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x104 to 0x108 \(note2.s\)
+[ ]+GA\*<PIC>pic[ ]+0x00000010[ ]+func[ ]+Applies to region from 0x104 to 0x106 \(func1\)
#...
diff --git a/binutils/testsuite/binutils-all/note-2-64.s b/binutils/testsuite/binutils-all/note-2-64.s
index 02b84e4..e421d6b 100644
--- a/binutils/testsuite/binutils-all/note-2-64.s
+++ b/binutils/testsuite/binutils-all/note-2-64.s
@@ -6,32 +6,43 @@ note1.s:
.pushsection .gnu.build.attributes, "0x100000", %note
.balign 4
- .dc.l 4
.dc.l 8
+ .dc.l 16
.dc.l 0x100
- .asciz "$1"
+ .asciz "GA$3p1"
.8byte 0x100
+ .8byte 0x104
- .dc.l 12
+ .dc.l 14
.dc.l 0
.dc.l 0x100
- .asciz "$gcc 7.0.1"
+ .asciz "GA$gcc 7.0.1"
+ .dc.b 0,0
+
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2b, 0x2, 0
+ .dc.b 0,0,0
- .dc.l 3
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2b, 0x2, 0
- .dc.b 0
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0, 0
+ .dc.b 0,0
- .dc.l 4
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2a, 0x7, 0, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0, 0
+ .dc.b 0,0
- .dc.l 4
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2a, 0x6, 0, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0, 0
+ .dc.b 0,0
+
.popsection
@@ -43,33 +54,38 @@ func1:
.dc.l 0x100
.pushsection .gnu.build.attributes, "0x100000", %note
- .dc.l 4
- .dc.l 8
+ .dc.l 8
+ .dc.l 16
.dc.l 0x100
- .asciz "$1"
+ .asciz "GA$3p1"
.8byte 0x104
+ .8byte 0x108
- .dc.l 12
+ .dc.l 14
.dc.l 0
.dc.l 0x100
- .asciz "$gcc 7.0.1"
-
- .dc.l 3
+ .asciz "GA$gcc 7.0.1"
+ .dc.b 0,0
+
+ .dc.l 5
.dc.l 0
.dc.l 0x100
- .dc.b 0x21, 0x2, 0
- .dc.b 0
+ .dc.b 0x47, 0x41, 0x21, 0x2, 0
+ .dc.b 0,0,7
- .dc.l 4
- .dc.l 8
+ .dc.l 6
+ .dc.l 16
.dc.l 0x101
- .dc.b 0x2a, 0x7, 1, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 1, 0
+ .dc.b 0,0
.8byte 0x104
+ .8byte 0x106
- .dc.l 4
+ .dc.l 6
.dc.l 0
.dc.l 0x100
- .dc.b 0x2a, 0x6, 0, 0
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0, 0
+ .dc.b 0,0
.popsection
@@ -78,15 +94,17 @@ note3.s:
.dc.l 0x100
.pushsection .gnu.build.attributes, "0x100000", %note
- .dc.l 4
- .dc.l 8
+ .dc.l 8
+ .dc.l 16
.dc.l 0x100
- .asciz "$1"
+ .asciz "GA$3p1"
.8byte 0x108
+ .8byte 0x10b
- .dc.l 12
+ .dc.l 14
.dc.l 0
.dc.l 0x100
- .asciz "$gcc 7.0.1"
+ .asciz "GA$gcc 7.0.1"
+ .dc.b 0,0
.popsection
diff --git a/binutils/testsuite/binutils-all/note-3-32.d b/binutils/testsuite/binutils-all/note-3-32.d
index e35e9cc..783a409 100644
--- a/binutils/testsuite/binutils-all/note-3-32.d
+++ b/binutils/testsuite/binutils-all/note-3-32.d
@@ -7,12 +7,12 @@
#...
Displaying notes found in: .gnu.build.attributes
[ ]+Owner[ ]+Data size[ ]+Description
-[ ]+GA\$<version>2p1[ ]+0x0000000.[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122 \(note_1.s\)
-[ ]+GA\$<tool>gcc 6.3.1 20161221[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
-[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\$<version>3p1[ ]+0x0000000.[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122 \(note_1.s\)
[ ]+GA\*<stack prot>off[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
-[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\$<tool>gcc 6.3.1 20161221[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
[ ]+GA\*<PIC>PIC[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
[ ]+GA\!<short enum>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
-[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
#...
diff --git a/binutils/testsuite/binutils-all/note-3-32.s b/binutils/testsuite/binutils-all/note-3-32.s
index e2e06f9..a9993c6 100644
--- a/binutils/testsuite/binutils-all/note-3-32.s
+++ b/binutils/testsuite/binutils-all/note-3-32.s
@@ -9,10 +9,11 @@ note_1.s:
.balign 4
.dc.l 8
- .dc.l 4
+ .dc.l 8
.dc.l 0x100
- .asciz "GA$2p1"
- .dc.l note_1.s
+ .asciz "GA$3p1"
+ .dc.l 0x100 /* note_1.s */
+ .dc.l 0x122 /* note_1.s end */
.dc.l 23
.dc.l 0
@@ -55,4 +56,12 @@ note_1.s:
.dc.l 0x100
.dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
.dc.b 0, 0, 0
+
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x21, 0x8, 0
+ .dc.b 0, 0, 0
+
+
.popsection
diff --git a/binutils/testsuite/binutils-all/note-3-64.d b/binutils/testsuite/binutils-all/note-3-64.d
index 9899ea1..61a4d9f 100644
--- a/binutils/testsuite/binutils-all/note-3-64.d
+++ b/binutils/testsuite/binutils-all/note-3-64.d
@@ -7,12 +7,12 @@
#...
Displaying notes found in: .gnu.build.attributes
[ ]+Owner[ ]+Data size[ ]+Description
-[ ]+GA\$<version>2p1[ ]+0x0000000.[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122 \(note_1.s\)
-[ ]+GA\$<tool>gcc 6.3.1 20161221[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
-[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\$<version>3p1[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122 \(note_1.s\)
[ ]+GA\*<stack prot>off[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
-[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\$<tool>gcc 6.3.1 20161221[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
[ ]+GA\*<PIC>PIC[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
[ ]+GA\!<short enum>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
-[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
+[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x122
#...
diff --git a/binutils/testsuite/binutils-all/note-3-64.s b/binutils/testsuite/binutils-all/note-3-64.s
index e7d27d2..e0fd62f 100644
--- a/binutils/testsuite/binutils-all/note-3-64.s
+++ b/binutils/testsuite/binutils-all/note-3-64.s
@@ -9,10 +9,11 @@ note_1.s:
.balign 4
.dc.l 8
- .dc.l 8
+ .dc.l 16
.dc.l 0x100
- .asciz "GA$2p1"
- .8byte note_1.s
+ .asciz "GA$3p1"
+ .8byte 0x100 /* note_1.s */
+ .8byte 0x122 /* note_1 end */
.dc.l 23
.dc.l 0
@@ -55,4 +56,11 @@ note_1.s:
.dc.l 0x100
.dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
.dc.b 0, 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+ .dc.b 0, 0
+
.popsection
diff --git a/binutils/testsuite/binutils-all/note-4-32.d b/binutils/testsuite/binutils-all/note-4-32.d
index 6c9e98e..33784c3 100644
--- a/binutils/testsuite/binutils-all/note-4-32.d
+++ b/binutils/testsuite/binutils-all/note-4-32.d
@@ -8,12 +8,12 @@
Displaying notes found in: .gnu.build.attributes
[ ]+Owner[ ]+Data size[ ]+Description
[ ]+GA\$<version>3p3[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110 \(note_4.s\)
-[ ]+GA\$<tool>gcc 7.2.1 20170915[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
-[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
[ ]+GA\*<stack prot>off[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
-[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
+[ ]+GA\$<tool>gcc 7.2.1 20170915[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
+[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
[ ]+GA\*<PIC>PIC[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
[ ]+GA\!<short enum>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
-[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
+[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
+[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x10. to 0x110
[ ]+GA\*<stack prot>strong[ ]+0x00000008[ ]+func[ ]+Applies to region from 0x10. to 0x10c.*
#...
diff --git a/binutils/testsuite/binutils-all/note-4-32.s b/binutils/testsuite/binutils-all/note-4-32.s
index 20d9e7b..722ab7a 100644
--- a/binutils/testsuite/binutils-all/note-4-32.s
+++ b/binutils/testsuite/binutils-all/note-4-32.s
@@ -18,8 +18,8 @@ note_4.s_end:
.dc.l 8
.dc.l 0x100
.asciz "GA$3p3"
- .dc.l note_4.s - 2
- .dc.l note_4.s_end
+ .dc.l 0x100 /* note_4.s - 2 */
+ .dc.l 0x110 /* note_4.s_end */
.dc.l 23
.dc.l 0
@@ -63,12 +63,18 @@ note_4.s_end:
.dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
.dc.b 0, 0, 0
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x21, 0x8, 0
+ .dc.b 0, 0, 0
+
.dc.l 6
.dc.l 8
.dc.l 0x101
.dc.b 0x47, 0x41, 0x2a, 0x2, 0x3, 0
.dc.b 0, 0
- .dc.l bar
- .dc.l bar_end
+ .dc.l 0x108 /* bar */
+ .dc.l 0x10c /* bar_end */
.popsection
diff --git a/binutils/testsuite/binutils-all/note-4-64.d b/binutils/testsuite/binutils-all/note-4-64.d
index f81c9c4..1520d43 100644
--- a/binutils/testsuite/binutils-all/note-4-64.d
+++ b/binutils/testsuite/binutils-all/note-4-64.d
@@ -8,12 +8,12 @@
Displaying notes found in: .gnu.build.attributes
[ ]+Owner[ ]+Data size[ ]+Description
[ ]+GA\$<version>3p3[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120 \(note_4.s\)
-[ ]+GA\$<tool>gcc 7.2.1 20170915[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
-[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
[ ]+GA\*<stack prot>off[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
-[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
+[ ]+GA\$<tool>gcc 7.2.1 20170915[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
+[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
[ ]+GA\*<PIC>PIC[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
[ ]+GA\!<short enum>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
-[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
-[ ]+GA\*<stack prot>strong[ ]+0x00000010[ ]+func[ ]+Applies to region from 0x110 to 0x11c.*
+[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
+[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x120
+[ ]+GA\*<stack prot>strong[ ]+0x00000010[ ]+func[ ]+Applies to region from 0x110 to 0x120.*
#...
diff --git a/binutils/testsuite/binutils-all/note-4-64.s b/binutils/testsuite/binutils-all/note-4-64.s
index 1901682..70b2e57 100644
--- a/binutils/testsuite/binutils-all/note-4-64.s
+++ b/binutils/testsuite/binutils-all/note-4-64.s
@@ -22,8 +22,8 @@ note_4.s_end:
.dc.l 16
.dc.l 0x100
.asciz "GA$3p3"
- .8byte note_4.s - 2
- .8byte note_4.s_end
+ .8byte 0x100 /* note_4.s - 2 */
+ .8byte 0x120 /* note_4.s_end */
.dc.l 23
.dc.l 0
@@ -68,11 +68,17 @@ note_4.s_end:
.dc.b 0, 0, 0
.dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+ .dc.b 0, 0
+
+ .dc.l 6
.dc.l 16
.dc.l 0x101
.dc.b 0x47, 0x41, 0x2a, 0x2, 0x3, 0
.dc.b 0, 0
- .8byte bar
- .8byte bar_end
+ .8byte 0x110 /* bar */
+ .8byte 0x120 /* bar_end */
.popsection
diff --git a/binutils/testsuite/binutils-all/note-6-32.d b/binutils/testsuite/binutils-all/note-6-32.d
new file mode 100644
index 0000000..75b7b59
--- /dev/null
+++ b/binutils/testsuite/binutils-all/note-6-32.d
@@ -0,0 +1,20 @@
+#PROG: objcopy
+#readelf: --notes --wide
+#objcopy: --merge-notes
+#name: v3 gnu build attribute note merging (32-bit)
+#source: note-6-32.s
+
+#...
+Displaying notes found in: .gnu.build.attributes
+[ ]+Owner[ ]+Data size[ ]+Description
+[ ]+GA\$<version>3p1[ ]+0x00000008[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106 \(note_test\)
+[ ]+GA\*<stack prot>off[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\$<tool>gcc 8.3.1 20190507[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*<PIC>PIC[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\!<short enum>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\$<version>3p1[ ]+0x00000008[ ]+func[ ]+Applies to region from 0x102 to 0x106
+[ ]+GA\$<tool>hello world[ ]+0x00000000[ ]+func[ ]+Applies to region from 0x102 to 0x106
+#...
diff --git a/binutils/testsuite/binutils-all/note-6-32.s b/binutils/testsuite/binutils-all/note-6-32.s
new file mode 100644
index 0000000..12a1c76
--- /dev/null
+++ b/binutils/testsuite/binutils-all/note-6-32.s
@@ -0,0 +1,145 @@
+ .text
+ .org 0x100
+ .global note_test
+note_test:
+note_1_start:
+ .word 0
+note_1_end:
+note_2_start:
+ .word 0
+note_2_end:
+note_3_start:
+ .word 0
+note_3_end:
+note_test_end:
+ .size note_test, note_test_end - note_test
+
+ .pushsection .gnu.build.attributes, "", %note
+ .balign 4
+
+ .dc.l 8
+ .dc.l 8
+ .dc.l 0x100
+ .asciz "GA$3p1"
+ .4byte 0x100 /* note_1_start */
+ .4byte 0x102 /* note_1_end */
+
+ .dc.l 23
+ .dc.l 0
+ .dc.l 0x100
+ .asciz "GA$gcc 8.3.1 20190507"
+ .dc.b 0
+
+ .dc.l 10
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x47, 0x4f, 0x57, 0, 0, 0x7, 0
+ .dc.b 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x2, 0, 0
+ .dc.b 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x46, 0x4f, 0x52, 0x54, 0x49, 0x46, 0x59, 0, 0xff, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+ .dc.b 0, 0
+
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x21, 0x8, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
+ .dc.b 0, 0, 0
+
+
+ .dc.l 8
+ .dc.l 8
+ .dc.l 0x100
+ .asciz "GA$3p1"
+ .4byte 0x102 /* note_2_start */
+ .4byte 0x106 /* note_3_end */
+
+ .dc.l 23
+ .dc.l 0
+ .dc.l 0x100
+ .asciz "GA$gcc 8.3.1 20190507"
+ .dc.b 0
+
+ .dc.l 10
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x47, 0x4f, 0x57, 0, 0, 0x7, 0
+ .dc.b 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x2, 0, 0
+ .dc.b 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x46, 0x4f, 0x52, 0x54, 0x49, 0x46, 0x59, 0, 0xff, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+ .dc.b 0, 0
+
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x21, 0x8, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
+ .dc.b 0, 0, 0
+
+
+ .dc.l 8
+ .dc.l 8
+ .dc.l 0x101
+ .asciz "GA$3p1"
+ .4byte 0x102 /* note_2_start */
+ .4byte 0x104 /* note_2_end */
+
+ .dc.l 16
+ .dc.l 0
+ .dc.l 0x101
+ .asciz "GA$hello world"
+
+
+ .dc.l 8
+ .dc.l 8
+ .dc.l 0x101
+ .asciz "GA$3p1"
+ .4byte 0x104 /* note_3_start */
+ .4byte 0x106 /* note_3_end */
+
+ .dc.l 16
+ .dc.l 0
+ .dc.l 0x101
+ .asciz "GA$hello world"
+
+ .popsection
diff --git a/binutils/testsuite/binutils-all/note-6-64.d b/binutils/testsuite/binutils-all/note-6-64.d
new file mode 100644
index 0000000..0bdec23
--- /dev/null
+++ b/binutils/testsuite/binutils-all/note-6-64.d
@@ -0,0 +1,20 @@
+#PROG: objcopy
+#readelf: --notes --wide
+#objcopy: --merge-notes
+#name: v3 gnu build attribute note merging (64-bit)
+#source: note-6-64.s
+
+#...
+Displaying notes found in: .gnu.build.attributes
+[ ]+Owner[ ]+Data size[ ]+Description
+[ ]+GA\$<version>3p1[ ]+0x00000010[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106 \(note_test\)
+[ ]+GA\*<stack prot>off[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\$<tool>gcc 8.3.1 20190507[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*<ABI>0x[0-9a-f]+[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*<PIC>PIC[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\!<short enum>false[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*FORTIFY:0xff[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\*GOW:0x700[ ]+0x00000000[ ]+OPEN[ ]+Applies to region from 0x100 to 0x106
+[ ]+GA\$<version>3p1[ ]+0x00000010[ ]+func[ ]+Applies to region from 0x102 to 0x106
+[ ]+GA\$<tool>hello world[ ]+0x00000000[ ]+func[ ]+Applies to region from 0x102 to 0x106
+#...
diff --git a/binutils/testsuite/binutils-all/note-6-64.s b/binutils/testsuite/binutils-all/note-6-64.s
new file mode 100644
index 0000000..3fe3f9d
--- /dev/null
+++ b/binutils/testsuite/binutils-all/note-6-64.s
@@ -0,0 +1,145 @@
+ .text
+ .org 0x100
+ .global note_test
+note_test:
+note_1_start:
+ .word 0
+note_1_end:
+note_2_start:
+ .word 0
+note_2_end:
+note_3_start:
+ .word 0
+note_3_end:
+note_test_end:
+ .size note_test, note_test_end - note_test
+
+ .pushsection .gnu.build.attributes, "", %note
+ .balign 4
+
+ .dc.l 8
+ .dc.l 16
+ .dc.l 0x100
+ .asciz "GA$3p1"
+ .8byte 0x100 /* note_1_start */
+ .8byte 0x102 /* note_1_end */
+
+ .dc.l 23
+ .dc.l 0
+ .dc.l 0x100
+ .asciz "GA$gcc 8.3.1 20190507"
+ .dc.b 0
+
+ .dc.l 10
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x47, 0x4f, 0x57, 0, 0, 0x7, 0
+ .dc.b 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x2, 0, 0
+ .dc.b 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x46, 0x4f, 0x52, 0x54, 0x49, 0x46, 0x59, 0, 0xff, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+ .dc.b 0, 0
+
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x21, 0x8, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
+ .dc.b 0, 0, 0
+
+
+ .dc.l 8
+ .dc.l 16
+ .dc.l 0x100
+ .asciz "GA$3p1"
+ .8byte 0x102 /* note_2_start */
+ .8byte 0x106 /* note_3_end */
+
+ .dc.l 23
+ .dc.l 0
+ .dc.l 0x100
+ .asciz "GA$gcc 8.3.1 20190507"
+ .dc.b 0
+
+ .dc.l 10
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x47, 0x4f, 0x57, 0, 0, 0x7, 0
+ .dc.b 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x2, 0, 0
+ .dc.b 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x46, 0x4f, 0x52, 0x54, 0x49, 0x46, 0x59, 0, 0xff, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 6
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x7, 0x2, 0
+ .dc.b 0, 0
+
+ .dc.l 5
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x21, 0x8, 0
+ .dc.b 0, 0, 0
+
+ .dc.l 13
+ .dc.l 0
+ .dc.l 0x100
+ .dc.b 0x47, 0x41, 0x2a, 0x6, 0xf2, 0x3, 0x38, 0xee, 0xce, 0xfa, 0x5e, 0x3c, 0
+ .dc.b 0, 0, 0
+
+
+ .dc.l 8
+ .dc.l 16
+ .dc.l 0x101
+ .asciz "GA$3p1"
+ .8byte 0x102 /* note_2_start */
+ .8byte 0x104 /* note_2_end */
+
+ .dc.l 16
+ .dc.l 0
+ .dc.l 0x101
+ .asciz "GA$hello world"
+
+
+ .dc.l 8
+ .dc.l 16
+ .dc.l 0x101
+ .asciz "GA$3p1"
+ .8byte 0x104 /* note_3_start */
+ .8byte 0x106 /* note_3_end */
+
+ .dc.l 16
+ .dc.l 0
+ .dc.l 0x101
+ .asciz "GA$hello world"
+
+ .popsection
diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index e12a828..6c4b019 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -1108,10 +1108,12 @@ if [is_elf_format] {
run_dump_test "note-2-64"
run_dump_test "note-3-64"
run_dump_test "note-4-64"
+ run_dump_test "note-6-64"
} else {
run_dump_test "note-2-32"
run_dump_test "note-3-32"
run_dump_test "note-4-32"
+ run_dump_test "note-6-32"
}
run_dump_test "note-5"
}