| /* SPARC-specific support for 64-bit ELF |
| Copyright (C) 1993-2024 Free Software Foundation, Inc. |
| |
| This file is part of BFD, the Binary File Descriptor library. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| MA 02110-1301, USA. */ |
| |
| #include "sysdep.h" |
| #include <limits.h> |
| #include "bfd.h" |
| #include "libbfd.h" |
| #include "elf-bfd.h" |
| #include "elf/sparc.h" |
| #include "opcode/sparc.h" |
| #include "elfxx-sparc.h" |
| |
| /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ |
| #define MINUS_ONE (~ (bfd_vma) 0) |
| |
| /* Due to the way how we handle R_SPARC_OLO10, each entry in a SHT_RELA |
| section can represent up to two relocs, we must tell the user to allocate |
| more space. */ |
| |
| static long |
| elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) |
| { |
| size_t count, raw; |
| |
| count = sec->reloc_count; |
| if (count >= LONG_MAX / 2 / sizeof (arelent *) |
| || _bfd_mul_overflow (count, sizeof (Elf64_External_Rela), &raw)) |
| { |
| bfd_set_error (bfd_error_file_too_big); |
| return -1; |
| } |
| if (!bfd_write_p (abfd)) |
| { |
| ufile_ptr filesize = bfd_get_file_size (abfd); |
| if (filesize != 0 && raw > filesize) |
| { |
| bfd_set_error (bfd_error_file_truncated); |
| return -1; |
| } |
| } |
| return (count * 2 + 1) * sizeof (arelent *); |
| } |
| |
| static long |
| elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd) |
| { |
| long ret = _bfd_elf_get_dynamic_reloc_upper_bound (abfd); |
| if (ret > LONG_MAX / 2) |
| { |
| bfd_set_error (bfd_error_file_too_big); |
| ret = -1; |
| } |
| else if (ret > 0) |
| ret *= 2; |
| return ret; |
| } |
| |
| /* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of |
| them. We cannot use generic elf routines for this, because R_SPARC_OLO10 |
| has secondary addend in ELF64_R_TYPE_DATA. We handle it as two relocations |
| for the same location, R_SPARC_LO10 and R_SPARC_13. */ |
| |
| static bool |
| elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect, |
| Elf_Internal_Shdr *rel_hdr, |
| asymbol **symbols, bool dynamic) |
| { |
| void * allocated = NULL; |
| bfd_byte *native_relocs; |
| arelent *relent; |
| unsigned int i; |
| int entsize; |
| bfd_size_type count; |
| arelent *relents; |
| |
| if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0) |
| return false; |
| allocated = _bfd_malloc_and_read (abfd, rel_hdr->sh_size, rel_hdr->sh_size); |
| if (allocated == NULL) |
| return false; |
| |
| native_relocs = (bfd_byte *) allocated; |
| |
| relents = asect->relocation + canon_reloc_count (asect); |
| |
| entsize = rel_hdr->sh_entsize; |
| BFD_ASSERT (entsize == sizeof (Elf64_External_Rela)); |
| |
| count = rel_hdr->sh_size / entsize; |
| |
| for (i = 0, relent = relents; i < count; |
| i++, relent++, native_relocs += entsize) |
| { |
| Elf_Internal_Rela rela; |
| unsigned int r_type; |
| |
| bfd_elf64_swap_reloca_in (abfd, native_relocs, &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 || dynamic) |
| relent->address = rela.r_offset; |
| else |
| relent->address = rela.r_offset - asect->vma; |
| |
| if (ELF64_R_SYM (rela.r_info) == STN_UNDEF) |
| relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
| else if (/* PR 17512: file: 996185f8. */ |
| ELF64_R_SYM (rela.r_info) > (dynamic |
| ? bfd_get_dynamic_symcount (abfd) |
| : bfd_get_symcount (abfd))) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB(%pA): relocation %d has invalid symbol index %ld"), |
| abfd, asect, i, (long) ELF64_R_SYM (rela.r_info)); |
| bfd_set_error (bfd_error_bad_value); |
| relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
| } |
| else |
| { |
| asymbol **ps, *s; |
| |
| ps = symbols + ELF64_R_SYM (rela.r_info) - 1; |
| s = *ps; |
| |
| /* Canonicalize ELF section symbols. FIXME: Why? */ |
| if ((s->flags & BSF_SECTION_SYM) == 0) |
| relent->sym_ptr_ptr = ps; |
| else |
| relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; |
| } |
| |
| relent->addend = rela.r_addend; |
| |
| r_type = ELF64_R_TYPE_ID (rela.r_info); |
| if (r_type == R_SPARC_OLO10) |
| { |
| relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, R_SPARC_LO10); |
| relent[1].address = relent->address; |
| relent++; |
| relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
| relent->addend = ELF64_R_TYPE_DATA (rela.r_info); |
| relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, R_SPARC_13); |
| } |
| else |
| { |
| relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, r_type); |
| if (relent->howto == NULL) |
| goto error_return; |
| } |
| } |
| |
| canon_reloc_count (asect) += relent - relents; |
| |
| free (allocated); |
| return true; |
| |
| error_return: |
| free (allocated); |
| return false; |
| } |
| |
| /* Read in and swap the external relocs. */ |
| |
| static bool |
| elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect, |
| asymbol **symbols, bool dynamic) |
| { |
| struct bfd_elf_section_data * const d = elf_section_data (asect); |
| Elf_Internal_Shdr *rel_hdr; |
| Elf_Internal_Shdr *rel_hdr2; |
| bfd_size_type amt; |
| |
| if (asect->relocation != NULL) |
| return true; |
| |
| if (! dynamic) |
| { |
| if ((asect->flags & SEC_RELOC) == 0 |
| || asect->reloc_count == 0) |
| return true; |
| |
| rel_hdr = d->rel.hdr; |
| rel_hdr2 = d->rela.hdr; |
| |
| BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset) |
| || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); |
| } |
| else |
| { |
| /* Note that ASECT->RELOC_COUNT tends not to be accurate in this |
| case because relocations against this section may use the |
| dynamic symbol table, and in that case bfd_section_from_shdr |
| in elf.c does not update the RELOC_COUNT. */ |
| if (asect->size == 0) |
| return true; |
| |
| rel_hdr = &d->this_hdr; |
| asect->reloc_count = NUM_SHDR_ENTRIES (rel_hdr); |
| rel_hdr2 = NULL; |
| } |
| |
| amt = asect->reloc_count; |
| amt *= 2 * sizeof (arelent); |
| asect->relocation = (arelent *) bfd_alloc (abfd, amt); |
| if (asect->relocation == NULL) |
| return false; |
| |
| /* The elf64_sparc_slurp_one_reloc_table routine increments |
| canon_reloc_count. */ |
| canon_reloc_count (asect) = 0; |
| |
| if (rel_hdr |
| && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols, |
| dynamic)) |
| return false; |
| |
| if (rel_hdr2 |
| && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols, |
| dynamic)) |
| return false; |
| |
| return true; |
| } |
| |
| /* Canonicalize the relocs. */ |
| |
| static long |
| elf64_sparc_canonicalize_reloc (bfd *abfd, sec_ptr section, |
| arelent **relptr, asymbol **symbols) |
| { |
| arelent *tblptr; |
| unsigned int i; |
| const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
| |
| if (! bed->s->slurp_reloc_table (abfd, section, symbols, false)) |
| return -1; |
| |
| tblptr = section->relocation; |
| for (i = 0; i < canon_reloc_count (section); i++) |
| *relptr++ = tblptr++; |
| |
| *relptr = NULL; |
| |
| return canon_reloc_count (section); |
| } |
| |
| |
| /* Canonicalize the dynamic relocation entries. Note that we return |
| the dynamic relocations as a single block, although they are |
| actually associated with particular sections; the interface, which |
| was designed for SunOS style shared libraries, expects that there |
| is only one set of dynamic relocs. Any section that was actually |
| installed in the BFD, and has type SHT_REL or SHT_RELA, and uses |
| the dynamic symbol table, is considered to be a dynamic reloc |
| section. */ |
| |
| static long |
| elf64_sparc_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage, |
| asymbol **syms) |
| { |
| asection *s; |
| long ret; |
| |
| if (elf_dynsymtab (abfd) == 0) |
| { |
| bfd_set_error (bfd_error_invalid_operation); |
| return -1; |
| } |
| |
| ret = 0; |
| for (s = abfd->sections; s != NULL; s = s->next) |
| { |
| if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) |
| && (elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) |
| { |
| arelent *p; |
| long count, i; |
| |
| if (! elf64_sparc_slurp_reloc_table (abfd, s, syms, true)) |
| return -1; |
| count = canon_reloc_count (s); |
| p = s->relocation; |
| for (i = 0; i < count; i++) |
| *storage++ = p++; |
| ret += count; |
| } |
| } |
| |
| *storage = NULL; |
| |
| return ret; |
| } |
| |
| /* Install a new set of internal relocs. */ |
| |
| static void |
| elf64_sparc_set_reloc (bfd *abfd ATTRIBUTE_UNUSED, |
| asection *asect, |
| arelent **location, |
| unsigned int count) |
| { |
| asect->orelocation = location; |
| canon_reloc_count (asect) = count; |
| if (count != 0) |
| asect->flags |= SEC_RELOC; |
| else |
| asect->flags &= ~SEC_RELOC; |
| } |
| |
| /* Write out the relocs. */ |
| |
| static void |
| elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data) |
| { |
| bool *failedp = (bool *) data; |
| Elf_Internal_Shdr *rela_hdr; |
| bfd_vma addr_offset; |
| Elf64_External_Rela *outbound_relocas, *src_rela; |
| unsigned int idx, count; |
| asymbol *last_sym = 0; |
| int last_sym_idx = 0; |
| |
| /* If we have already failed, don't do anything. */ |
| if (*failedp) |
| return; |
| |
| if ((sec->flags & SEC_RELOC) == 0) |
| return; |
| |
| /* The linker backend writes the relocs out itself, and sets the |
| reloc_count field to zero to inhibit writing them here. Also, |
| sometimes the SEC_RELOC flag gets set even when there aren't any |
| relocs. */ |
| if (canon_reloc_count (sec) == 0) |
| return; |
| |
| /* We can combine two relocs that refer to the same address |
| into R_SPARC_OLO10 if first one is R_SPARC_LO10 and the |
| latter is R_SPARC_13 with no associated symbol. */ |
| count = 0; |
| for (idx = 0; idx < canon_reloc_count (sec); idx++) |
| { |
| bfd_vma addr; |
| |
| ++count; |
| |
| addr = sec->orelocation[idx]->address; |
| if (sec->orelocation[idx]->howto->type == R_SPARC_LO10 |
| && idx < canon_reloc_count (sec) - 1) |
| { |
| arelent *r = sec->orelocation[idx + 1]; |
| |
| if (r->howto->type == R_SPARC_13 |
| && r->address == addr |
| && bfd_is_abs_section ((*r->sym_ptr_ptr)->section) |
| && (*r->sym_ptr_ptr)->value == 0) |
| ++idx; |
| } |
| } |
| |
| rela_hdr = elf_section_data (sec)->rela.hdr; |
| |
| rela_hdr->sh_size = rela_hdr->sh_entsize * count; |
| rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size); |
| if (rela_hdr->contents == NULL) |
| { |
| *failedp = true; |
| return; |
| } |
| |
| /* Figure out whether the relocations are RELA or REL relocations. */ |
| if (rela_hdr->sh_type != SHT_RELA) |
| abort (); |
| |
| /* 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; |
| |
| /* orelocation has the data, reloc_count has the count... */ |
| outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents; |
| src_rela = outbound_relocas; |
| |
| for (idx = 0; idx < canon_reloc_count (sec); idx++) |
| { |
| Elf_Internal_Rela dst_rela; |
| arelent *ptr; |
| asymbol *sym; |
| int n; |
| |
| ptr = sec->orelocation[idx]; |
| sym = *ptr->sym_ptr_ptr; |
| if (sym == last_sym) |
| n = last_sym_idx; |
| else if (bfd_is_abs_section (sym->section) && sym->value == 0) |
| n = STN_UNDEF; |
| else |
| { |
| last_sym = sym; |
| n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); |
| if (n < 0) |
| { |
| *failedp = true; |
| return; |
| } |
| 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)) |
| { |
| *failedp = true; |
| return; |
| } |
| |
| if (ptr->howto->type == R_SPARC_LO10 |
| && idx < canon_reloc_count (sec) - 1) |
| { |
| arelent *r = sec->orelocation[idx + 1]; |
| |
| if (r->howto->type == R_SPARC_13 |
| && r->address == ptr->address |
| && bfd_is_abs_section ((*r->sym_ptr_ptr)->section) |
| && (*r->sym_ptr_ptr)->value == 0) |
| { |
| idx++; |
| dst_rela.r_info |
| = ELF64_R_INFO (n, ELF64_R_TYPE_INFO (r->addend, |
| R_SPARC_OLO10)); |
| } |
| else |
| dst_rela.r_info = ELF64_R_INFO (n, R_SPARC_LO10); |
| } |
| else |
| dst_rela.r_info = ELF64_R_INFO (n, ptr->howto->type); |
| |
| dst_rela.r_offset = ptr->address + addr_offset; |
| dst_rela.r_addend = ptr->addend; |
| |
| bfd_elf64_swap_reloca_out (abfd, &dst_rela, (bfd_byte *) src_rela); |
| ++src_rela; |
| } |
| } |
| |
| /* Hook called by the linker routine which adds symbols from an object |
| file. We use it for STT_REGISTER symbols. */ |
| |
| static bool |
| elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, |
| Elf_Internal_Sym *sym, const char **namep, |
| flagword *flagsp ATTRIBUTE_UNUSED, |
| asection **secp ATTRIBUTE_UNUSED, |
| bfd_vma *valp ATTRIBUTE_UNUSED) |
| { |
| static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" }; |
| |
| if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER) |
| { |
| int reg; |
| struct _bfd_sparc_elf_app_reg *p; |
| |
| reg = (int)sym->st_value; |
| switch (reg & ~1) |
| { |
| case 2: reg -= 2; break; |
| case 6: reg -= 4; break; |
| default: |
| _bfd_error_handler |
| (_("%pB: only registers %%g[2367] can be declared using STT_REGISTER"), |
| abfd); |
| return false; |
| } |
| |
| if (info->output_bfd->xvec != abfd->xvec |
| || (abfd->flags & DYNAMIC) != 0) |
| { |
| /* STT_REGISTER only works when linking an elf64_sparc object. |
| If STT_REGISTER comes from a dynamic object, don't put it into |
| the output bfd. The dynamic linker will recheck it. */ |
| *namep = NULL; |
| return true; |
| } |
| |
| p = _bfd_sparc_elf_hash_table(info)->app_regs + reg; |
| |
| if (p->name != NULL && strcmp (p->name, *namep)) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("register %%g%d used incompatibly: %s in %pB," |
| " previously %s in %pB"), |
| (int) sym->st_value, **namep ? *namep : "#scratch", abfd, |
| *p->name ? p->name : "#scratch", p->abfd); |
| return false; |
| } |
| |
| if (p->name == NULL) |
| { |
| if (**namep) |
| { |
| struct elf_link_hash_entry *h; |
| |
| h = (struct elf_link_hash_entry *) |
| bfd_link_hash_lookup (info->hash, *namep, false, false, false); |
| |
| if (h != NULL) |
| { |
| unsigned char type = h->type; |
| |
| if (type > STT_FUNC) |
| type = 0; |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("symbol `%s' has differing types: REGISTER in %pB," |
| " previously %s in %pB"), |
| *namep, abfd, stt_types[type], p->abfd); |
| return false; |
| } |
| |
| p->name = bfd_hash_allocate (&info->hash->table, |
| strlen (*namep) + 1); |
| if (!p->name) |
| return false; |
| |
| strcpy (p->name, *namep); |
| } |
| else |
| p->name = ""; |
| p->bind = ELF_ST_BIND (sym->st_info); |
| p->abfd = abfd; |
| p->shndx = sym->st_shndx; |
| } |
| else |
| { |
| if (p->bind == STB_WEAK |
| && ELF_ST_BIND (sym->st_info) == STB_GLOBAL) |
| { |
| p->bind = STB_GLOBAL; |
| p->abfd = abfd; |
| } |
| } |
| *namep = NULL; |
| return true; |
| } |
| else if (*namep && **namep |
| && info->output_bfd->xvec == abfd->xvec) |
| { |
| int i; |
| struct _bfd_sparc_elf_app_reg *p; |
| |
| p = _bfd_sparc_elf_hash_table(info)->app_regs; |
| for (i = 0; i < 4; i++, p++) |
| if (p->name != NULL && ! strcmp (p->name, *namep)) |
| { |
| unsigned char type = ELF_ST_TYPE (sym->st_info); |
| |
| if (type > STT_FUNC) |
| type = 0; |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("Symbol `%s' has differing types: %s in %pB," |
| " previously REGISTER in %pB"), |
| *namep, stt_types[type], abfd, p->abfd); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /* This function takes care of emitting STT_REGISTER symbols |
| which we cannot easily keep in the symbol hash table. */ |
| |
| static bool |
| elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED, |
| struct bfd_link_info *info, |
| void * flaginfo, |
| int (*func) (void *, const char *, |
| Elf_Internal_Sym *, |
| asection *, |
| struct elf_link_hash_entry *)) |
| { |
| int reg; |
| struct _bfd_sparc_elf_app_reg *app_regs = |
| _bfd_sparc_elf_hash_table(info)->app_regs; |
| Elf_Internal_Sym sym; |
| |
| for (reg = 0; reg < 4; reg++) |
| if (app_regs [reg].name != NULL) |
| { |
| if (info->strip == strip_some |
| && bfd_hash_lookup (info->keep_hash, |
| app_regs [reg].name, |
| false, false) == NULL) |
| continue; |
| |
| sym.st_value = reg < 2 ? reg + 2 : reg + 4; |
| sym.st_size = 0; |
| sym.st_other = 0; |
| sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER); |
| sym.st_shndx = app_regs [reg].shndx; |
| sym.st_target_internal = 0; |
| if ((*func) (flaginfo, app_regs [reg].name, &sym, |
| sym.st_shndx == SHN_ABS |
| ? bfd_abs_section_ptr : bfd_und_section_ptr, |
| NULL) != 1) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static int |
| elf64_sparc_get_symbol_type (Elf_Internal_Sym *elf_sym, int type) |
| { |
| if (ELF_ST_TYPE (elf_sym->st_info) == STT_REGISTER) |
| return STT_REGISTER; |
| else |
| return type; |
| } |
| |
| /* A STB_GLOBAL,STT_REGISTER symbol should be BSF_GLOBAL |
| even in SHN_UNDEF section. */ |
| |
| static void |
| elf64_sparc_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym) |
| { |
| elf_symbol_type *elfsym; |
| |
| elfsym = (elf_symbol_type *) asym; |
| if (elfsym->internal_elf_sym.st_info |
| == ELF_ST_INFO (STB_GLOBAL, STT_REGISTER)) |
| { |
| asym->flags |= BSF_GLOBAL; |
| } |
| } |
| |
| |
| /* Functions for dealing with the e_flags field. */ |
| |
| /* Merge backend specific data from an object file to the output |
| object file when linking. */ |
| |
| static bool |
| elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) |
| { |
| bfd *obfd = info->output_bfd; |
| bool error; |
| flagword new_flags, old_flags; |
| int new_mm, old_mm; |
| |
| if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
| || bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
| return true; |
| |
| new_flags = elf_elfheader (ibfd)->e_flags; |
| old_flags = elf_elfheader (obfd)->e_flags; |
| |
| if (!elf_flags_init (obfd)) /* First call, no flags set */ |
| { |
| elf_flags_init (obfd) = true; |
| elf_elfheader (obfd)->e_flags = new_flags; |
| } |
| |
| else if (new_flags == old_flags) /* Compatible flags are ok */ |
| ; |
| |
| else /* Incompatible flags */ |
| { |
| error = false; |
| |
| #define EF_SPARC_ISA_EXTENSIONS \ |
| (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3 | EF_SPARC_HAL_R1) |
| |
| if ((ibfd->flags & DYNAMIC) != 0) |
| { |
| /* We don't want dynamic objects memory ordering and |
| architecture to have any role. That's what dynamic linker |
| should do. */ |
| new_flags &= ~(EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS); |
| new_flags |= (old_flags |
| & (EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS)); |
| } |
| else |
| { |
| /* Choose the highest architecture requirements. */ |
| old_flags |= (new_flags & EF_SPARC_ISA_EXTENSIONS); |
| new_flags |= (old_flags & EF_SPARC_ISA_EXTENSIONS); |
| if ((old_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3)) |
| && (old_flags & EF_SPARC_HAL_R1)) |
| { |
| error = true; |
| _bfd_error_handler |
| (_("%pB: linking UltraSPARC specific with HAL specific code"), |
| ibfd); |
| } |
| /* Choose the most restrictive memory ordering. */ |
| old_mm = (old_flags & EF_SPARCV9_MM); |
| new_mm = (new_flags & EF_SPARCV9_MM); |
| old_flags &= ~EF_SPARCV9_MM; |
| new_flags &= ~EF_SPARCV9_MM; |
| if (new_mm < old_mm) |
| old_mm = new_mm; |
| old_flags |= old_mm; |
| new_flags |= old_mm; |
| } |
| |
| /* Warn about any other mismatches */ |
| if (new_flags != old_flags) |
| { |
| error = true; |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: uses different e_flags (%#x) fields than previous modules (%#x)"), |
| ibfd, new_flags, old_flags); |
| } |
| |
| elf_elfheader (obfd)->e_flags = old_flags; |
| |
| if (error) |
| { |
| bfd_set_error (bfd_error_bad_value); |
| return false; |
| } |
| } |
| return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info); |
| } |
| |
| /* MARCO: Set the correct entry size for the .stab section. */ |
| |
| static bool |
| elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, |
| Elf_Internal_Shdr *hdr ATTRIBUTE_UNUSED, |
| asection *sec) |
| { |
| const char *name; |
| |
| name = bfd_section_name (sec); |
| |
| if (strcmp (name, ".stab") == 0) |
| { |
| /* Even in the 64bit case the stab entries are only 12 bytes long. */ |
| elf_section_data (sec)->this_hdr.sh_entsize = 12; |
| } |
| |
| return true; |
| } |
| |
| /* Print a STT_REGISTER symbol to file FILE. */ |
| |
| static const char * |
| elf64_sparc_print_symbol_all (bfd *abfd ATTRIBUTE_UNUSED, void * filep, |
| asymbol *symbol) |
| { |
| FILE *file = (FILE *) filep; |
| int reg, type; |
| |
| if (ELF_ST_TYPE (((elf_symbol_type *) symbol)->internal_elf_sym.st_info) |
| != STT_REGISTER) |
| return NULL; |
| |
| reg = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; |
| type = symbol->flags; |
| fprintf (file, "REG_%c%c%11s%c%c R", "GOLI" [reg / 8], '0' + (reg & 7), "", |
| ((type & BSF_LOCAL) |
| ? (type & BSF_GLOBAL) ? '!' : 'l' |
| : (type & BSF_GLOBAL) ? 'g' : ' '), |
| (type & BSF_WEAK) ? 'w' : ' '); |
| if (symbol->name == NULL || symbol->name [0] == '\0') |
| return "#scratch"; |
| else |
| return symbol->name; |
| } |
| |
| /* Used to decide how to sort relocs in an optimal manner for the |
| dynamic linker, before writing them out. */ |
| |
| static enum elf_reloc_type_class |
| elf64_sparc_reloc_type_class (const struct bfd_link_info *info, |
| const asection *rel_sec ATTRIBUTE_UNUSED, |
| const Elf_Internal_Rela *rela) |
| { |
| bfd *abfd = info->output_bfd; |
| const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
| struct _bfd_sparc_elf_link_hash_table *htab |
| = _bfd_sparc_elf_hash_table (info); |
| BFD_ASSERT (htab != NULL); |
| |
| if (htab->elf.dynsym != NULL |
| && htab->elf.dynsym->contents != NULL) |
| { |
| /* Check relocation against STT_GNU_IFUNC symbol if there are |
| dynamic symbols. */ |
| unsigned long r_symndx = htab->r_symndx (rela->r_info); |
| if (r_symndx != STN_UNDEF) |
| { |
| Elf_Internal_Sym sym; |
| if (!bed->s->swap_symbol_in (abfd, |
| (htab->elf.dynsym->contents |
| + r_symndx * bed->s->sizeof_sym), |
| 0, &sym)) |
| abort (); |
| |
| if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) |
| return reloc_class_ifunc; |
| } |
| } |
| |
| switch ((int) ELF64_R_TYPE (rela->r_info)) |
| { |
| case R_SPARC_IRELATIVE: |
| return reloc_class_ifunc; |
| case R_SPARC_RELATIVE: |
| return reloc_class_relative; |
| case R_SPARC_JMP_SLOT: |
| return reloc_class_plt; |
| case R_SPARC_COPY: |
| return reloc_class_copy; |
| default: |
| return reloc_class_normal; |
| } |
| } |
| |
| /* Relocations in the 64 bit SPARC ELF ABI are more complex than in |
| standard ELF, because R_SPARC_OLO10 has secondary addend in |
| ELF64_R_TYPE_DATA field. This structure is used to redirect the |
| relocation handling routines. */ |
| |
| const struct elf_size_info elf64_sparc_size_info = |
| { |
| sizeof (Elf64_External_Ehdr), |
| sizeof (Elf64_External_Phdr), |
| sizeof (Elf64_External_Shdr), |
| sizeof (Elf64_External_Rel), |
| sizeof (Elf64_External_Rela), |
| sizeof (Elf64_External_Sym), |
| sizeof (Elf64_External_Dyn), |
| sizeof (Elf_External_Note), |
| 4, /* hash-table entry size. */ |
| /* Internal relocations per external relocations. |
| For link purposes we use just 1 internal per |
| 1 external, for assembly and slurp symbol table |
| we use 2. */ |
| 1, |
| 64, /* arch_size. */ |
| 3, /* log_file_align. */ |
| ELFCLASS64, |
| EV_CURRENT, |
| bfd_elf64_write_out_phdrs, |
| bfd_elf64_write_shdrs_and_ehdr, |
| bfd_elf64_checksum_contents, |
| elf64_sparc_write_relocs, |
| bfd_elf64_swap_symbol_in, |
| bfd_elf64_swap_symbol_out, |
| elf64_sparc_slurp_reloc_table, |
| bfd_elf64_slurp_symbol_table, |
| bfd_elf64_swap_dyn_in, |
| bfd_elf64_swap_dyn_out, |
| bfd_elf64_swap_reloc_in, |
| bfd_elf64_swap_reloc_out, |
| bfd_elf64_swap_reloca_in, |
| bfd_elf64_swap_reloca_out |
| }; |
| |
| #define TARGET_BIG_SYM sparc_elf64_vec |
| #define TARGET_BIG_NAME "elf64-sparc" |
| #define ELF_ARCH bfd_arch_sparc |
| #define ELF_MAXPAGESIZE 0x100000 |
| #define ELF_COMMONPAGESIZE 0x2000 |
| |
| /* This is the official ABI value. */ |
| #define ELF_MACHINE_CODE EM_SPARCV9 |
| |
| /* This is the value that we used before the ABI was released. */ |
| #define ELF_MACHINE_ALT1 EM_OLD_SPARCV9 |
| |
| #define elf_backend_reloc_type_class \ |
| elf64_sparc_reloc_type_class |
| #define bfd_elf64_get_reloc_upper_bound \ |
| elf64_sparc_get_reloc_upper_bound |
| #define bfd_elf64_get_dynamic_reloc_upper_bound \ |
| elf64_sparc_get_dynamic_reloc_upper_bound |
| #define bfd_elf64_canonicalize_reloc \ |
| elf64_sparc_canonicalize_reloc |
| #define bfd_elf64_canonicalize_dynamic_reloc \ |
| elf64_sparc_canonicalize_dynamic_reloc |
| #define bfd_elf64_set_reloc \ |
| elf64_sparc_set_reloc |
| #define elf_backend_add_symbol_hook \ |
| elf64_sparc_add_symbol_hook |
| #define elf_backend_get_symbol_type \ |
| elf64_sparc_get_symbol_type |
| #define elf_backend_symbol_processing \ |
| elf64_sparc_symbol_processing |
| #define elf_backend_print_symbol_all \ |
| elf64_sparc_print_symbol_all |
| #define elf_backend_output_arch_syms \ |
| elf64_sparc_output_arch_syms |
| #define bfd_elf64_bfd_merge_private_bfd_data \ |
| elf64_sparc_merge_private_bfd_data |
| #define elf_backend_fake_sections \ |
| elf64_sparc_fake_sections |
| #define elf_backend_size_info \ |
| elf64_sparc_size_info |
| |
| #define elf_backend_plt_sym_val \ |
| _bfd_sparc_elf_plt_sym_val |
| #define bfd_elf64_bfd_link_hash_table_create \ |
| _bfd_sparc_elf_link_hash_table_create |
| #define elf_info_to_howto \ |
| _bfd_sparc_elf_info_to_howto |
| #define elf_backend_copy_indirect_symbol \ |
| _bfd_sparc_elf_copy_indirect_symbol |
| #define bfd_elf64_bfd_reloc_type_lookup \ |
| _bfd_sparc_elf_reloc_type_lookup |
| #define bfd_elf64_bfd_reloc_name_lookup \ |
| _bfd_sparc_elf_reloc_name_lookup |
| #define bfd_elf64_bfd_relax_section \ |
| _bfd_sparc_elf_relax_section |
| #define bfd_elf64_new_section_hook \ |
| _bfd_sparc_elf_new_section_hook |
| |
| #define elf_backend_create_dynamic_sections \ |
| _bfd_sparc_elf_create_dynamic_sections |
| #define elf_backend_relocs_compatible \ |
| _bfd_elf_relocs_compatible |
| #define elf_backend_check_relocs \ |
| _bfd_sparc_elf_check_relocs |
| #define elf_backend_adjust_dynamic_symbol \ |
| _bfd_sparc_elf_adjust_dynamic_symbol |
| #define elf_backend_omit_section_dynsym \ |
| _bfd_sparc_elf_omit_section_dynsym |
| #define elf_backend_late_size_sections \ |
| _bfd_sparc_elf_late_size_sections |
| #define elf_backend_relocate_section \ |
| _bfd_sparc_elf_relocate_section |
| #define elf_backend_finish_dynamic_symbol \ |
| _bfd_sparc_elf_finish_dynamic_symbol |
| #define elf_backend_finish_dynamic_sections \ |
| _bfd_sparc_elf_finish_dynamic_sections |
| #define elf_backend_fixup_symbol \ |
| _bfd_sparc_elf_fixup_symbol |
| |
| #define bfd_elf64_mkobject \ |
| _bfd_sparc_elf_mkobject |
| #define elf_backend_object_p \ |
| _bfd_sparc_elf_object_p |
| #define elf_backend_gc_mark_hook \ |
| _bfd_sparc_elf_gc_mark_hook |
| #define elf_backend_init_index_section \ |
| _bfd_elf_init_1_index_section |
| |
| #define elf_backend_can_gc_sections 1 |
| #define elf_backend_can_refcount 1 |
| #define elf_backend_want_got_plt 0 |
| #define elf_backend_plt_readonly 0 |
| #define elf_backend_want_plt_sym 1 |
| #define elf_backend_got_header_size 8 |
| #define elf_backend_want_dynrelro 1 |
| #define elf_backend_rela_normal 1 |
| |
| /* Section 5.2.4 of the ABI specifies a 256-byte boundary for the table. */ |
| #define elf_backend_plt_alignment 8 |
| |
| #include "elf64-target.h" |
| |
| /* FreeBSD support */ |
| #undef TARGET_BIG_SYM |
| #define TARGET_BIG_SYM sparc_elf64_fbsd_vec |
| #undef TARGET_BIG_NAME |
| #define TARGET_BIG_NAME "elf64-sparc-freebsd" |
| #undef ELF_OSABI |
| #define ELF_OSABI ELFOSABI_FREEBSD |
| |
| #undef elf64_bed |
| #define elf64_bed elf64_sparc_fbsd_bed |
| |
| #include "elf64-target.h" |
| |
| /* Solaris 2. */ |
| |
| #undef TARGET_BIG_SYM |
| #define TARGET_BIG_SYM sparc_elf64_sol2_vec |
| #undef TARGET_BIG_NAME |
| #define TARGET_BIG_NAME "elf64-sparc-sol2" |
| |
| /* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE |
| objects won't be recognized. */ |
| #undef ELF_OSABI |
| |
| #undef elf64_bed |
| #define elf64_bed elf64_sparc_sol2_bed |
| |
| /* The 64-bit static TLS arena size is rounded to the nearest 16-byte |
| boundary. */ |
| #undef elf_backend_static_tls_alignment |
| #define elf_backend_static_tls_alignment 16 |
| |
| #undef elf_backend_strtab_flags |
| #define elf_backend_strtab_flags SHF_STRINGS |
| |
| static bool |
| elf64_sparc_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED, |
| bfd *obfd ATTRIBUTE_UNUSED, |
| const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED, |
| Elf_Internal_Shdr *osection ATTRIBUTE_UNUSED) |
| { |
| /* PR 19938: FIXME: Need to add code for setting the sh_info |
| and sh_link fields of Solaris specific section types. */ |
| return false; |
| } |
| |
| #undef elf_backend_copy_special_section_fields |
| #define elf_backend_copy_special_section_fields elf64_sparc_copy_solaris_special_section_fields |
| |
| #include "elf64-target.h" |
| |
| #undef elf_backend_strtab_flags |
| #undef elf_backend_copy_special_section_fields |