- s = bfd_get_section_by_name (dynobj, ".interp");
- BFD_ASSERT (s != NULL);
- s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
- s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
- }
- }
- else
- {
- /* We may have created entries in the .rela.got section.
- However, if we are not creating the dynamic sections, we will
- not actually use these entries. Reset the size of .rela.got,
- which will cause it to get stripped from the output file
- below. */
- s = bfd_get_section_by_name (dynobj, ".rela.got");
- if (s != NULL)
- s->_raw_size = 0;
- }
-
- /* The check_relocs and adjust_dynamic_symbol entry points have
- determined the sizes of the various dynamic sections. Allocate
- memory for them. */
- relplt = false;
- for (s = dynobj->sections; s != NULL; s = s->next)
- {
- const char *name;
- boolean strip;
-
- if ((s->flags & SEC_LINKER_CREATED) == 0)
- continue;
-
- /* It's OK to base decisions on the section name, because none
- of the dynobj section names depend upon the input files. */
- name = bfd_get_section_name (dynobj, s);
-
- strip = false;
-
- if (strncmp (name, ".rela", 5) == 0)
- {
- if (s->_raw_size == 0)
- {
- /* If we don't need this section, strip it from the
- output file. This is to handle .rela.bss and
- .rel.plt. We must create it in
- create_dynamic_sections, because it must be created
- before the linker maps input sections to output
- sections. The linker does that before
- adjust_dynamic_symbol is called, and it is that
- function which decides whether anything needs to go
- into these sections. */
- strip = true;
- }
- else
- {
- if (strcmp (name, ".rela.plt") == 0)
- relplt = true;
-
- /* We use the reloc_count field as a counter if we need
- to copy relocs into the output file. */
- s->reloc_count = 0;
- }
- }
- else if (strcmp (name, ".plt") != 0
- && strncmp (name, ".got", 4) != 0)
- {
- /* It's not one of our sections, so don't allocate space. */
- continue;
- }
-
- if (strip)
- {
- _bfd_strip_section_from_output (info, s);
- continue;
- }
-
- /* Allocate memory for the section contents. Zero the memory
- for the benefit of .rela.plt, which has 4 unused entries
- at the beginning, and we don't want garbage. */
- s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
- if (s->contents == NULL && s->_raw_size != 0)
- return false;
- }
-
- if (elf_hash_table (info)->dynamic_sections_created)
- {
- /* Add some entries to the .dynamic section. We fill in the
- values later, in sparc64_elf_finish_dynamic_sections, but we
- must add the entries now so that we get the correct size for
- the .dynamic section. The DT_DEBUG entry is filled in by the
- dynamic linker and used by the debugger. */
-#define add_dynamic_entry(TAG, VAL) \
- bfd_elf64_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
-
- int reg;
- struct sparc64_elf_app_reg * app_regs;
- struct elf_strtab_hash *dynstr;
- struct elf_link_hash_table *eht = elf_hash_table (info);
-
- if (!info->shared)
- {
- if (!add_dynamic_entry (DT_DEBUG, 0))
- return false;
- }
-
- if (relplt)
- {
- if (!add_dynamic_entry (DT_PLTGOT, 0)
- || !add_dynamic_entry (DT_PLTRELSZ, 0)
- || !add_dynamic_entry (DT_PLTREL, DT_RELA)
- || !add_dynamic_entry (DT_JMPREL, 0))
- return false;
- }
-
- if (!add_dynamic_entry (DT_RELA, 0)
- || !add_dynamic_entry (DT_RELASZ, 0)
- || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
- return false;
-
- if (info->flags & DF_TEXTREL)
- {
- if (!add_dynamic_entry (DT_TEXTREL, 0))
- return false;
- }
-
- /* Add dynamic STT_REGISTER symbols and corresponding DT_SPARC_REGISTER
- entries if needed. */
- app_regs = sparc64_elf_hash_table (info)->app_regs;
- dynstr = eht->dynstr;
-
- for (reg = 0; reg < 4; reg++)
- if (app_regs [reg].name != NULL)
- {
- struct elf_link_local_dynamic_entry *entry, *e;
-
- if (!add_dynamic_entry (DT_SPARC_REGISTER, 0))
- return false;
-
- entry = (struct elf_link_local_dynamic_entry *)
- bfd_hash_allocate (&info->hash->table, sizeof (*entry));
- if (entry == NULL)
- return false;
-
- /* We cheat here a little bit: the symbol will not be local, so we
- put it at the end of the dynlocal linked list. We will fix it
- later on, as we have to fix other fields anyway. */
- entry->isym.st_value = reg < 2 ? reg + 2 : reg + 4;
- entry->isym.st_size = 0;
- if (*app_regs [reg].name != '\0')
- entry->isym.st_name
- = _bfd_elf_strtab_add (dynstr, app_regs[reg].name, false);
- else
- entry->isym.st_name = 0;
- entry->isym.st_other = 0;
- entry->isym.st_info = ELF_ST_INFO (app_regs [reg].bind,
- STT_REGISTER);
- entry->isym.st_shndx = app_regs [reg].shndx;
- entry->next = NULL;
- entry->input_bfd = output_bfd;
- entry->input_indx = -1;
-
- if (eht->dynlocal == NULL)
- eht->dynlocal = entry;
- else
- {
- for (e = eht->dynlocal; e->next; e = e->next)
- ;
- e->next = entry;
- }
- eht->dynsymcount++;
- }
- }
-#undef add_dynamic_entry
-
- return true;
-}
-\f
-#define SET_SEC_DO_RELAX(section) do { elf_section_data(section)->tdata = (void *)1; } while (0)
-#define SEC_DO_RELAX(section) (elf_section_data(section)->tdata == (void *)1)
-
-static boolean
-sparc64_elf_relax_section (abfd, section, link_info, again)
- bfd *abfd ATTRIBUTE_UNUSED;
- asection *section ATTRIBUTE_UNUSED;
- struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
- boolean *again;
-{
- *again = false;
- SET_SEC_DO_RELAX (section);
- return true;
-}
-\f
-/* Relocate a SPARC64 ELF section. */
-
-static boolean
-sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
- contents, relocs, local_syms, local_sections)
- bfd *output_bfd;
- struct bfd_link_info *info;
- bfd *input_bfd;
- asection *input_section;
- bfd_byte *contents;
- Elf_Internal_Rela *relocs;
- Elf_Internal_Sym *local_syms;
- asection **local_sections;
-{
- bfd *dynobj;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- bfd_vma *local_got_offsets;
- bfd_vma got_base;
- asection *sgot;
- asection *splt;
- asection *sreloc;
- Elf_Internal_Rela *rel;
- Elf_Internal_Rela *relend;
-
- dynobj = elf_hash_table (info)->dynobj;
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (input_bfd);
- local_got_offsets = elf_local_got_offsets (input_bfd);
-
- if (elf_hash_table(info)->hgot == NULL)
- got_base = 0;
- else
- got_base = elf_hash_table (info)->hgot->root.u.def.value;
-
- sgot = splt = sreloc = NULL;
-
- rel = relocs;
- relend = relocs + NUM_SHDR_ENTRIES (& elf_section_data (input_section)->rel_hdr);
- for (; rel < relend; rel++)
- {
- int r_type;
- reloc_howto_type *howto;
- unsigned long r_symndx;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
- asection *sec;
- bfd_vma relocation;
- bfd_reloc_status_type r;
-
- r_type = ELF64_R_TYPE_ID (rel->r_info);
- if (r_type < 0 || r_type >= (int) R_SPARC_max_std)
- {
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
- howto = sparc64_elf_howto_table + r_type;
-
- r_symndx = ELF64_R_SYM (rel->r_info);
-
- if (info->relocateable)
- {
- /* This is a relocateable link. We don't have to change
- anything, unless the reloc is against a section symbol,
- in which case we have to adjust according to where the
- section symbol winds up in the output section. */
- if (r_symndx < symtab_hdr->sh_info)
- {
- sym = local_syms + r_symndx;
- if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
- {
- sec = local_sections[r_symndx];
- rel->r_addend += sec->output_offset + sym->st_value;
- }
- }
-
- continue;
- }
-
- /* This is a final link. */
- h = NULL;
- sym = NULL;
- sec = NULL;
- if (r_symndx < symtab_hdr->sh_info)
- {
- sym = local_syms + r_symndx;
- sec = local_sections[r_symndx];
- relocation = (sec->output_section->vma
- + sec->output_offset
- + sym->st_value);
- }
- else
- {
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- boolean skip_it = false;
- sec = h->root.u.def.section;
-
- switch (r_type)
- {
- case R_SPARC_WPLT30:
- case R_SPARC_PLT32:
- case R_SPARC_HIPLT22:
- case R_SPARC_LOPLT10:
- case R_SPARC_PCPLT32:
- case R_SPARC_PCPLT22:
- case R_SPARC_PCPLT10:
- case R_SPARC_PLT64:
- if (h->plt.offset != (bfd_vma) -1)
- skip_it = true;
- break;
-
- case R_SPARC_GOT10:
- case R_SPARC_GOT13:
- case R_SPARC_GOT22:
- if (elf_hash_table(info)->dynamic_sections_created
- && (!info->shared
- || (!info->symbolic && h->dynindx != -1)
- || !(h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR)))
- skip_it = true;
- break;
-
- case R_SPARC_PC10:
- case R_SPARC_PC22:
- case R_SPARC_PC_HH22:
- case R_SPARC_PC_HM10:
- case R_SPARC_PC_LM22:
- if (!strcmp(h->root.root.string, "_GLOBAL_OFFSET_TABLE_"))
- break;
- /* FALLTHRU */
-
- case R_SPARC_8:
- case R_SPARC_16:
- case R_SPARC_32:
- case R_SPARC_DISP8:
- case R_SPARC_DISP16:
- case R_SPARC_DISP32:
- case R_SPARC_WDISP30:
- case R_SPARC_WDISP22:
- case R_SPARC_HI22:
- case R_SPARC_22:
- case R_SPARC_13:
- case R_SPARC_LO10:
- case R_SPARC_UA32:
- case R_SPARC_10:
- case R_SPARC_11:
- case R_SPARC_64:
- case R_SPARC_OLO10:
- case R_SPARC_HH22:
- case R_SPARC_HM10:
- case R_SPARC_LM22:
- case R_SPARC_WDISP19:
- case R_SPARC_WDISP16:
- case R_SPARC_7:
- case R_SPARC_5:
- case R_SPARC_6:
- case R_SPARC_DISP64:
- case R_SPARC_HIX22:
- case R_SPARC_LOX10:
- case R_SPARC_H44:
- case R_SPARC_M44:
- case R_SPARC_L44:
- case R_SPARC_UA64:
- case R_SPARC_UA16:
- if (info->shared
- && ((!info->symbolic && h->dynindx != -1)
- || !(h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR)))
- skip_it = true;
- break;
- }
-
- if (skip_it)
- {
- /* In these cases, we don't need the relocation
- value. We check specially because in some
- obscure cases sec->output_section will be NULL. */
- relocation = 0;
- }
- else
- {
- relocation = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- }
- else if (h->root.type == bfd_link_hash_undefweak)
- relocation = 0;
- else if (info->shared
- && (!info->symbolic || info->allow_shlib_undefined)
- && !info->no_undefined
- && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- relocation = 0;
- else
- {
- if (! ((*info->callbacks->undefined_symbol)
- (info, h->root.root.string, input_bfd,
- input_section, rel->r_offset,
- (!info->shared || info->no_undefined
- || ELF_ST_VISIBILITY (h->other)))))
- return false;
-
- /* To avoid generating warning messages about truncated
- relocations, set the relocation's address to be the same as
- the start of this section. */
-
- if (input_section->output_section != NULL)
- relocation = input_section->output_section->vma;
- else
- relocation = 0;
- }
- }
-
- /* When generating a shared object, these relocations are copied
- into the output file to be resolved at run time. */
- if (info->shared && r_symndx != 0 && (input_section->flags & SEC_ALLOC))
- {
- switch (r_type)
- {
- case R_SPARC_PC10:
- case R_SPARC_PC22:
- case R_SPARC_PC_HH22:
- case R_SPARC_PC_HM10:
- case R_SPARC_PC_LM22:
- if (h != NULL
- && !strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_"))
- break;
- /* Fall through. */
- case R_SPARC_DISP8:
- case R_SPARC_DISP16:
- case R_SPARC_DISP32:
- case R_SPARC_WDISP30:
- case R_SPARC_WDISP22:
- case R_SPARC_WDISP19:
- case R_SPARC_WDISP16:
- case R_SPARC_DISP64:
- if (h == NULL)
- break;
- /* Fall through. */
- case R_SPARC_8:
- case R_SPARC_16:
- case R_SPARC_32:
- case R_SPARC_HI22:
- case R_SPARC_22:
- case R_SPARC_13:
- case R_SPARC_LO10:
- case R_SPARC_UA32:
- case R_SPARC_10:
- case R_SPARC_11:
- case R_SPARC_64:
- case R_SPARC_OLO10:
- case R_SPARC_HH22:
- case R_SPARC_HM10:
- case R_SPARC_LM22:
- case R_SPARC_7:
- case R_SPARC_5:
- case R_SPARC_6:
- case R_SPARC_HIX22:
- case R_SPARC_LOX10:
- case R_SPARC_H44:
- case R_SPARC_M44:
- case R_SPARC_L44:
- case R_SPARC_UA64:
- case R_SPARC_UA16:
- {
- Elf_Internal_Rela outrel;
- boolean skip;
-
- if (sreloc == NULL)
- {
- const char *name =
- (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
-
- if (name == NULL)
- return false;
-
- BFD_ASSERT (strncmp (name, ".rela", 5) == 0
- && strcmp (bfd_get_section_name(input_bfd,
- input_section),
- name + 5) == 0);
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- BFD_ASSERT (sreloc != NULL);
- }
-
- skip = false;
-
- if (elf_section_data (input_section)->stab_info == NULL)
- outrel.r_offset = rel->r_offset;
- else
- {
- bfd_vma off;
-
- off = (_bfd_stab_section_offset
- (output_bfd, &elf_hash_table (info)->stab_info,
- input_section,
- &elf_section_data (input_section)->stab_info,
- rel->r_offset));
- if (off == MINUS_ONE)
- skip = true;
- outrel.r_offset = off;
- }
-
- outrel.r_offset += (input_section->output_section->vma
- + input_section->output_offset);
-
- /* Optimize unaligned reloc usage now that we know where
- it finally resides. */
- switch (r_type)
- {
- case R_SPARC_16:
- if (outrel.r_offset & 1) r_type = R_SPARC_UA16;
- break;
- case R_SPARC_UA16:
- if (!(outrel.r_offset & 1)) r_type = R_SPARC_16;
- break;
- case R_SPARC_32:
- if (outrel.r_offset & 3) r_type = R_SPARC_UA32;
- break;
- case R_SPARC_UA32:
- if (!(outrel.r_offset & 3)) r_type = R_SPARC_32;
- break;
- case R_SPARC_64:
- if (outrel.r_offset & 7) r_type = R_SPARC_UA64;
- break;
- case R_SPARC_UA64:
- if (!(outrel.r_offset & 7)) r_type = R_SPARC_64;
- break;
- }
-
- if (skip)
- memset (&outrel, 0, sizeof outrel);
- /* h->dynindx may be -1 if the symbol was marked to
- become local. */
- else if (h != NULL
- && ((! info->symbolic && h->dynindx != -1)
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
- {
- BFD_ASSERT (h->dynindx != -1);
- outrel.r_info
- = ELF64_R_INFO (h->dynindx,
- ELF64_R_TYPE_INFO (
- ELF64_R_TYPE_DATA (rel->r_info),
- r_type));
- outrel.r_addend = rel->r_addend;
- }
- else
- {
- if (r_type == R_SPARC_64)
- {
- outrel.r_info = ELF64_R_INFO (0, R_SPARC_RELATIVE);
- outrel.r_addend = relocation + rel->r_addend;
- }
- else
- {
- long indx;
-
- if (h == NULL)
- sec = local_sections[r_symndx];
- else
- {
- BFD_ASSERT (h->root.type == bfd_link_hash_defined
- || (h->root.type
- == bfd_link_hash_defweak));
- sec = h->root.u.def.section;
- }
- if (sec != NULL && bfd_is_abs_section (sec))
- indx = 0;
- else if (sec == NULL || sec->owner == NULL)
- {
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
- else
- {
- asection *osec;
-
- osec = sec->output_section;
- indx = elf_section_data (osec)->dynindx;
-
- /* FIXME: we really should be able to link non-pic
- shared libraries. */
- if (indx == 0)
- {
- BFD_FAIL ();
- (*_bfd_error_handler)
- (_("%s: probably compiled without -fPIC?"),
- bfd_archive_filename (input_bfd));
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
- }
-
- outrel.r_info
- = ELF64_R_INFO (indx,
- ELF64_R_TYPE_INFO (
- ELF64_R_TYPE_DATA (rel->r_info),
- r_type));
- outrel.r_addend = relocation + rel->r_addend;
- }
- }
-
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- (((Elf64_External_Rela *)
- sreloc->contents)
- + sreloc->reloc_count));
- ++sreloc->reloc_count;
-
- /* This reloc will be computed at runtime, so there's no
- need to do anything now. */
- continue;
- }
- break;
- }
- }
-
- switch (r_type)
- {
- case R_SPARC_GOT10:
- case R_SPARC_GOT13:
- case R_SPARC_GOT22:
- /* Relocation is to the entry for this symbol in the global
- offset table. */
- if (sgot == NULL)
- {
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
- }
-
- if (h != NULL)
- {
- bfd_vma off = h->got.offset;
- BFD_ASSERT (off != (bfd_vma) -1);
-
- if (! elf_hash_table (info)->dynamic_sections_created
- || (info->shared
- && (info->symbolic || h->dynindx == -1)
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR)))
- {
- /* This is actually a static link, or it is a -Bsymbolic
- link and the symbol is defined locally, or the symbol
- was forced to be local because of a version file. We
- must initialize this entry in the global offset table.
- Since the offset must always be a multiple of 8, we
- use the least significant bit to record whether we
- have initialized it already.
-
- When doing a dynamic link, we create a .rela.got
- relocation entry to initialize the value. This is
- done in the finish_dynamic_symbol routine. */
-
- if ((off & 1) != 0)
- off &= ~1;
- else
- {
- bfd_put_64 (output_bfd, relocation,
- sgot->contents + off);
- h->got.offset |= 1;
- }
- }
- relocation = sgot->output_offset + off - got_base;
- }
- else
- {
- bfd_vma off;
-
- BFD_ASSERT (local_got_offsets != NULL);
- off = local_got_offsets[r_symndx];
- BFD_ASSERT (off != (bfd_vma) -1);
-
- /* The offset must always be a multiple of 8. We use
- the least significant bit to record whether we have
- already processed this entry. */
- if ((off & 1) != 0)
- off &= ~1;
- else
- {
- local_got_offsets[r_symndx] |= 1;
-
- if (info->shared)
- {
- asection *srelgot;
- Elf_Internal_Rela outrel;
-
- /* The Solaris 2.7 64-bit linker adds the contents
- of the location to the value of the reloc.
- Note this is different behaviour to the
- 32-bit linker, which both adds the contents
- and ignores the addend. So clear the location. */
- bfd_put_64 (output_bfd, (bfd_vma) 0,
- sgot->contents + off);
-
- /* We need to generate a R_SPARC_RELATIVE reloc
- for the dynamic linker. */
- srelgot = bfd_get_section_by_name(dynobj, ".rela.got");
- BFD_ASSERT (srelgot != NULL);
-
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + off);
- outrel.r_info = ELF64_R_INFO (0, R_SPARC_RELATIVE);
- outrel.r_addend = relocation;
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- (((Elf64_External_Rela *)
- srelgot->contents)
- + srelgot->reloc_count));
- ++srelgot->reloc_count;
- }
- else
- bfd_put_64 (output_bfd, relocation, sgot->contents + off);
- }
- relocation = sgot->output_offset + off - got_base;
- }
- goto do_default;
-
- case R_SPARC_WPLT30:
- case R_SPARC_PLT32:
- case R_SPARC_HIPLT22:
- case R_SPARC_LOPLT10:
- case R_SPARC_PCPLT32:
- case R_SPARC_PCPLT22:
- case R_SPARC_PCPLT10:
- case R_SPARC_PLT64:
- /* Relocation is to the entry for this symbol in the
- procedure linkage table. */
- BFD_ASSERT (h != NULL);
-
- if (h->plt.offset == (bfd_vma) -1)
- {
- /* We didn't make a PLT entry for this symbol. This
- happens when statically linking PIC code, or when
- using -Bsymbolic. */
- goto do_default;
- }
-
- if (splt == NULL)
- {
- splt = bfd_get_section_by_name (dynobj, ".plt");
- BFD_ASSERT (splt != NULL);
- }
-
- relocation = (splt->output_section->vma
- + splt->output_offset
- + sparc64_elf_plt_entry_offset (h->plt.offset));
- if (r_type == R_SPARC_WPLT30)
- goto do_wplt30;
- goto do_default;
-
- case R_SPARC_OLO10:
- {
- bfd_vma x;
-
- relocation += rel->r_addend;
- relocation = (relocation & 0x3ff) + ELF64_R_TYPE_DATA (rel->r_info);
-
- x = bfd_get_32 (input_bfd, contents + rel->r_offset);
- x = (x & ~(bfd_vma) 0x1fff) | (relocation & 0x1fff);
- bfd_put_32 (input_bfd, x, contents + rel->r_offset);
-
- r = bfd_check_overflow (howto->complain_on_overflow,
- howto->bitsize, howto->rightshift,
- bfd_arch_bits_per_address (input_bfd),
- relocation);
- }
- break;
-
- case R_SPARC_WDISP16:
- {
- bfd_vma x;
-
- relocation += rel->r_addend;
- /* Adjust for pc-relative-ness. */
- relocation -= (input_section->output_section->vma
- + input_section->output_offset);
- relocation -= rel->r_offset;
-
- x = bfd_get_32 (input_bfd, contents + rel->r_offset);
- x &= ~(bfd_vma) 0x303fff;
- x |= ((((relocation >> 2) & 0xc000) << 6)
- | ((relocation >> 2) & 0x3fff));
- bfd_put_32 (input_bfd, x, contents + rel->r_offset);
-
- r = bfd_check_overflow (howto->complain_on_overflow,
- howto->bitsize, howto->rightshift,
- bfd_arch_bits_per_address (input_bfd),
- relocation);
- }
- break;
-
- case R_SPARC_HIX22:
- {
- bfd_vma x;
-
- relocation += rel->r_addend;
- relocation = relocation ^ MINUS_ONE;
-
- x = bfd_get_32 (input_bfd, contents + rel->r_offset);
- x = (x & ~(bfd_vma) 0x3fffff) | ((relocation >> 10) & 0x3fffff);
- bfd_put_32 (input_bfd, x, contents + rel->r_offset);
-
- r = bfd_check_overflow (howto->complain_on_overflow,
- howto->bitsize, howto->rightshift,
- bfd_arch_bits_per_address (input_bfd),
- relocation);
- }
- break;
-
- case R_SPARC_LOX10:
- {
- bfd_vma x;
-
- relocation += rel->r_addend;
- relocation = (relocation & 0x3ff) | 0x1c00;
-
- x = bfd_get_32 (input_bfd, contents + rel->r_offset);
- x = (x & ~(bfd_vma) 0x1fff) | relocation;
- bfd_put_32 (input_bfd, x, contents + rel->r_offset);
-
- r = bfd_reloc_ok;
- }
- break;
-
- case R_SPARC_WDISP30:
- do_wplt30:
- if (SEC_DO_RELAX (input_section)
- && rel->r_offset + 4 < input_section->_raw_size)
- {
-#define G0 0
-#define O7 15
-#define XCC (2 << 20)
-#define COND(x) (((x)&0xf)<<25)
-#define CONDA COND(0x8)
-#define INSN_BPA (F2(0,1) | CONDA | BPRED | XCC)
-#define INSN_BA (F2(0,2) | CONDA)
-#define INSN_OR F3(2, 0x2, 0)
-#define INSN_NOP F2(0,4)
-
- bfd_vma x, y;
-
- /* If the instruction is a call with either:
- restore
- arithmetic instruction with rd == %o7
- where rs1 != %o7 and rs2 if it is register != %o7
- then we can optimize if the call destination is near
- by changing the call into a branch always. */
- x = bfd_get_32 (input_bfd, contents + rel->r_offset);
- y = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
- if ((x & OP(~0)) == OP(1) && (y & OP(~0)) == OP(2))
- {
- if (((y & OP3(~0)) == OP3(0x3d) /* restore */
- || ((y & OP3(0x28)) == 0 /* arithmetic */
- && (y & RD(~0)) == RD(O7)))
- && (y & RS1(~0)) != RS1(O7)
- && ((y & F3I(~0))
- || (y & RS2(~0)) != RS2(O7)))
- {
- bfd_vma reloc;
-
- reloc = relocation + rel->r_addend - rel->r_offset;
- reloc -= (input_section->output_section->vma
- + input_section->output_offset);
- if (reloc & 3)
- goto do_default;
-
- /* Ensure the branch fits into simm22. */
- if ((reloc & ~(bfd_vma)0x7fffff)
- && ((reloc | 0x7fffff) != MINUS_ONE))
- goto do_default;
- reloc >>= 2;
-
- /* Check whether it fits into simm19. */
- if ((reloc & 0x3c0000) == 0
- || (reloc & 0x3c0000) == 0x3c0000)
- x = INSN_BPA | (reloc & 0x7ffff); /* ba,pt %xcc */
- else
- x = INSN_BA | (reloc & 0x3fffff); /* ba */
- bfd_put_32 (input_bfd, x, contents + rel->r_offset);
- r = bfd_reloc_ok;
- if (rel->r_offset >= 4
- && (y & (0xffffffff ^ RS1(~0)))
- == (INSN_OR | RD(O7) | RS2(G0)))
- {
- bfd_vma z;
- unsigned int reg;
-
- z = bfd_get_32 (input_bfd,
- contents + rel->r_offset - 4);
- if ((z & (0xffffffff ^ RD(~0)))
- != (INSN_OR | RS1(O7) | RS2(G0)))
- break;
-
- /* The sequence was
- or %o7, %g0, %rN
- call foo
- or %rN, %g0, %o7
-
- If call foo was replaced with ba, replace
- or %rN, %g0, %o7 with nop. */
-
- reg = (y & RS1(~0)) >> 14;
- if (reg != ((z & RD(~0)) >> 25)
- || reg == G0 || reg == O7)
- break;
-
- bfd_put_32 (input_bfd, (bfd_vma) INSN_NOP,
- contents + rel->r_offset + 4);
- }
- break;
- }
- }
- }
- /* FALLTHROUGH */
-
- default:
- do_default:
- r = _bfd_final_link_relocate (howto, input_bfd, input_section,
- contents, rel->r_offset,
- relocation, rel->r_addend);
- break;
- }
-
- switch (r)
- {
- case bfd_reloc_ok:
- break;
-
- default:
- case bfd_reloc_outofrange:
- abort ();
-
- case bfd_reloc_overflow:
- {
- const char *name;
-
- if (h != NULL)
- {
- if (h->root.type == bfd_link_hash_undefweak
- && howto->pc_relative)
- {
- /* Assume this is a call protected by other code that
- detect the symbol is undefined. If this is the case,
- we can safely ignore the overflow. If not, the
- program is hosed anyway, and a little warning isn't
- going to help. */
- break;
- }
-
- name = h->root.root.string;
- }
- else
- {
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- symtab_hdr->sh_link,
- sym->st_name));
- if (name == NULL)
- return false;
- if (*name == '\0')
- name = bfd_section_name (input_bfd, sec);
- }
- if (! ((*info->callbacks->reloc_overflow)
- (info, name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset)))
- return false;
- }
- break;
- }
- }
-
- return true;
-}
-
-/* Finish up dynamic symbol handling. We set the contents of various
- dynamic sections here. */
-
-static boolean
-sparc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
- bfd *output_bfd;
- struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
-{
- bfd *dynobj;
-
- dynobj = elf_hash_table (info)->dynobj;
-
- if (h->plt.offset != (bfd_vma) -1)
- {
- asection *splt;
- asection *srela;
- Elf_Internal_Rela rela;
-
- /* This symbol has an entry in the PLT. Set it up. */
-
- BFD_ASSERT (h->dynindx != -1);
-
- splt = bfd_get_section_by_name (dynobj, ".plt");
- srela = bfd_get_section_by_name (dynobj, ".rela.plt");
- BFD_ASSERT (splt != NULL && srela != NULL);
-
- /* Fill in the entry in the .rela.plt section. */
-
- if (h->plt.offset < LARGE_PLT_THRESHOLD)
- {
- rela.r_offset = sparc64_elf_plt_entry_offset (h->plt.offset);
- rela.r_addend = 0;
- }
- else
- {
- bfd_vma max = splt->_raw_size / PLT_ENTRY_SIZE;
- rela.r_offset = sparc64_elf_plt_ptr_offset (h->plt.offset, max);
- rela.r_addend = -(sparc64_elf_plt_entry_offset (h->plt.offset) + 4)
- -(splt->output_section->vma + splt->output_offset);
- }
- rela.r_offset += (splt->output_section->vma + splt->output_offset);
- rela.r_info = ELF64_R_INFO (h->dynindx, R_SPARC_JMP_SLOT);
-
- /* Adjust for the first 4 reserved elements in the .plt section
- when setting the offset in the .rela.plt section.
- Sun forgot to read their own ABI and copied elf32-sparc behaviour,
- thus .plt[4] has corresponding .rela.plt[0] and so on. */
-
- bfd_elf64_swap_reloca_out (output_bfd, &rela,
- ((Elf64_External_Rela *) srela->contents
- + (h->plt.offset - 4)));
-
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- {
- /* Mark the symbol as undefined, rather than as defined in
- the .plt section. Leave the value alone. */
- sym->st_shndx = SHN_UNDEF;
- /* If the symbol is weak, we do need to clear the value.
- Otherwise, the PLT entry would provide a definition for
- the symbol even if the symbol wasn't defined anywhere,
- and so the symbol would never be NULL. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
- == 0)
- sym->st_value = 0;
- }
- }
-
- if (h->got.offset != (bfd_vma) -1)
- {
- asection *sgot;
- asection *srela;
- Elf_Internal_Rela rela;
-
- /* This symbol has an entry in the GOT. Set it up. */
-
- sgot = bfd_get_section_by_name (dynobj, ".got");
- srela = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (sgot != NULL && srela != NULL);
-
- rela.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + (h->got.offset &~ (bfd_vma) 1));
-
- /* If this is a -Bsymbolic link, and the symbol is defined
- locally, we just want to emit a RELATIVE reloc. Likewise if
- the symbol was forced to be local because of a version file.
- The entry in the global offset table will already have been
- initialized in the relocate_section function. */
- if (info->shared
- && (info->symbolic || h->dynindx == -1)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
- {
- asection *sec = h->root.u.def.section;
- rela.r_info = ELF64_R_INFO (0, R_SPARC_RELATIVE);
- rela.r_addend = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- else
- {
- bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
- rela.r_info = ELF64_R_INFO (h->dynindx, R_SPARC_GLOB_DAT);
- rela.r_addend = 0;
- }
-
- bfd_elf64_swap_reloca_out (output_bfd, &rela,
- ((Elf64_External_Rela *) srela->contents
- + srela->reloc_count));
- ++srela->reloc_count;
- }
-
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
- {
- asection *s;
- Elf_Internal_Rela rela;
-
- /* This symbols needs a copy reloc. Set it up. */
-
- BFD_ASSERT (h->dynindx != -1);
-
- s = bfd_get_section_by_name (h->root.u.def.section->owner,
- ".rela.bss");
- BFD_ASSERT (s != NULL);
-
- rela.r_offset = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
- rela.r_info = ELF64_R_INFO (h->dynindx, R_SPARC_COPY);
- rela.r_addend = 0;
- bfd_elf64_swap_reloca_out (output_bfd, &rela,
- ((Elf64_External_Rela *) s->contents
- + s->reloc_count));
- ++s->reloc_count;
- }
-
- /* Mark some specially defined symbols as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
- sym->st_shndx = SHN_ABS;
-
- return true;
-}
-
-/* Finish up the dynamic sections. */
-
-static boolean
-sparc64_elf_finish_dynamic_sections (output_bfd, info)
- bfd *output_bfd;
- struct bfd_link_info *info;
-{
- bfd *dynobj;
- int stt_regidx = -1;
- asection *sdyn;
- asection *sgot;
-
- dynobj = elf_hash_table (info)->dynobj;
-
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
-
- if (elf_hash_table (info)->dynamic_sections_created)
- {
- asection *splt;
- Elf64_External_Dyn *dyncon, *dynconend;
-
- splt = bfd_get_section_by_name (dynobj, ".plt");
- BFD_ASSERT (splt != NULL && sdyn != NULL);
-
- dyncon = (Elf64_External_Dyn *) sdyn->contents;
- dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
- for (; dyncon < dynconend; dyncon++)
- {
- Elf_Internal_Dyn dyn;
- const char *name;
- boolean size;
-
- bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
-
- switch (dyn.d_tag)
- {
- case DT_PLTGOT: name = ".plt"; size = false; break;
- case DT_PLTRELSZ: name = ".rela.plt"; size = true; break;
- case DT_JMPREL: name = ".rela.plt"; size = false; break;
- case DT_SPARC_REGISTER:
- if (stt_regidx == -1)
- {
- stt_regidx =
- _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1);
- if (stt_regidx == -1)
- return false;
- }
- dyn.d_un.d_val = stt_regidx++;
- bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
- /* fallthrough */
- default: name = NULL; size = false; break;
- }
-
- if (name != NULL)
- {
- asection *s;
-
- s = bfd_get_section_by_name (output_bfd, name);
- if (s == NULL)
- dyn.d_un.d_val = 0;
- else
- {
- if (! size)
- dyn.d_un.d_ptr = s->vma;
- else
- {
- if (s->_cooked_size != 0)
- dyn.d_un.d_val = s->_cooked_size;
- else
- dyn.d_un.d_val = s->_raw_size;
- }
- }
- bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
- }
- }
-
- /* Initialize the contents of the .plt section. */
- if (splt->_raw_size > 0)
- {
- sparc64_elf_build_plt (output_bfd, splt->contents,
- (int) (splt->_raw_size / PLT_ENTRY_SIZE));
- }
-
- elf_section_data (splt->output_section)->this_hdr.sh_entsize =
- PLT_ENTRY_SIZE;
- }
-
- /* Set the first entry in the global offset table to the address of
- the dynamic section. */
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
- if (sgot->_raw_size > 0)
- {
- if (sdyn == NULL)
- bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents);
- else
- bfd_put_64 (output_bfd,
- sdyn->output_section->vma + sdyn->output_offset,
- sgot->contents);
- }
-
- elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 8;
-
- return true;
-}
-
-static enum elf_reloc_type_class
-sparc64_elf_reloc_type_class (rela)
- const Elf_Internal_Rela *rela;
-{
- switch ((int) ELF64_R_TYPE (rela->r_info))
- {
- 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;
- }
-}
-\f
-/* Functions for dealing with the e_flags field. */
-
-/* Copy backend specific data from one object module to another */
-static boolean
-sparc64_elf_copy_private_bfd_data (ibfd, obfd)
- bfd *ibfd, *obfd;
-{
- if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
- return true;
-
- BFD_ASSERT (!elf_flags_init (obfd)
- || (elf_elfheader (obfd)->e_flags
- == elf_elfheader (ibfd)->e_flags));
-
- elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
- elf_flags_init (obfd) = true;
- return true;
-}
-
-/* Merge backend specific data from an object file to the output
- object file when linking. */
-
-static boolean
-sparc64_elf_merge_private_bfd_data (ibfd, obfd)
- bfd *ibfd;
- bfd *obfd;
-{
- boolean 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));