aboutsummaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2018-04-26 15:12:42 +0100
committerNick Clifton <nickc@redhat.com>2018-04-26 15:12:42 +0100
commit0df8ad28f0f727fab3a696d6c98b9a8a77ee1024 (patch)
tree1c4194b04e789a81a0a82af590a12105209fd05b /gas/write.c
parentaa684341294a9125c528041f81d17c488bed5552 (diff)
downloadgdb-0df8ad28f0f727fab3a696d6c98b9a8a77ee1024.zip
gdb-0df8ad28f0f727fab3a696d6c98b9a8a77ee1024.tar.gz
gdb-0df8ad28f0f727fab3a696d6c98b9a8a77ee1024.tar.bz2
Extend the assembler so that it can automatically generate GNU Build attribute notes if none are present in the input files.
gas * as.c (flag_generate_build_notes): New variable. (show_usage): Add entry for --generate-missing-build-notes. (parse_args): Parse --generate-missing-build-notes. * as.h: Export flag_generate_build_notes. * symbols.c (save_symbol_name): Ensure that the name parameter is not NULL. * write.c (create_obj_attrs_section): Reformat. (create_note_reloc): New function - creates a relocation for a field in a GNU Build attribute note. (maybe_generate_build_notes): New function - created GNU Build attribute notes if none are present in the output file. (write_object_file): Call maybe_generate_build_notes. * configure.ac (--enable-generate-build-notes): New option. * NEWS: Announce the new feature. * doc/as.textinfo: Document the new option. * config.in: Regenerate. * configure: Regenerate. binutils* readelf.c (is_32bit_abs_reloc): Support R_PARISC_DIR32 as a 32-bit absolute reloc for the HPPA target. * testsuite/binutils-all/note-5.d: New test. * testsuite/binutils-all/note-5.s: Source file for new test. * testsuite/binutils-all/objcopy.exp: Run new test.
Diffstat (limited to 'gas/write.c')
-rw-r--r--gas/write.c213
1 files changed, 197 insertions, 16 deletions
diff --git a/gas/write.c b/gas/write.c
index 2d0bbe4..b902bf8 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1867,25 +1867,200 @@ create_obj_attrs_section (void)
const char *name;
size = bfd_elf_obj_attr_size (stdoutput);
- if (size)
+ if (size == 0)
+ return;
+
+ name = get_elf_backend_data (stdoutput)->obj_attrs_section;
+ if (!name)
+ name = ".gnu.attributes";
+ s = subseg_new (name, 0);
+ elf_section_type (s)
+ = get_elf_backend_data (stdoutput)->obj_attrs_section_type;
+ bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
+ frag_now_fix ();
+ p = frag_more (size);
+ bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
+
+ subsegs_finish_section (s);
+ relax_segment (seg_info (s)->frchainP->frch_root, s, 0);
+ size_seg (stdoutput, s, NULL);
+}
+
+#include "struc-symbol.h"
+
+/* Create a relocation against an entry in a GNU Build attribute section. */
+
+static void
+create_note_reloc (segT sec,
+ symbolS * sym,
+ bfd_size_type offset,
+ int reloc_type,
+ bfd_vma addend,
+ char * note)
+{
+ struct reloc_list * reloc;
+
+ reloc = XNEW (struct reloc_list);
+
+ /* We create a .b type reloc as resolve_reloc_expr_symbols() has already been called. */
+ reloc->u.b.sec = sec;
+ reloc->u.b.s = sym->bsym;
+ reloc->u.b.r.sym_ptr_ptr = & reloc->u.b.s;
+ reloc->u.b.r.address = offset;
+ reloc->u.b.r.addend = addend;
+ reloc->u.b.r.howto = bfd_reloc_type_lookup (stdoutput, reloc_type);
+
+ if (reloc->u.b.r.howto == NULL)
{
- name = get_elf_backend_data (stdoutput)->obj_attrs_section;
- if (!name)
- name = ".gnu.attributes";
- s = subseg_new (name, 0);
- elf_section_type (s)
- = get_elf_backend_data (stdoutput)->obj_attrs_section_type;
- bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
- frag_now_fix ();
- p = frag_more (size);
- bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
-
- subsegs_finish_section (s);
- relax_segment (seg_info (s)->frchainP->frch_root, s, 0);
- size_seg (stdoutput, s, NULL);
+ as_bad (_("unable to create reloc for build note"));
+ return;
+ }
+
+ reloc->file = N_("<gnu build note>");
+ reloc->line = 0;
+
+ reloc->next = reloc_list;
+ reloc_list = reloc;
+
+ /* For REL relocs, store the addend in the section. */
+ if (! sec->use_rela_p
+ /* The SH target is a special case that uses RELA relocs
+ but still stores the addend in the word being relocated. */
+ || strstr (bfd_get_target (stdoutput), "-sh") != NULL)
+ {
+ if (target_big_endian)
+ {
+ if (bfd_arch_bits_per_address (stdoutput) <= 32)
+ note[offset + 3] = addend;
+ else
+ note[offset + 7] = addend;
+ }
+ else
+ note[offset] = addend;
}
}
-#endif
+
+static void
+maybe_generate_build_notes (void)
+{
+ segT sec;
+ char * note;
+ offsetT note_size;
+ offsetT desc_size;
+ offsetT desc2_offset;
+ int desc_reloc;
+ symbolS * sym;
+
+ if (! flag_generate_build_notes
+ || bfd_get_section_by_name (stdoutput,
+ GNU_BUILD_ATTRS_SECTION_NAME) != NULL)
+ return;
+
+ /* Create a GNU Build Attribute section. */
+ sec = subseg_new (GNU_BUILD_ATTRS_SECTION_NAME, FALSE);
+ elf_section_type (sec) = SHT_NOTE;
+ bfd_set_section_flags (stdoutput, sec,
+ SEC_READONLY | SEC_HAS_CONTENTS | SEC_DATA);
+ bfd_set_section_alignment (stdoutput, sec, 2);
+
+ /* Create a version note. */
+ if (bfd_arch_bits_per_address (stdoutput) <= 32)
+ {
+ note_size = 28;
+ desc_size = 8; /* Two 4-byte offsets. */
+ desc2_offset = 24;
+
+ /* FIXME: The BFD backend for the CRX target does not support the
+ BFD_RELOC_32, even though it really should. Likewise for the
+ CR16 target. So we have special case code here... */
+ if (strstr (bfd_get_target (stdoutput), "-crx") != NULL)
+ desc_reloc = BFD_RELOC_CRX_NUM32;
+ else if (strstr (bfd_get_target (stdoutput), "-cr16") != NULL)
+ desc_reloc = BFD_RELOC_CR16_NUM32;
+ else
+ desc_reloc = BFD_RELOC_32;
+ }
+ else
+ {
+ note_size = 36;
+ desc_size = 16; /* Two 8-byte offsets. */
+ desc2_offset = 28;
+ /* FIXME: The BFD backend for the IA64 target does not support the
+ BFD_RELOC_64, even though it really should. The HPPA backend
+ has a similar issue, although it does not support BFD_RELOCs at
+ all! So we have special case code to handle these targets. */
+ if (strstr (bfd_get_target (stdoutput), "-ia64") != NULL)
+ desc_reloc = target_big_endian ? BFD_RELOC_IA64_DIR32MSB : BFD_RELOC_IA64_DIR32LSB;
+ else if (strstr (bfd_get_target (stdoutput), "-hppa") != NULL)
+ desc_reloc = 80; /* R_PARISC_DIR64. */
+ else
+ desc_reloc = BFD_RELOC_64;
+ }
+
+ frag_now_fix ();
+ note = frag_more (note_size);
+ memset (note, 0, note_size);
+
+ if (target_big_endian)
+ {
+ note[3] = 8; /* strlen (name) + 1. */
+ note[7] = desc_size; /* Two 8-byte offsets. */
+ note[10] = NT_GNU_BUILD_ATTRIBUTE_OPEN >> 8;
+ note[11] = NT_GNU_BUILD_ATTRIBUTE_OPEN & 0xff;
+ }
+ else
+ {
+ note[0] = 8; /* strlen (name) + 1. */
+ note[4] = desc_size; /* Two 8-byte offsets. */
+ note[8] = NT_GNU_BUILD_ATTRIBUTE_OPEN & 0xff;
+ note[9] = NT_GNU_BUILD_ATTRIBUTE_OPEN >> 8;
+ }
+
+ /* The a1 version number indicates that this note was
+ generated by the assembler and not the gcc annobin plugin. */
+ memcpy (note + 12, "GA$3a1", 8);
+
+ /* Find the first code section symbol. */
+ for (sym = symbol_rootP; sym != NULL; sym = sym->sy_next)
+ if (sym->bsym != NULL
+ && sym->bsym->flags & BSF_SECTION_SYM
+ && sym->bsym->section != NULL
+ && sym->bsym->section->flags & SEC_CODE)
+ {
+ /* Found one - now create a relocation against this symbol. */
+ create_note_reloc (sec, sym, 20, desc_reloc, 0, note);
+ break;
+ }
+
+ /* Find the last code section symbol. */
+ if (sym)
+ {
+ for (sym = symbol_lastP; sym != NULL; sym = sym->sy_previous)
+ if (sym->bsym != NULL
+ && sym->bsym->flags & BSF_SECTION_SYM
+ && sym->bsym->section != NULL
+ && sym->bsym->section->flags & SEC_CODE)
+ {
+ /* Create a relocation against the end of this symbol. */
+ create_note_reloc (sec, sym, desc2_offset, desc_reloc,
+ bfd_get_section_size (sym->bsym->section),
+ note);
+ break;
+ }
+ }
+ /* else - if we were unable to find any code section symbols then
+ probably there is no code in the output. So leaving the start
+ and end values as zero in the note is OK. */
+
+ /* FIXME: Maybe add a note recording the assembler command line and version ? */
+
+ /* Install the note(s) into the section. */
+ bfd_set_section_contents (stdoutput, sec, (bfd_byte *) note, 0, note_size);
+ subsegs_finish_section (sec);
+ relax_segment (seg_info (sec)->frchainP->frch_root, sec, 0);
+ size_seg (stdoutput, sec, NULL);
+}
+#endif /* OBJ_ELF */
/* Write the object file. */
@@ -2097,6 +2272,11 @@ write_object_file (void)
resolve_local_symbol_values ();
resolve_reloc_expr_symbols ();
+#ifdef OBJ_ELF
+ if (IS_ELF)
+ maybe_generate_build_notes ();
+#endif
+
PROGRESS (1);
#ifdef tc_frob_file_before_adjust
@@ -2273,6 +2453,7 @@ write_object_file (void)
#ifdef obj_coff_generate_pdata
obj_coff_generate_pdata ();
#endif
+
bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
#ifdef tc_frob_file_after_relocs