diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9f1a9424ae..1cfff1c04d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,36 @@ +2020-03-05 Nick Clifton + + * elf-bfd.h (struct elf_backend_data): Add new fields: + init_secondary_reloc_section, slurp_secondary_reloc_section, + write_secondary_reloc_section. + (_bfd_elf_init_secondary_reloc_section): Prototype. + (_bfd_elf_slurp_secondary_reloc_section): Prototype. + (_bfd_elf_write_secondary_reloc_section): Prototype. + * elf.c ( bfd_section_from_shdr): Invoke the new + init_secondary_reloc_section backend function, if defined, when a + second reloc section is encountered. + (swap_out_syms): Invoke the new symbol_section_index function, if + defined, when computing the section index of an OS/PROC specific + symbol. + (_bfd_elf_init_secondary_reloc_section): New function. + (_bfd_elf_slurp_secondary_reloc_section): New function. + (_bfd_elf_write_secondary_reloc_section): New function. + (_bfd_elf_copy_special_section_fields): New function. + * elfcode.h (elf_write_relocs): Invoke the new + write_secondary_relocs function, if defined, in order to emit + secondary relocs. + (elf_slurp_reloc_table): Invoke the new slurp_secondary_relocs + function, if defined, in order to read in secondary relocs. + * elfxx-target.h (elf_backend_copy_special_section_fields): + Provide a non-NULL default definition. + (elf_backend_init_secondary_reloc_section): Likewise. + (elf_backend_slurp_secondary_reloc_section): Likewise. + (elf_backend_write_secondary_reloc_section): Likewise. + (struct elf_backend_data elfNN_bed): Add initialisers for the new + fields. + * configure.ac (score_elf32_[bl]e_vec): Add elf64.lo + * configure: Regenerate. + 2020-03-05 Alan Modra * archive64.c (_bfd_archive_64_bit_slurp_armap): Check parsed_size diff --git a/bfd/configure b/bfd/configure index cca67ee108..30b80fe27c 100755 --- a/bfd/configure +++ b/bfd/configure @@ -14887,8 +14887,8 @@ do rx_elf32_linux_le_vec) tb="$tb elf32-rx.lo elf32.lo $elf" ;; s390_elf32_vec) tb="$tb elf32-s390.lo elf32.lo $elf" ;; s390_elf64_vec) tb="$tb elf64-s390.lo elf64.lo $elf"; target_size=64 ;; - score_elf32_be_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;; - score_elf32_le_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;; + score_elf32_be_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo elf64.lo $elf"; want64=true; target_size=64 ;; + score_elf32_le_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo elf64.lo $elf"; want64=true; target_size=64 ;; sh_coff_vec) tb="$tb coff-sh.lo $coff" ;; sh_coff_le_vec) tb="$tb coff-sh.lo $coff" ;; sh_coff_small_vec) tb="$tb coff-sh.lo $coff" ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index af4d4b8c13..3426ded094 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -619,8 +619,8 @@ do rx_elf32_linux_le_vec) tb="$tb elf32-rx.lo elf32.lo $elf" ;; s390_elf32_vec) tb="$tb elf32-s390.lo elf32.lo $elf" ;; s390_elf64_vec) tb="$tb elf64-s390.lo elf64.lo $elf"; target_size=64 ;; - score_elf32_be_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;; - score_elf32_le_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;; + score_elf32_be_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo elf64.lo $elf"; want64=true; target_size=64 ;; + score_elf32_le_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo elf64.lo $elf"; want64=true; target_size=64 ;; sh_coff_vec) tb="$tb coff-sh.lo $coff" ;; sh_coff_le_vec) tb="$tb coff-sh.lo $coff" ;; sh_coff_small_vec) tb="$tb coff-sh.lo $coff" ;; diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 38a9aa0601..5d9e0fedcd 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1509,6 +1509,16 @@ struct elf_backend_data emitted symbol. If not defined, the value is left unchanged. */ unsigned int (*symbol_section_index) (bfd *, elf_symbol_type *); + /* Called when a section has extra reloc sections. */ + bfd_boolean (*init_secondary_reloc_section) (bfd *, Elf_Internal_Shdr *, + const char *, unsigned int); + + /* Called when after loading the normal relocs for a section. */ + bfd_boolean (*slurp_secondary_relocs) (bfd *, asection *, asymbol **); + + /* Called after writing the normal relocs for a section. */ + bfd_boolean (*write_secondary_relocs) (bfd *, asection *); + /* This is non-zero if static TLS segments require a special alignment. */ unsigned static_tls_alignment; @@ -2838,6 +2848,19 @@ extern bfd_vma elf32_r_sym (bfd_vma); extern bfd_boolean is_debuginfo_file (bfd *); + +extern bfd_boolean _bfd_elf_init_secondary_reloc_section + (bfd *, Elf_Internal_Shdr *, const char *, unsigned int); +extern bfd_boolean _bfd_elf_slurp_secondary_reloc_section + (bfd *, asection *, asymbol **); +extern bfd_boolean _bfd_elf_copy_special_section_fields + (const bfd *, bfd *, const Elf_Internal_Shdr *, Elf_Internal_Shdr *); +extern bfd_boolean _bfd_elf_write_secondary_reloc_section + (bfd *, asection *); +extern unsigned int _bfd_elf_symbol_section_index + (bfd *, elf_symbol_type *); + + /* Large common section. */ extern asection _bfd_elf_large_com_section; diff --git a/bfd/elf.c b/bfd/elf.c index c4d6718aaa..747d120101 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1607,7 +1607,7 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) /* Final attempt. Call the backend copy function with a NULL input section. */ if (bed->elf_backend_copy_special_section_fields != NULL) - bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader); + (void) bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader); } } @@ -2458,13 +2458,17 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) sections. */ if (*p_hdr != NULL) { - _bfd_error_handler - /* xgettext:c-format */ - (_("%pB: warning: multiple relocation sections for section %pA \ -found - ignoring all but the first"), - abfd, target_sect); + if (bed->init_secondary_reloc_section == NULL + || ! bed->init_secondary_reloc_section (abfd, hdr, name, shindex)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: warning: secondary relocation section '%s' for section %pA found - ignoring"), + abfd, name, target_sect); + } goto success; } + hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2)); if (hdr2 == NULL) goto fail; @@ -12308,3 +12312,364 @@ _bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec, size = 1; return size; } + +/* Set to non-zero to enable some debug messages. */ +#define DEBUG_SECONDARY_RELOCS 0 + +/* An internal-to-the-bfd-library only section type + used to indicate a cached secondary reloc section. */ +#define SHT_SECONDARY_RELOC (SHT_LOOS + SHT_RELA) + +/* Create a BFD section to hold a secondary reloc section. */ + +bfd_boolean +_bfd_elf_init_secondary_reloc_section (bfd * abfd, + Elf_Internal_Shdr *hdr, + const char * name, + unsigned int shindex) +{ + /* We only support RELA secondary relocs. */ + if (hdr->sh_type != SHT_RELA) + return FALSE; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "secondary reloc section %s encountered\n", name); +#endif + hdr->sh_type = SHT_SECONDARY_RELOC; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); +} + +/* Read in any secondary relocs associated with SEC. */ + +bfd_boolean +_bfd_elf_slurp_secondary_reloc_section (bfd * abfd, + asection * sec, + asymbol ** symbols) +{ + const struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + asection * relsec; + bfd_boolean result = TRUE; + bfd_vma (*r_sym) (bfd_vma); + +#if BFD_DEFAULT_TARGET_SIZE > 32 + if (bfd_arch_bits_per_address (abfd) != 32) + r_sym = elf64_r_sym; + else +#endif + r_sym = elf32_r_sym; + + /* Discover if there are any secondary reloc sections + associated with SEC. */ + for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next) + { + Elf_Internal_Shdr * hdr = & elf_section_data (relsec)->this_hdr; + + if (hdr->sh_type == SHT_SECONDARY_RELOC + && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx) + { + bfd_byte * native_relocs; + bfd_byte * native_reloc; + arelent * internal_relocs; + arelent * internal_reloc; + unsigned int i; + unsigned int entsize; + unsigned int symcount; + unsigned int reloc_count; + size_t amt; + + if (ebd->elf_info_to_howto == NULL) + return FALSE; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "read secondary relocs for %s from %s\n", + sec->name, relsec->name); +#endif + entsize = hdr->sh_entsize; + + native_relocs = bfd_malloc (hdr->sh_size); + if (native_relocs == NULL) + { + result = FALSE; + continue; + } + + reloc_count = NUM_SHDR_ENTRIES (hdr); + if (_bfd_mul_overflow (reloc_count, sizeof (arelent), & amt)) + { + bfd_set_error (bfd_error_file_too_big); + result = FALSE; + continue; + } + + internal_relocs = (arelent *) bfd_alloc (abfd, amt); + if (internal_relocs == NULL) + { + free (native_relocs); + result = FALSE; + continue; + } + + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread (native_relocs, hdr->sh_size, abfd) + != hdr->sh_size)) + { + free (native_relocs); + free (internal_relocs); + result = FALSE; + continue; + } + + symcount = bfd_get_symcount (abfd); + + for (i = 0, internal_reloc = internal_relocs, + native_reloc = native_relocs; + i < reloc_count; + i++, internal_reloc++, native_reloc += entsize) + { + bfd_boolean res; + Elf_Internal_Rela rela; + + ebd->s->swap_reloca_in (abfd, native_reloc, & rela); + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a normal BFD reloc is always section relative, + and the address of a dynamic reloc is absolute.. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + internal_reloc->address = rela.r_offset; + else + internal_reloc->address = rela.r_offset - sec->vma; + + if (r_sym (rela.r_info) == STN_UNDEF) + { + /* FIXME: This and the error case below mean that we + have a symbol on relocs that is not elf_symbol_type. */ + internal_reloc->sym_ptr_ptr = + bfd_abs_section_ptr->symbol_ptr_ptr; + } + else if (r_sym (rela.r_info) > symcount) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): relocation %d has invalid symbol index %ld"), + abfd, sec, i, (long) r_sym (rela.r_info)); + bfd_set_error (bfd_error_bad_value); + internal_reloc->sym_ptr_ptr = + bfd_abs_section_ptr->symbol_ptr_ptr; + result = FALSE; + } + else + { + asymbol **ps; + + ps = symbols + r_sym (rela.r_info) - 1; + + internal_reloc->sym_ptr_ptr = ps; + /* Make sure that this symbol is not removed by strip. */ + (*ps)->flags |= BSF_KEEP; + } + + internal_reloc->addend = rela.r_addend; + + res = ebd->elf_info_to_howto (abfd, internal_reloc, & rela); + if (! res || internal_reloc->howto == NULL) + { +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "there is no howto associated with reloc %lx\n", + rela.r_info); +#endif + result = FALSE; + } + } + + free (native_relocs); + /* Store the internal relocs. */ + elf_section_data (relsec)->sec_info = internal_relocs; + } + } + + return result; +} + +/* Set the ELF section header fields of an output secondary reloc section. */ + +bfd_boolean +_bfd_elf_copy_special_section_fields (const bfd * ibfd ATTRIBUTE_UNUSED, + bfd * obfd ATTRIBUTE_UNUSED, + const Elf_Internal_Shdr * isection, + Elf_Internal_Shdr * osection) +{ + asection * isec; + asection * osec; + + if (isection == NULL) + return FALSE; + + if (isection->sh_type != SHT_SECONDARY_RELOC) + return TRUE; + + isec = isection->bfd_section; + if (isec == NULL) + return FALSE; + + osec = osection->bfd_section; + if (osec == NULL) + return FALSE; + + BFD_ASSERT (elf_section_data (osec)->sec_info == NULL); + elf_section_data (osec)->sec_info = elf_section_data (isec)->sec_info; + osection->sh_type = SHT_RELA; + osection->sh_link = elf_onesymtab (obfd); + if (osection->sh_link == 0) + { + /* There is no symbol table - we are hosed... */ + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): link section cannot be set because the output file does not have a symbol table"), + obfd, osec); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Find the output section that corresponds to the isection's sh_info link. */ + BFD_ASSERT (isection->sh_info > 0 + && isection->sh_info < elf_numsections (ibfd)); + isection = elf_elfsections (ibfd)[isection->sh_info]; + + BFD_ASSERT (isection != NULL); + BFD_ASSERT (isection->bfd_section != NULL); + BFD_ASSERT (isection->bfd_section->output_section != NULL); + osection->sh_info = + elf_section_data (isection->bfd_section->output_section)->this_idx; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "update header of %s, sh_link = %u, sh_info = %u\n", + osec->name, osection->sh_link, osection->sh_info); +#endif + + return TRUE; +} + +/* Write out a secondary reloc section. */ + +bfd_boolean +_bfd_elf_write_secondary_reloc_section (bfd *abfd, asection *sec) +{ + const struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + bfd_vma addr_offset; + asection * relsec; + bfd_vma (*r_info) (bfd_vma, bfd_vma); + +#if BFD_DEFAULT_TARGET_SIZE > 32 + if (bfd_arch_bits_per_address (abfd) != 32) + r_info = elf64_r_info; + else +#endif + r_info = elf32_r_info; + + if (sec == NULL) + return FALSE; + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + addr_offset = 0; + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + addr_offset = sec->vma; + + /* Discover if there are any secondary reloc sections + associated with SEC. */ + for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next) + { + const struct bfd_elf_section_data * const esd = elf_section_data (relsec); + Elf_Internal_Shdr * const hdr = (Elf_Internal_Shdr *) & esd->this_hdr; + + if (hdr->sh_type == SHT_RELA + && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx) + { + asymbol * last_sym; + int last_sym_idx; + unsigned int reloc_count; + unsigned int idx; + arelent * src_irel; + bfd_byte * dst_rela; + + BFD_ASSERT (hdr->contents == NULL); + + reloc_count = hdr->sh_size / hdr->sh_entsize; + BFD_ASSERT (reloc_count > 0); + + hdr->contents = bfd_alloc (abfd, hdr->sh_size); + if (hdr->contents == NULL) + continue; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "write %u secondary relocs for %s from %s\n", + reloc_count, sec->name, relsec->name); +#endif + last_sym = NULL; + last_sym_idx = 0; + dst_rela = hdr->contents; + src_irel = (arelent *) esd->sec_info; + BFD_ASSERT (src_irel != NULL); + + for (idx = 0; idx < reloc_count; idx++, dst_rela += hdr->sh_entsize) + { + Elf_Internal_Rela src_rela; + arelent *ptr; + asymbol *sym; + int n; + + ptr = src_irel + idx; + sym = *ptr->sym_ptr_ptr; + + if (sym == last_sym) + n = last_sym_idx; + else + { + last_sym = sym; + n = _bfd_elf_symbol_from_bfd_symbol (abfd, & sym); + if (n < 0) + { +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "failed to find symbol %s whilst rewriting relocs\n", + sym->name); +#endif + /* FIXME: Signal failure somehow. */ + n = 0; + } + last_sym_idx = n; + } + + if ((*ptr->sym_ptr_ptr)->the_bfd != NULL + && (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec + && ! _bfd_elf_validate_reloc (abfd, ptr)) + { +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "symbol %s is not in the output bfd\n", + sym->name); +#endif + /* FIXME: Signal failure somehow. */ + n = 0; + } + + if (ptr->howto == NULL) + { +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "reloc for symbol %s does not have a howto associated with it\n", + sym->name); +#endif + /* FIXME: Signal failure somehow. */ + n = 0; + } + + src_rela.r_offset = ptr->address + addr_offset; + src_rela.r_info = r_info (n, ptr->howto->type); + src_rela.r_addend = ptr->addend; + ebd->s->swap_reloca_out (abfd, &src_rela, dst_rela); + } + } + } + + return TRUE; +} diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 600abfe836..18a6dac64e 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -869,6 +869,7 @@ elf_object_p (bfd *abfd) void elf_write_relocs (bfd *abfd, asection *sec, void *data) { + const struct elf_backend_data * const bed = get_elf_backend_data (abfd); bfd_boolean *failedp = (bfd_boolean *) data; Elf_Internal_Shdr *rela_hdr; bfd_vma addr_offset; @@ -985,6 +986,13 @@ elf_write_relocs (bfd *abfd, asection *sec, void *data) src_rela.r_addend = ptr->addend; (*swap_out) (abfd, &src_rela, dst_rela); } + + if (bed->write_secondary_relocs != NULL) + if (! bed->write_secondary_relocs (abfd, sec)) + { + *failedp = TRUE; + return; + } } /* Write out the program headers. */ @@ -1292,7 +1300,10 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) { /* This symbol is in a section for which we did not create a BFD section. Just use bfd_abs_section, - although it is wrong. FIXME. */ + although it is wrong. FIXME. Note - there is + code in elf.c:swap_out_syms that calls + symbol_section_index() in the elf backend for + cases like this. */ sym->symbol.section = bfd_abs_section_ptr; } } @@ -1517,6 +1528,7 @@ elf_slurp_reloc_table (bfd *abfd, asymbol **symbols, bfd_boolean dynamic) { + const struct elf_backend_data * const bed = get_elf_backend_data (abfd); struct bfd_elf_section_data * const d = elf_section_data (asect); Elf_Internal_Shdr *rel_hdr; Elf_Internal_Shdr *rel_hdr2; @@ -1584,6 +1596,10 @@ elf_slurp_reloc_table (bfd *abfd, symbols, dynamic)) return FALSE; + if (bed->slurp_secondary_relocs != NULL + && ! bed->slurp_secondary_relocs (abfd, asect, symbols)) + return FALSE; + asect->relocation = relents; return TRUE; } diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index e9cac0a535..1ae17f45ee 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -758,7 +758,7 @@ #endif #ifndef elf_backend_copy_special_section_fields -#define elf_backend_copy_special_section_fields NULL +#define elf_backend_copy_special_section_fields _bfd_elf_copy_special_section_fields #endif #ifndef elf_backend_compact_eh_encoding @@ -766,7 +766,19 @@ #endif #ifndef elf_backend_cant_unwind_opcode -#define elf_backend_cant_unwind_opcode 0 +#define elf_backend_cant_unwind_opcode NULL +#endif + +#ifndef elf_backend_init_secondary_reloc_section +#define elf_backend_init_secondary_reloc_section _bfd_elf_init_secondary_reloc_section +#endif + +#ifndef elf_backend_slurp_secondary_reloc_section +#define elf_backend_slurp_secondary_reloc_section _bfd_elf_slurp_secondary_reloc_section +#endif + +#ifndef elf_backend_write_secondary_reloc_section +#define elf_backend_write_secondary_reloc_section _bfd_elf_write_secondary_reloc_section #endif #ifndef elf_backend_symbol_section_index @@ -900,6 +912,9 @@ static struct elf_backend_data elfNN_bed = elf_backend_compact_eh_encoding, elf_backend_cant_unwind_opcode, elf_backend_symbol_section_index, + elf_backend_init_secondary_reloc_section, + elf_backend_slurp_secondary_reloc_section, + elf_backend_write_secondary_reloc_section, elf_backend_static_tls_alignment, elf_backend_stack_align, elf_backend_strtab_flags,