From 44c0bed7f346f67254dc02573a89dbc07903e8d2 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 28 Jun 2017 16:35:11 +0100 Subject: [PATCH] Update support for GNU Build Attribute notes to include version 2 notes. --- binutils-gnu-build-notes.patch | 335 +++++++++++++++++++++++++++++++++ binutils.spec | 5 +- 2 files changed, 339 insertions(+), 1 deletion(-) diff --git a/binutils-gnu-build-notes.patch b/binutils-gnu-build-notes.patch index 71a1339..00f6294 100644 --- a/binutils-gnu-build-notes.patch +++ b/binutils-gnu-build-notes.patch @@ -1646,3 +1646,338 @@ diff -rup binutils.orig/binutils/readelf.c binutils-2.28/binutils/readelf.c } } break; +diff -rup binutils.orig/binutils/objcopy.c binutils-2.28/binutils/objcopy.c +--- binutils.orig/binutils/objcopy.c 2017-06-28 15:28:35.859154073 +0100 ++++ binutils-2.28/binutils/objcopy.c 2017-06-28 15:33:35.093694480 +0100 +@@ -1854,14 +1854,17 @@ merge_gnu_build_notes (bfd * abfd, asect + Elf_Internal_Note * pnotes; + Elf_Internal_Note * pnote; + bfd_size_type remain = size; +- unsigned version_notes_seen = 0; ++ unsigned version_1_seen = 0; ++ unsigned version_2_seen = 0; + bfd_boolean duplicate_found = FALSE; + const char * err = NULL; + bfd_byte * in = contents; ++ int attribute_type_byte; ++ int val_start; + + /* Make a copy of the notes. + Minimum size of a note is 12 bytes. */ +- pnote = pnotes = (Elf_Internal_Note *) xmalloc ((size / 12) * sizeof (Elf_Internal_Note)); ++ pnote = pnotes = (Elf_Internal_Note *) xcalloc ((size / 12), sizeof (Elf_Internal_Note)); + while (remain >= 12) + { + pnote->namesz = (bfd_get_32 (abfd, in ) + 3) & ~3; +@@ -1901,8 +1904,24 @@ merge_gnu_build_notes (bfd * abfd, asect + remain -= 12 + pnote->namesz + pnote->descsz; + in += 12 + pnote->namesz + pnote->descsz; + +- if (pnote->namesz > 1 && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION) +- ++ version_notes_seen; ++ if (pnote->namedata[pnote->namesz - 1] != 0) ++ { ++ err = _("corrupt GNU build attribute note: name not NUL terminated"); ++ goto done; ++ } ++ ++ if (pnote->namesz > 2 ++ && pnote->namedata[0] == '$' ++ && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION ++ && pnote->namedata[2] == '1') ++ ++ version_1_seen; ++ else if (pnote->namesz > 4 ++ && pnote->namedata[0] == 'G' ++ && pnote->namedata[1] == 'A' ++ && pnote->namedata[2] == '$' ++ && pnote->namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION ++ && pnote->namedata[4] == '2') ++ ++ version_2_seen; + pnote ++; + } + +@@ -1911,41 +1930,45 @@ merge_gnu_build_notes (bfd * abfd, asect + /* Check that the notes are valid. */ + if (remain != 0) + { +- err = _("corrupt GNU build attribute notes: data at end"); ++ err = _("corrupt GNU build attribute notes: excess data at end"); ++ goto done; ++ } ++ ++ if (version_1_seen == 0 && version_2_seen == 0) ++ { ++ err = _("bad GNU build attribute notes: no known versions detected"); + goto done; + } + +- if (version_notes_seen == 0) ++ if (version_1_seen > 0 && version_2_seen > 0) + { +- err = _("bad GNU build attribute notes: no version note"); ++ err = _("bad GNU build attribute notes: multiple different versions"); + goto done; + } + + /* Merging is only needed if there is more than one version note... */ +- if (version_notes_seen == 1) ++ if (version_1_seen == 1 || version_2_seen == 1) + goto done; + ++ attribute_type_byte = version_1_seen ? 1 : 3; ++ val_start = attribute_type_byte + 1; ++ + /* The first note should be the first version note. */ +- if (pnotes[0].namedata[1] != GNU_BUILD_ATTRIBUTE_VERSION) ++ if (pnotes[0].namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION) + { + err = _("bad GNU build attribute notes: first note not version note"); + goto done; + } + +- if (pnotes[0].namedata[0] != GNU_BUILD_ATTRIBUTE_TYPE_STRING +- || pnotes[0].namedata[2] != '1') +- { +- err = _("bad GNU build attribute notes: version note not v1"); +- goto done; +- } +- + /* 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. +- 4. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and ++ 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 +@@ -1968,8 +1991,63 @@ merge_gnu_build_notes (bfd * abfd, asect + prev_open = back; + + if (back->type == pnote->type +- && back->namedata[1] == pnote->namedata[1]) ++ && back->namedata[attribute_type_byte] == pnote->namedata[attribute_type_byte]) + { ++ if (back->namedata[attribute_type_byte] == GNU_BUILD_ATTRIBUTE_STACK_SIZE) ++ { ++ 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->namesz - val_start, ++ name = (unsigned char *) pnote->namedata + val_start; ++ bytes--;) ++ { ++ byte = (* name ++) & 0xff; ++ note_val |= byte << shift; ++ shift += 8; ++ } ++ ++ for (shift = 0, back_val = 0, ++ bytes = back->namesz - val_start, ++ name = (unsigned char *) back->namedata + val_start; ++ bytes--;) ++ { ++ byte = (* name ++) & 0xff; ++ back_val |= byte << shift; ++ shift += 8; ++ } ++ ++ back_val += note_val; ++ if (num_bytes (back_val) >= back->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->namedata + val_start; ++ while (name < (unsigned char *) back->namedata + back->namesz) ++ { ++ byte = back_val & 0xff; ++ * name ++ = byte; ++ if (back_val == 0) ++ break; ++ back_val >>= 8; ++ } ++ ++ duplicate_found = TRUE; ++ pnote->type = 0; ++ break; ++ } ++ + if (back->namesz == pnote->namesz + && memcmp (back->namedata, pnote->namedata, back->namesz) == 0) + { +@@ -1979,11 +2057,12 @@ merge_gnu_build_notes (bfd * abfd, asect + } + + /* If we have found an attribute match then stop searching backwards. */ +- if (! ISPRINT (back->namedata[1]) +- || strcmp (back->namedata + 2, pnote->namedata + 2) == 0) ++ if (! ISPRINT (back->namedata[attribute_type_byte]) ++ /* Names are NUL terminated, so this is safe. */ ++ || strcmp (back->namedata + val_start, pnote->namedata + val_start) == 0) + { + /* Since we are keeping this note we must check to see if its +- description refers back to an earlier OPEN note. If so ++ description refers back to an earlier OPEN version note. If so + then we must make sure that version note is also preserved. */ + if (pnote->descsz == 0 + && prev_open != NULL +@@ -2067,15 +2146,18 @@ merge_gnu_build_notes (bfd * abfd, asect + + if (relcount > 0) + { +- arelent ** rel; ++ arelent **rel = relpp; + +- for (rel = relpp; rel < relpp + relcount; rel ++) +- if ((* rel)->howto == NULL) ++ while (rel < relpp + relcount) ++ if ((*rel)->howto != NULL) ++ rel++; ++ else + { + /* Delete eliminated relocs. + FIXME: There are better ways to do this. */ +- memmove (rel, rel + 1, ((relcount - (rel - relpp)) - 1) * sizeof (* rel)); +- relcount --; ++ memmove (rel, rel + 1, ++ ((relcount - (rel - relpp)) - 1) * sizeof (*rel)); ++ relcount--; + } + bfd_set_reloc (abfd, sec, relpp, relcount); + } +diff -rup binutils.orig/binutils/readelf.c binutils-2.28/binutils/readelf.c +--- binutils.orig/binutils/readelf.c 2017-06-28 15:28:35.868153969 +0100 ++++ binutils-2.28/binutils/readelf.c 2017-06-28 15:35:01.500695487 +0100 +@@ -16517,7 +16517,7 @@ print_gnu_build_attribute_name (Elf_Inte + const char * expected_types; + const char * name = pnote->namedata; + const char * text; +- int left; ++ signed int left; + + if (name == NULL || pnote->namesz < 2) + { +@@ -16526,6 +16526,16 @@ print_gnu_build_attribute_name (Elf_Inte + return FALSE; + } + ++ left = 20; ++ ++ /* Version 2 of the spec adds a "GA" prefix to the name field. */ ++ if (name[0] == 'G' && name[1] == 'A') ++ { ++ printf ("GA"); ++ name += 2; ++ left -= 2; ++ } ++ + switch ((name_type = * name)) + { + case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC: +@@ -16533,6 +16543,7 @@ print_gnu_build_attribute_name (Elf_Inte + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE: + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE: + printf ("%c", * name); ++ left --; + break; + default: + error (_("unrecognised attribute type in name field: %d\n"), name_type); +@@ -16540,7 +16551,6 @@ print_gnu_build_attribute_name (Elf_Inte + return FALSE; + } + +- left = 19; + ++ name; + text = NULL; + +@@ -16586,7 +16596,6 @@ print_gnu_build_attribute_name (Elf_Inte + expected_types = bool_expected; + ++ name; + break; +- + default: + if (ISPRINT (* name)) + { +@@ -16601,6 +16610,7 @@ print_gnu_build_attribute_name (Elf_Inte + else + { + static char tmpbuf [128]; ++ + error (_("unrecognised byte in name field: %d\n"), * name); + sprintf (tmpbuf, _(""), * name); + text = tmpbuf; +@@ -16611,10 +16621,7 @@ print_gnu_build_attribute_name (Elf_Inte + } + + if (text) +- { +- printf ("%s", text); +- left -= strlen (text); +- } ++ left -= printf ("%s", text); + + if (strchr (expected_types, name_type) == NULL) + warn (_("attribute does not have an expected type (%c)\n"), name_type); +@@ -16634,10 +16641,10 @@ print_gnu_build_attribute_name (Elf_Inte + { + case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC: + { +- unsigned int bytes; +- unsigned long long val = 0; +- unsigned int shift = 0; +- char * decoded = NULL; ++ unsigned int bytes; ++ unsigned long long val = 0; ++ unsigned int shift = 0; ++ char * decoded = NULL; + + bytes = pnote->namesz - (name - pnote->namedata); + if (bytes > 0) +@@ -16735,6 +16742,7 @@ print_gnu_build_attribute_name (Elf_Inte + I.E. the value of namesz for the name "FSF" is 4. + + If the value of namesz is zero, there is no name present. */ ++ + static int + process_note (Elf_Internal_Note * pnote, + FILE * file) +--- fred/binutils/objcopy.c 2017-06-28 15:39:09.627826773 +0100 ++++ binutils-2.28/binutils/objcopy.c 2017-06-28 15:39:29.117601441 +0100 +@@ -1844,6 +1844,22 @@ copy_unknown_object (bfd *ibfd, bfd *obf + 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; ++} ++ + /* Merge the notes on SEC, removing redundant entries. + Returns the new, smaller size of the section upon success. */ + diff --git a/binutils.spec b/binutils.spec index da9a4b3..59c2010 100644 --- a/binutils.spec +++ b/binutils.spec @@ -43,7 +43,7 @@ Summary: A GNU collection of binary utilities Name: %{?cross}binutils%{?_with_debug:-debug} Version: 2.28 -Release: 9%{?dist} +Release: 10%{?dist} License: GPLv3+ Group: Development/Tools URL: http://sources.redhat.com/binutils @@ -602,6 +602,9 @@ exit 0 %endif # %{isnative} %changelog +* Wed Jun 28 2017 Nick Clifton 2.28-10 +- Update support for GNU Build Attribute notes to include version 2 notes. + * Thu Jun 15 2017 Nick Clifton 2.28-9 - Update patch to fix AArch64 copy reloc generation. (#1452170)