+ return bfd_reloc_ok;
+}
+
+static reloc_howto_type *
+frv_reloc_type_lookup (abfd, code)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ bfd_reloc_code_real_type code;
+{
+ switch (code)
+ {
+ default:
+ break;
+
+ case BFD_RELOC_NONE:
+ return &elf32_frv_howto_table[ (int) R_FRV_NONE];
+
+ case BFD_RELOC_32:
+ if (elf_elfheader (abfd)->e_type == ET_EXEC
+ || elf_elfheader (abfd)->e_type == ET_DYN)
+ return &elf32_frv_rel_32_howto;
+ /* Fall through. */
+ case BFD_RELOC_CTOR:
+ return &elf32_frv_howto_table[ (int) R_FRV_32];
+
+ case BFD_RELOC_FRV_LABEL16:
+ return &elf32_frv_howto_table[ (int) R_FRV_LABEL16];
+
+ case BFD_RELOC_FRV_LABEL24:
+ return &elf32_frv_howto_table[ (int) R_FRV_LABEL24];
+
+ case BFD_RELOC_FRV_LO16:
+ return &elf32_frv_howto_table[ (int) R_FRV_LO16];
+
+ case BFD_RELOC_FRV_HI16:
+ return &elf32_frv_howto_table[ (int) R_FRV_HI16];
+
+ case BFD_RELOC_FRV_GPREL12:
+ return &elf32_frv_howto_table[ (int) R_FRV_GPREL12];
+
+ case BFD_RELOC_FRV_GPRELU12:
+ return &elf32_frv_howto_table[ (int) R_FRV_GPRELU12];
+
+ case BFD_RELOC_FRV_GPREL32:
+ return &elf32_frv_howto_table[ (int) R_FRV_GPREL32];
+
+ case BFD_RELOC_FRV_GPRELHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_GPRELHI];
+
+ case BFD_RELOC_FRV_GPRELLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_GPRELLO];
+
+ case BFD_RELOC_FRV_GOT12:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOT12];
+
+ case BFD_RELOC_FRV_GOTHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTHI];
+
+ case BFD_RELOC_FRV_GOTLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTLO];
+
+ case BFD_RELOC_FRV_FUNCDESC:
+ if (elf_elfheader (abfd)->e_type == ET_EXEC
+ || elf_elfheader (abfd)->e_type == ET_DYN)
+ return &elf32_frv_rel_funcdesc_howto;
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC];
+
+ case BFD_RELOC_FRV_FUNCDESC_GOT12:
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOT12];
+
+ case BFD_RELOC_FRV_FUNCDESC_GOTHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTHI];
+
+ case BFD_RELOC_FRV_FUNCDESC_GOTLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTLO];
+
+ case BFD_RELOC_FRV_FUNCDESC_VALUE:
+ if (elf_elfheader (abfd)->e_type == ET_EXEC
+ || elf_elfheader (abfd)->e_type == ET_DYN)
+ return &elf32_frv_rel_funcdesc_value_howto;
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_VALUE];
+
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTOFF12];
+
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTOFFHI];
+
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTOFFLO];
+
+ case BFD_RELOC_FRV_GOTOFF12:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTOFF12];
+
+ case BFD_RELOC_FRV_GOTOFFHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTOFFHI];
+
+ case BFD_RELOC_FRV_GOTOFFLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTOFFLO];
+
+ case BFD_RELOC_FRV_GETTLSOFF:
+ return &elf32_frv_howto_table[ (int) R_FRV_GETTLSOFF];
+
+ case BFD_RELOC_FRV_TLSDESC_VALUE:
+ if (elf_elfheader (abfd)->e_type == ET_EXEC
+ || elf_elfheader (abfd)->e_type == ET_DYN)
+ return &elf32_frv_rel_tlsdesc_value_howto;
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSDESC_VALUE];
+
+ case BFD_RELOC_FRV_GOTTLSDESC12:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSDESC12];
+
+ case BFD_RELOC_FRV_GOTTLSDESCHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSDESCHI];
+
+ case BFD_RELOC_FRV_GOTTLSDESCLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSDESCLO];
+
+ case BFD_RELOC_FRV_TLSMOFF12:
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFF12];
+
+ case BFD_RELOC_FRV_TLSMOFFHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFFHI];
+
+ case BFD_RELOC_FRV_TLSMOFFLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFFLO];
+
+ case BFD_RELOC_FRV_GOTTLSOFF12:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSOFF12];
+
+ case BFD_RELOC_FRV_GOTTLSOFFHI:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSOFFHI];
+
+ case BFD_RELOC_FRV_GOTTLSOFFLO:
+ return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSOFFLO];
+
+ case BFD_RELOC_FRV_TLSOFF:
+ if (elf_elfheader (abfd)->e_type == ET_EXEC
+ || elf_elfheader (abfd)->e_type == ET_DYN)
+ return &elf32_frv_rel_tlsoff_howto;
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSOFF];
+
+ case BFD_RELOC_FRV_TLSDESC_RELAX:
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSDESC_RELAX];
+
+ case BFD_RELOC_FRV_GETTLSOFF_RELAX:
+ return &elf32_frv_howto_table[ (int) R_FRV_GETTLSOFF_RELAX];
+
+ case BFD_RELOC_FRV_TLSOFF_RELAX:
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSOFF_RELAX];
+
+ case BFD_RELOC_FRV_TLSMOFF:
+ return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFF];
+
+ case BFD_RELOC_VTABLE_INHERIT:
+ return &elf32_frv_vtinherit_howto;
+
+ case BFD_RELOC_VTABLE_ENTRY:
+ return &elf32_frv_vtentry_howto;
+ }
+
+ return NULL;
+}
+
+static reloc_howto_type *
+frv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < sizeof (elf32_frv_howto_table) / sizeof (elf32_frv_howto_table[0]);
+ i++)
+ if (elf32_frv_howto_table[i].name != NULL
+ && strcasecmp (elf32_frv_howto_table[i].name, r_name) == 0)
+ return &elf32_frv_howto_table[i];
+
+ if (strcasecmp (elf32_frv_vtinherit_howto.name, r_name) == 0)
+ return &elf32_frv_vtinherit_howto;
+ if (strcasecmp (elf32_frv_vtentry_howto.name, r_name) == 0)
+ return &elf32_frv_vtentry_howto;
+
+ return NULL;
+}
+
+/* Set the howto pointer for an FRV ELF reloc. */
+
+static void
+frv_info_to_howto_rela (abfd, cache_ptr, dst)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *cache_ptr;
+ Elf_Internal_Rela *dst;
+{
+ unsigned int r_type;
+
+ r_type = ELF32_R_TYPE (dst->r_info);
+ switch (r_type)
+ {
+ case R_FRV_GNU_VTINHERIT:
+ cache_ptr->howto = &elf32_frv_vtinherit_howto;
+ break;
+
+ case R_FRV_GNU_VTENTRY:
+ cache_ptr->howto = &elf32_frv_vtentry_howto;
+ break;
+
+ default:
+ cache_ptr->howto = & elf32_frv_howto_table [r_type];
+ break;
+ }
+}
+
+/* Set the howto pointer for an FRV ELF REL reloc. */
+static void
+frvfdpic_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *cache_ptr, Elf_Internal_Rela *dst)
+{
+ unsigned int r_type;
+
+ r_type = ELF32_R_TYPE (dst->r_info);
+ switch (r_type)
+ {
+ case R_FRV_32:
+ cache_ptr->howto = &elf32_frv_rel_32_howto;
+ break;
+
+ case R_FRV_FUNCDESC:
+ cache_ptr->howto = &elf32_frv_rel_funcdesc_howto;
+ break;
+
+ case R_FRV_FUNCDESC_VALUE:
+ cache_ptr->howto = &elf32_frv_rel_funcdesc_value_howto;
+ break;
+
+ case R_FRV_TLSDESC_VALUE:
+ cache_ptr->howto = &elf32_frv_rel_tlsdesc_value_howto;
+ break;
+
+ case R_FRV_TLSOFF:
+ cache_ptr->howto = &elf32_frv_rel_tlsoff_howto;
+ break;
+
+ default:
+ cache_ptr->howto = NULL;
+ break;
+ }
+}
+\f
+/* Perform a single relocation. By default we use the standard BFD
+ routines, but a few relocs, we have to do them ourselves. */
+
+static bfd_reloc_status_type
+frv_final_link_relocate (howto, input_bfd, input_section, contents, rel,
+ relocation)
+ reloc_howto_type *howto;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ Elf_Internal_Rela *rel;
+ bfd_vma relocation;
+{
+ return _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset, relocation,
+ rel->r_addend);
+}
+
+\f
+/* Relocate an FRV ELF section.
+
+ The RELOCATE_SECTION function is called by the new ELF backend linker
+ to handle the relocations for a section.
+
+ The relocs are always passed as Rela structures; if the section
+ actually uses Rel structures, the r_addend field will always be
+ zero.
+
+ This function is responsible for adjusting the section contents as
+ necessary, and (if using Rela relocs and generating a relocatable
+ output file) adjusting the reloc addend as necessary.
+
+ This function does not have to worry about setting the reloc
+ address or the reloc symbol index.
+
+ LOCAL_SYMS is a pointer to the swapped in local symbols.
+
+ LOCAL_SECTIONS is an array giving the section in the input file
+ corresponding to the st_shndx field of each local symbol.
+
+ The global hash table entry for the global symbols can be found
+ via elf_sym_hashes (input_bfd).
+
+ When generating relocatable output, this function must handle
+ STB_LOCAL/STT_SECTION symbols specially. The output symbol is
+ going to be the section symbol corresponding to the output
+ section, which means that the addend must be adjusted
+ accordingly. */
+
+static bfd_boolean
+elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section,
+ contents, relocs, local_syms, local_sections)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ 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;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ unsigned isec_segment, got_segment, plt_segment, gprel_segment, tls_segment,
+ check_segment[2];
+ int silence_segment_error = !(info->shared || info->pie);
+ unsigned long insn;
+
+ symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (input_bfd);
+ relend = relocs + input_section->reloc_count;
+
+ isec_segment = _frvfdpic_osec_to_segment (output_bfd,
+ input_section->output_section);
+ if (IS_FDPIC (output_bfd) && frvfdpic_got_section (info))
+ got_segment = _frvfdpic_osec_to_segment (output_bfd,
+ frvfdpic_got_section (info)
+ ->output_section);
+ else
+ got_segment = -1;
+ if (IS_FDPIC (output_bfd) && frvfdpic_gotfixup_section (info))
+ gprel_segment = _frvfdpic_osec_to_segment (output_bfd,
+ frvfdpic_gotfixup_section (info)
+ ->output_section);
+ else
+ gprel_segment = -1;
+ if (IS_FDPIC (output_bfd) && frvfdpic_plt_section (info))
+ plt_segment = _frvfdpic_osec_to_segment (output_bfd,
+ frvfdpic_plt_section (info)
+ ->output_section);
+ else
+ plt_segment = -1;
+ if (elf_hash_table (info)->tls_sec)
+ tls_segment = _frvfdpic_osec_to_segment (output_bfd,
+ elf_hash_table (info)->tls_sec);
+ else
+ tls_segment = -1;
+
+ for (rel = relocs; rel < relend; rel ++)
+ {
+ reloc_howto_type *howto;
+ unsigned long r_symndx;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ struct elf_link_hash_entry *h;
+ bfd_vma relocation;
+ bfd_reloc_status_type r;
+ const char * name = NULL;
+ int r_type;
+ asection *osec;
+ struct frvfdpic_relocs_info *picrel;
+ bfd_vma orig_addend = rel->r_addend;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if ( r_type == R_FRV_GNU_VTINHERIT
+ || r_type == R_FRV_GNU_VTENTRY)
+ continue;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ howto = elf32_frv_howto_table + ELF32_R_TYPE (rel->r_info);
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ osec = sec = local_sections [r_symndx];
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+
+ name = bfd_elf_string_from_elf_section
+ (input_bfd, symtab_hdr->sh_link, sym->st_name);
+ name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
+ }
+ else
+ {
+ bfd_boolean warned;
+ bfd_boolean unresolved_reloc;
+
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation,
+ unresolved_reloc, warned);
+ osec = sec;
+ }
+
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (info->relocatable)
+ continue;
+
+ if (r_type != R_FRV_TLSMOFF
+ && h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !FRVFDPIC_SYM_LOCAL (info, h))
+ {
+ osec = sec = NULL;
+ relocation = 0;
+ }
+
+ switch (r_type)
+ {
+ case R_FRV_LABEL24:
+ case R_FRV_32:
+ if (! IS_FDPIC (output_bfd))
+ goto non_fdpic;
+
+ case R_FRV_GOT12:
+ case R_FRV_GOTHI:
+ case R_FRV_GOTLO:
+ case R_FRV_FUNCDESC_GOT12:
+ case R_FRV_FUNCDESC_GOTHI:
+ case R_FRV_FUNCDESC_GOTLO:
+ case R_FRV_GOTOFF12:
+ case R_FRV_GOTOFFHI:
+ case R_FRV_GOTOFFLO:
+ case R_FRV_FUNCDESC_GOTOFF12:
+ case R_FRV_FUNCDESC_GOTOFFHI:
+ case R_FRV_FUNCDESC_GOTOFFLO:
+ case R_FRV_FUNCDESC:
+ case R_FRV_FUNCDESC_VALUE:
+ case R_FRV_GETTLSOFF:
+ case R_FRV_TLSDESC_VALUE:
+ case R_FRV_GOTTLSDESC12:
+ case R_FRV_GOTTLSDESCHI:
+ case R_FRV_GOTTLSDESCLO:
+ case R_FRV_TLSMOFF12:
+ case R_FRV_TLSMOFFHI:
+ case R_FRV_TLSMOFFLO:
+ case R_FRV_GOTTLSOFF12:
+ case R_FRV_GOTTLSOFFHI:
+ case R_FRV_GOTTLSOFFLO:
+ case R_FRV_TLSOFF:
+ case R_FRV_TLSDESC_RELAX:
+ case R_FRV_GETTLSOFF_RELAX:
+ case R_FRV_TLSOFF_RELAX:
+ case R_FRV_TLSMOFF:
+ if (h != NULL)
+ picrel = frvfdpic_relocs_info_for_global (frvfdpic_relocs_info
+ (info), input_bfd, h,
+ orig_addend, INSERT);
+ else
+ /* In order to find the entry we created before, we must
+ use the original addend, not the one that may have been
+ modified by _bfd_elf_rela_local_sym(). */
+ picrel = frvfdpic_relocs_info_for_local (frvfdpic_relocs_info
+ (info), input_bfd, r_symndx,
+ orig_addend, INSERT);
+ if (! picrel)
+ return FALSE;
+
+ if (!_frvfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
+ osec, sym,
+ rel->r_addend))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%x): relocation to `%s+%x' may have caused the error above"),
+ input_bfd, input_section, rel->r_offset, name, rel->r_addend);
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ non_fdpic:
+ picrel = NULL;
+ if (h && ! FRVFDPIC_SYM_LOCAL (info, h))
+ {
+ info->callbacks->warning
+ (info, _("relocation references symbol not defined in the module"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_FRV_GETTLSOFF:
+ case R_FRV_TLSDESC_VALUE:
+ case R_FRV_GOTTLSDESC12:
+ case R_FRV_GOTTLSDESCHI:
+ case R_FRV_GOTTLSDESCLO:
+ case R_FRV_TLSMOFF12:
+ case R_FRV_TLSMOFFHI:
+ case R_FRV_TLSMOFFLO:
+ case R_FRV_GOTTLSOFF12:
+ case R_FRV_GOTTLSOFFHI:
+ case R_FRV_GOTTLSOFFLO:
+ case R_FRV_TLSOFF:
+ case R_FRV_TLSDESC_RELAX:
+ case R_FRV_GETTLSOFF_RELAX:
+ case R_FRV_TLSOFF_RELAX:
+ case R_FRV_TLSMOFF:
+ if (sec && (bfd_is_abs_section (sec) || bfd_is_und_section (sec)))
+ relocation += tls_biased_base (info);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Try to apply TLS relaxations. */
+ if (1)
+ switch (r_type)
+ {
+
+#define LOCAL_EXEC_P(info, picrel) \
+ ((info)->executable \
+ && (picrel->symndx != -1 || FRVFDPIC_SYM_LOCAL ((info), (picrel)->d.h)))
+#define INITIAL_EXEC_P(info, picrel) \
+ (((info)->executable || (info)->flags & DF_STATIC_TLS) \
+ && (picrel)->tlsoff_entry)
+
+#define IN_RANGE_FOR_OFST12_P(value) \
+ ((bfd_vma)((value) + 2048) < (bfd_vma)4096)
+#define IN_RANGE_FOR_SETLOS_P(value) \
+ ((bfd_vma)((value) + 32768) < (bfd_vma)65536)
+#define TLSMOFF_IN_RANGE_FOR_SETLOS_P(value, info) \
+ (IN_RANGE_FOR_SETLOS_P ((value) - tls_biased_base (info)))
+
+#define RELAX_GETTLSOFF_LOCAL_EXEC_P(info, picrel, value) \
+ (LOCAL_EXEC_P ((info), (picrel)) \
+ && TLSMOFF_IN_RANGE_FOR_SETLOS_P((value), (info)))
+#define RELAX_GETTLSOFF_INITIAL_EXEC_P(info, picrel) \
+ (INITIAL_EXEC_P ((info), (picrel)) \
+ && IN_RANGE_FOR_OFST12_P ((picrel)->tlsoff_entry))
+
+#define RELAX_TLSDESC_LOCAL_EXEC_P(info, picrel, value) \
+ (LOCAL_EXEC_P ((info), (picrel)))
+#define RELAX_TLSDESC_INITIAL_EXEC_P(info, picrel) \
+ (INITIAL_EXEC_P ((info), (picrel)))
+
+#define RELAX_GOTTLSOFF_LOCAL_EXEC_P(info, picrel, value) \
+ (LOCAL_EXEC_P ((info), (picrel)) \
+ && TLSMOFF_IN_RANGE_FOR_SETLOS_P((value), (info)))
+
+ case R_FRV_GETTLSOFF:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a call instruction? */
+ if ((insn & (unsigned long)0x01fc0000) != 0x003c0000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GETTLSOFF not applied to a call instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_GETTLSOFF_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend))
+ {
+ /* Replace the call instruction (except the packing bit)
+ with setlos #tlsmofflo(symbol+offset), gr9. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x12fc0000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_GETTLSOFF_INITIAL_EXEC_P (info, picrel))
+ {
+ /* Replace the call instruction (except the packing bit)
+ with ldi @(gr15, #gottlsoff12(symbol+addend)), gr9. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x12c8f000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_GOTTLSOFF12;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ break;
+
+ case R_FRV_GOTTLSDESC12:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this an lddi instruction? */
+ if ((insn & (unsigned long)0x01fc0000) != 0x00cc0000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GOTTLSDESC12 not applied to an lddi instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ && TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend,
+ info))
+ {
+ /* Replace lddi @(grB, #gottlsdesc12(symbol+offset), grC
+ with setlos #tlsmofflo(symbol+offset), gr<C+1>.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0x80000000)
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ insn |= (unsigned long)0x00fc0000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend))
+ {
+ /* Replace lddi @(grB, #gottlsdesc12(symbol+offset), grC
+ with sethi #tlsmoffhi(symbol+offset), gr<C+1>.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0x80000000)
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ insn |= (unsigned long)0x00f80000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFHI;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel))
+ {
+ /* Replace lddi @(grB, #gottlsdesc12(symbol+offset), grC
+ with ldi @(grB, #gottlsoff12(symbol+offset),
+ gr<C+1>. Preserve the packing bit. If gottlsoff12
+ overflows, we'll error out, but that's sort-of ok,
+ since we'd started with gottlsdesc12, that's actually
+ more demanding. Compiling with -fPIE instead of
+ -fpie would fix it; linking with --relax should fix
+ it as well. */
+ insn = (insn & (unsigned long)0x80cbf000)
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_GOTTLSOFF12;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ break;
+
+ case R_FRV_GOTTLSDESCHI:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a sethi instruction? */
+ if ((insn & (unsigned long)0x01ff0000) != 0x00f80000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GOTTLSDESCHI not applied to a sethi instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)
+ && IN_RANGE_FOR_SETLOS_P (picrel->tlsoff_entry)))
+ {
+ /* Replace sethi with a nop. Preserve the packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel))
+ {
+ /* Simply decay GOTTLSDESC to GOTTLSOFF. */
+ r_type = R_FRV_GOTTLSOFFHI;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ break;
+
+ case R_FRV_GOTTLSDESCLO:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a setlo or setlos instruction? */
+ if ((insn & (unsigned long)0x01f70000) != 0x00f40000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GOTTLSDESCLO"
+ " not applied to a setlo or setlos instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)
+ && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry)))
+ {
+ /* Replace setlo/setlos with a nop. Preserve the
+ packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel))
+ {
+ /* If the corresponding sethi (if it exists) decayed
+ to a nop, make sure this becomes (or already is) a
+ setlos, not setlo. */
+ if (IN_RANGE_FOR_SETLOS_P (picrel->tlsoff_entry))
+ {
+ insn |= (unsigned long)0x00080000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
+
+ /* Simply decay GOTTLSDESC to GOTTLSOFF. */
+ r_type = R_FRV_GOTTLSOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ break;
+
+ case R_FRV_TLSDESC_RELAX:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this an ldd instruction? */
+ if ((insn & (unsigned long)0x01fc0fc0) != 0x00080140)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_TLSDESC_RELAX not applied to an ldd instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ && TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend,
+ info))
+ {
+ /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC
+ with setlos #tlsmofflo(symbol+offset), gr<C+1>.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0x80000000)
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ insn |= (unsigned long)0x00fc0000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend))
+ {
+ /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC
+ with sethi #tlsmoffhi(symbol+offset), gr<C+1>.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0x80000000)
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ insn |= (unsigned long)0x00f80000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFHI;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)
+ && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry))
+ {
+ /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC
+ with ldi @(grB, #gottlsoff12(symbol+offset), gr<C+1>.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0x8003f000)
+ | (unsigned long)0x00c80000
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_GOTTLSOFF12;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel))
+ {
+ /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC
+ with ld #tlsoff(symbol+offset)@(grB, grA), gr<C+1>.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0x81ffffbf)
+ | ((insn + (unsigned long)0x02000000)
+ & (unsigned long)0x7e000000);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* #tlsoff(symbol+offset) is just a relaxation
+ annotation, so there's nothing left to
+ relocate. */
+ continue;
+ }
+
+ break;
+
+ case R_FRV_GETTLSOFF_RELAX:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a calll or callil instruction? */
+ if ((insn & (unsigned long)0x7ff80fc0) != 0x02300000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GETTLSOFF_RELAX"
+ " not applied to a calll instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ && TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend,
+ info))
+ {
+ /* Replace calll with a nop. Preserve the packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ else if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend))
+ {
+ /* Replace calll with setlo #tlsmofflo(symbol+offset), gr9.
+ Preserve the packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x12f40000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel))
+ {
+ /* Replace calll with a nop. Preserve the packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ break;
+
+ case R_FRV_GOTTLSOFF12:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this an ldi instruction? */
+ if ((insn & (unsigned long)0x01fc0000) != 0x00c80000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GOTTLSOFF12 not applied to an ldi instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend))
+ {
+ /* Replace ldi @(grB, #gottlsoff12(symbol+offset), grC
+ with setlos #tlsmofflo(symbol+offset), grC.
+ Preserve the packing bit. */
+ insn &= (unsigned long)0xfe000000;
+ insn |= (unsigned long)0x00fc0000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ break;
+
+ case R_FRV_GOTTLSOFFHI:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a sethi instruction? */
+ if ((insn & (unsigned long)0x01ff0000) != 0x00f80000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GOTTLSOFFHI not applied to a sethi instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)
+ && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry)))
+ {
+ /* Replace sethi with a nop. Preserve the packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ break;
+
+ case R_FRV_GOTTLSOFFLO:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a setlo or setlos instruction? */
+ if ((insn & (unsigned long)0x01f70000) != 0x00f40000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_GOTTLSOFFLO"
+ " not applied to a setlo or setlos instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend)
+ || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)
+ && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry)))
+ {
+ /* Replace setlo/setlos with a nop. Preserve the
+ packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ break;
+
+ case R_FRV_TLSOFF_RELAX:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this an ld instruction? */
+ if ((insn & (unsigned long)0x01fc0fc0) != 0x00080100)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_TLSOFF_RELAX not applied to an ld instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel,
+ relocation + rel->r_addend))
+ {
+ /* Replace ld #gottlsoff(symbol+offset)@(grB, grA), grC
+ with setlos #tlsmofflo(symbol+offset), grC.
+ Preserve the packing bit. */
+ insn &= (unsigned long)0xfe000000;
+ insn |= (unsigned long)0x00fc0000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_TLSMOFFLO;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)
+ && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry))
+ {
+ /* Replace ld #tlsoff(symbol+offset)@(grB, grA), grC
+ with ldi @(grB, #gottlsoff12(symbol+offset), grC.
+ Preserve the packing bit. */
+ insn = (insn & (unsigned long)0xfe03f000)
+ | (unsigned long)0x00c80000;;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ r_type = R_FRV_GOTTLSOFF12;
+ howto = elf32_frv_howto_table + r_type;
+ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ }
+
+ break;
+
+ case R_FRV_TLSMOFFHI:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a sethi instruction? */
+ if ((insn & (unsigned long)0x01ff0000) != 0x00f80000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_TLSMOFFHI not applied to a sethi instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend,
+ info))
+ {
+ /* Replace sethi with a nop. Preserve the packing bit. */
+ insn &= (unsigned long)0x80000000;
+ insn |= (unsigned long)0x00880000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ /* Nothing to relocate. */
+ continue;
+ }
+
+ break;
+
+ case R_FRV_TLSMOFFLO:
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Is this a setlo or setlos instruction? */
+ if ((insn & (unsigned long)0x01f70000) != 0x00f40000)
+ {
+ r = info->callbacks->warning
+ (info,
+ _("R_FRV_TLSMOFFLO"
+ " not applied to a setlo or setlos instruction"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ if (TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend,
+ info))
+ /* If the corresponding sethi (if it exists) decayed
+ to a nop, make sure this becomes (or already is) a
+ setlos, not setlo. */
+ {
+ insn |= (unsigned long)0x00080000;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
+
+ break;
+
+ /*
+ There's nothing to relax in these:
+ R_FRV_TLSDESC_VALUE
+ R_FRV_TLSOFF
+ R_FRV_TLSMOFF12
+ R_FRV_TLSMOFFHI
+ R_FRV_TLSMOFFLO
+ R_FRV_TLSMOFF
+ */
+
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_FRV_LABEL24:
+ check_segment[0] = isec_segment;
+ if (! IS_FDPIC (output_bfd))
+ check_segment[1] = isec_segment;
+ else if (picrel->plt)
+ {
+ relocation = frvfdpic_plt_section (info)->output_section->vma
+ + frvfdpic_plt_section (info)->output_offset
+ + picrel->plt_entry;
+ check_segment[1] = plt_segment;
+ }
+ /* We don't want to warn on calls to undefined weak symbols,
+ as calls to them must be protected by non-NULL tests
+ anyway, and unprotected calls would invoke undefined
+ behavior. */
+ else if (picrel->symndx == -1
+ && picrel->d.h->root.type == bfd_link_hash_undefweak)
+ check_segment[1] = check_segment[0];
+ else
+ check_segment[1] = sec
+ ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
+
+ case R_FRV_GOT12:
+ case R_FRV_GOTHI:
+ case R_FRV_GOTLO:
+ relocation = picrel->got_entry;
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+
+ case R_FRV_FUNCDESC_GOT12:
+ case R_FRV_FUNCDESC_GOTHI:
+ case R_FRV_FUNCDESC_GOTLO:
+ relocation = picrel->fdgot_entry;
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+
+ case R_FRV_GOTOFFHI:
+ case R_FRV_GOTOFF12:
+ case R_FRV_GOTOFFLO:
+ relocation -= frvfdpic_got_section (info)->output_section->vma
+ + frvfdpic_got_section (info)->output_offset
+ + frvfdpic_got_initial_offset (info);
+ check_segment[0] = got_segment;
+ check_segment[1] = sec
+ ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
+
+ case R_FRV_FUNCDESC_GOTOFF12:
+ case R_FRV_FUNCDESC_GOTOFFHI:
+ case R_FRV_FUNCDESC_GOTOFFLO:
+ relocation = picrel->fd_entry;
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+
+ case R_FRV_FUNCDESC:
+ {
+ int dynindx;
+ bfd_vma addend = rel->r_addend;
+
+ if (! (h && h->root.type == bfd_link_hash_undefweak
+ && FRVFDPIC_SYM_LOCAL (info, h)))
+ {
+ /* If the symbol is dynamic and there may be dynamic
+ symbol resolution because we are or are linked with a
+ shared library, emit a FUNCDESC relocation such that
+ the dynamic linker will allocate the function
+ descriptor. If the symbol needs a non-local function
+ descriptor but binds locally (e.g., its visibility is
+ protected, emit a dynamic relocation decayed to
+ section+offset. */
+ if (h && ! FRVFDPIC_FUNCDESC_LOCAL (info, h)
+ && FRVFDPIC_SYM_LOCAL (info, h)
+ && !(info->executable && !info->pie))
+ {
+ dynindx = elf_section_data (h->root.u.def.section
+ ->output_section)->dynindx;
+ addend += h->root.u.def.section->output_offset
+ + h->root.u.def.value;
+ }
+ else if (h && ! FRVFDPIC_FUNCDESC_LOCAL (info, h))
+ {
+ if (addend)
+ {
+ info->callbacks->warning
+ (info, _("R_FRV_FUNCDESC references dynamic symbol with nonzero addend"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+ dynindx = h->dynindx;
+ }
+ else
+ {
+ /* Otherwise, we know we have a private function
+ descriptor, so reference it directly. */
+ BFD_ASSERT (picrel->privfd);
+ r_type = R_FRV_32;
+ dynindx = elf_section_data (frvfdpic_got_section (info)
+ ->output_section)->dynindx;
+ addend = frvfdpic_got_section (info)->output_offset
+ + frvfdpic_got_initial_offset (info)
+ + picrel->fd_entry;
+ }
+
+ /* If there is room for dynamic symbol resolution, emit
+ the dynamic relocation. However, if we're linking an
+ executable at a fixed location, we won't have emitted a
+ dynamic symbol entry for the got section, so idx will
+ be zero, which means we can and should compute the
+ address of the private descriptor ourselves. */
+ if (info->executable && !info->pie
+ && (!h || FRVFDPIC_FUNCDESC_LOCAL (info, h)))
+ {
+ addend += frvfdpic_got_section (info)->output_section->vma;
+ if ((bfd_get_section_flags (output_bfd,
+ input_section->output_section)
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ bfd_vma offset;
+
+ if (_frvfdpic_osec_readonly_p (output_bfd,
+ input_section
+ ->output_section))
+ {
+ info->callbacks->warning
+ (info,
+ _("cannot emit fixups in read-only section"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ offset = _bfd_elf_section_offset
+ (output_bfd, info,
+ input_section, rel->r_offset);
+
+ if (offset != (bfd_vma)-1)
+ _frvfdpic_add_rofixup (output_bfd,
+ frvfdpic_gotfixup_section
+ (info),
+ offset + input_section
+ ->output_section->vma
+ + input_section->output_offset,
+ picrel);
+ }
+ }
+ else if ((bfd_get_section_flags (output_bfd,
+ input_section->output_section)
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ bfd_vma offset;
+
+ if (_frvfdpic_osec_readonly_p (output_bfd,
+ input_section
+ ->output_section))
+ {
+ info->callbacks->warning
+ (info,
+ _("cannot emit dynamic relocations in read-only section"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ offset = _bfd_elf_section_offset
+ (output_bfd, info,
+ input_section, rel->r_offset);
+
+ if (offset != (bfd_vma)-1)
+ _frvfdpic_add_dyn_reloc (output_bfd,
+ frvfdpic_gotrel_section (info),
+ offset + input_section
+ ->output_section->vma
+ + input_section->output_offset,
+ r_type, dynindx, addend, picrel);
+ }
+ else
+ addend += frvfdpic_got_section (info)->output_section->vma;
+ }
+
+ /* We want the addend in-place because dynamic
+ relocations are REL. Setting relocation to it should
+ arrange for it to be installed. */
+ relocation = addend - rel->r_addend;
+ }
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+
+ case R_FRV_32:
+ if (! IS_FDPIC (output_bfd))
+ {
+ check_segment[0] = check_segment[1] = -1;
+ break;
+ }
+ /* Fall through. */
+ case R_FRV_FUNCDESC_VALUE:
+ {
+ int dynindx;
+ bfd_vma addend = rel->r_addend;
+
+ /* If the symbol is dynamic but binds locally, use
+ section+offset. */
+ if (h && ! FRVFDPIC_SYM_LOCAL (info, h))
+ {
+ if (addend && r_type == R_FRV_FUNCDESC_VALUE)
+ {
+ info->callbacks->warning
+ (info, _("R_FRV_FUNCDESC_VALUE references dynamic symbol with nonzero addend"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+ dynindx = h->dynindx;
+ }
+ else
+ {
+ if (h)
+ addend += h->root.u.def.value;
+ else
+ addend += sym->st_value;
+ if (osec)
+ addend += osec->output_offset;
+ if (osec && osec->output_section
+ && ! bfd_is_abs_section (osec->output_section)
+ && ! bfd_is_und_section (osec->output_section))
+ dynindx = elf_section_data (osec->output_section)->dynindx;
+ else
+ dynindx = 0;
+ }
+
+ /* If we're linking an executable at a fixed address, we
+ can omit the dynamic relocation as long as the symbol
+ is defined in the current link unit (which is implied
+ by its output section not being NULL). */
+ if (info->executable && !info->pie
+ && (!h || FRVFDPIC_SYM_LOCAL (info, h)))
+ {
+ if (osec)
+ addend += osec->output_section->vma;
+ if (IS_FDPIC (input_bfd)
+ && (bfd_get_section_flags (output_bfd,
+ input_section->output_section)
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ if (_frvfdpic_osec_readonly_p (output_bfd,
+ input_section
+ ->output_section))
+ {
+ info->callbacks->warning
+ (info,
+ _("cannot emit fixups in read-only section"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+ if (!h || h->root.type != bfd_link_hash_undefweak)
+ {
+ bfd_vma offset = _bfd_elf_section_offset
+ (output_bfd, info,
+ input_section, rel->r_offset);
+
+ if (offset != (bfd_vma)-1)
+ {
+ _frvfdpic_add_rofixup (output_bfd,
+ frvfdpic_gotfixup_section
+ (info),
+ offset + input_section
+ ->output_section->vma
+ + input_section->output_offset,
+ picrel);
+ if (r_type == R_FRV_FUNCDESC_VALUE)
+ _frvfdpic_add_rofixup
+ (output_bfd,
+ frvfdpic_gotfixup_section (info),
+ offset
+ + input_section->output_section->vma
+ + input_section->output_offset + 4, picrel);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((bfd_get_section_flags (output_bfd,
+ input_section->output_section)
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ bfd_vma offset;
+
+ if (_frvfdpic_osec_readonly_p (output_bfd,
+ input_section
+ ->output_section))
+ {
+ info->callbacks->warning
+ (info,
+ _("cannot emit dynamic relocations in read-only section"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+
+ offset = _bfd_elf_section_offset
+ (output_bfd, info,
+ input_section, rel->r_offset);
+
+ if (offset != (bfd_vma)-1)
+ _frvfdpic_add_dyn_reloc (output_bfd,
+ frvfdpic_gotrel_section (info),
+ offset + input_section
+ ->output_section->vma
+ + input_section->output_offset,
+ r_type, dynindx, addend, picrel);
+ }
+ else if (osec)
+ addend += osec->output_section->vma;
+ /* We want the addend in-place because dynamic
+ relocations are REL. Setting relocation to it
+ should arrange for it to be installed. */
+ relocation = addend - rel->r_addend;
+ }
+
+ if (r_type == R_FRV_FUNCDESC_VALUE)
+ {
+ /* If we've omitted the dynamic relocation, just emit
+ the fixed addresses of the symbol and of the local
+ GOT base offset. */
+ if (info->executable && !info->pie
+ && (!h || FRVFDPIC_SYM_LOCAL (info, h)))
+ bfd_put_32 (output_bfd,
+ frvfdpic_got_section (info)->output_section->vma
+ + frvfdpic_got_section (info)->output_offset
+ + frvfdpic_got_initial_offset (info),
+ contents + rel->r_offset + 4);
+ else
+ /* A function descriptor used for lazy or local
+ resolving is initialized such that its high word
+ contains the output section index in which the
+ PLT entries are located, and the low word
+ contains the offset of the lazy PLT entry entry
+ point into that section. */
+ bfd_put_32 (output_bfd,
+ h && ! FRVFDPIC_SYM_LOCAL (info, h)
+ ? 0
+ : _frvfdpic_osec_to_segment (output_bfd,
+ sec
+ ->output_section),
+ contents + rel->r_offset + 4);
+ }
+ }
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+
+ case R_FRV_GPREL12:
+ case R_FRV_GPRELU12:
+ case R_FRV_GPREL32:
+ case R_FRV_GPRELHI:
+ case R_FRV_GPRELLO:
+ check_segment[0] = gprel_segment;
+ check_segment[1] = sec
+ ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
+
+ case R_FRV_GETTLSOFF:
+ relocation = frvfdpic_plt_section (info)->output_section->vma
+ + frvfdpic_plt_section (info)->output_offset
+ + picrel->tlsplt_entry;
+ BFD_ASSERT (picrel->tlsplt_entry != (bfd_vma)-1
+ && picrel->tlsdesc_entry);
+ check_segment[0] = isec_segment;
+ check_segment[1] = plt_segment;
+ break;
+
+ case R_FRV_GOTTLSDESC12:
+ case R_FRV_GOTTLSDESCHI:
+ case R_FRV_GOTTLSDESCLO:
+ BFD_ASSERT (picrel->tlsdesc_entry);
+ relocation = picrel->tlsdesc_entry;
+ check_segment[0] = tls_segment;
+ check_segment[1] = sec
+ && ! bfd_is_abs_section (sec)
+ && ! bfd_is_und_section (sec)
+ ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : tls_segment;
+ break;
+
+ case R_FRV_TLSMOFF12:
+ case R_FRV_TLSMOFFHI:
+ case R_FRV_TLSMOFFLO:
+ case R_FRV_TLSMOFF:
+ check_segment[0] = tls_segment;
+ if (! sec)
+ check_segment[1] = -1;
+ else if (bfd_is_abs_section (sec)
+ || bfd_is_und_section (sec))
+ {
+ relocation = 0;
+ check_segment[1] = tls_segment;
+ }
+ else if (sec->output_section)
+ {
+ relocation -= tls_biased_base (info);
+ check_segment[1] =
+ _frvfdpic_osec_to_segment (output_bfd, sec->output_section);
+ }
+ else
+ check_segment[1] = -1;
+ break;
+
+ case R_FRV_GOTTLSOFF12:
+ case R_FRV_GOTTLSOFFHI:
+ case R_FRV_GOTTLSOFFLO:
+ BFD_ASSERT (picrel->tlsoff_entry);
+ relocation = picrel->tlsoff_entry;
+ check_segment[0] = tls_segment;
+ check_segment[1] = sec
+ && ! bfd_is_abs_section (sec)
+ && ! bfd_is_und_section (sec)
+ ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : tls_segment;
+ break;
+
+ case R_FRV_TLSDESC_VALUE:
+ case R_FRV_TLSOFF:
+ /* These shouldn't be present in input object files. */
+ check_segment[0] = check_segment[1] = isec_segment;
+ break;
+
+ case R_FRV_TLSDESC_RELAX:
+ case R_FRV_GETTLSOFF_RELAX:
+ case R_FRV_TLSOFF_RELAX:
+ /* These are just annotations for relaxation, nothing to do
+ here. */
+ continue;
+
+ default:
+ check_segment[0] = isec_segment;
+ check_segment[1] = sec
+ ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
+ }
+
+ if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
+ {
+ /* If you take this out, remove the #error from fdpic-static-6.d
+ in the ld testsuite. */
+ /* This helps catch problems in GCC while we can't do more
+ than static linking. The idea is to test whether the
+ input file basename is crt0.o only once. */
+ if (silence_segment_error == 1)
+ silence_segment_error =
+ (strlen (input_bfd->filename) == 6
+ && strcmp (input_bfd->filename, "crt0.o") == 0)
+ || (strlen (input_bfd->filename) > 6
+ && strcmp (input_bfd->filename
+ + strlen (input_bfd->filename) - 7,
+ "/crt0.o") == 0)
+ ? -1 : 0;
+ if (!silence_segment_error
+ /* We don't want duplicate errors for undefined
+ symbols. */
+ && !(picrel && picrel->symndx == -1
+ && picrel->d.h->root.type == bfd_link_hash_undefined))
+ {
+ if (info->shared || info->pie)
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): reloc against `%s': %s"),
+ input_bfd, input_section, (long)rel->r_offset, name,
+ _("relocation references a different segment"));
+ else
+ info->callbacks->warning
+ (info,
+ _("relocation references a different segment"),
+ name, input_bfd, input_section, rel->r_offset);
+ }
+ if (!silence_segment_error && (info->shared || info->pie))
+ return FALSE;
+ elf_elfheader (output_bfd)->e_flags |= EF_FRV_PIC;
+ }
+
+ switch (r_type)
+ {
+ case R_FRV_GOTOFFHI:
+ case R_FRV_TLSMOFFHI:
+ /* We need the addend to be applied before we shift the
+ value right. */
+ relocation += rel->r_addend;
+ /* Fall through. */
+ case R_FRV_GOTHI:
+ case R_FRV_FUNCDESC_GOTHI:
+ case R_FRV_FUNCDESC_GOTOFFHI:
+ case R_FRV_GOTTLSOFFHI:
+ case R_FRV_GOTTLSDESCHI:
+ relocation >>= 16;
+ /* Fall through. */
+
+ case R_FRV_GOTLO:
+ case R_FRV_FUNCDESC_GOTLO:
+ case R_FRV_GOTOFFLO:
+ case R_FRV_FUNCDESC_GOTOFFLO:
+ case R_FRV_GOTTLSOFFLO:
+ case R_FRV_GOTTLSDESCLO:
+ case R_FRV_TLSMOFFLO:
+ relocation &= 0xffff;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_FRV_LABEL24:
+ if (! IS_FDPIC (output_bfd) || ! picrel->plt)
+ break;
+ /* Fall through. */
+
+ /* When referencing a GOT entry, a function descriptor or a
+ PLT, we don't want the addend to apply to the reference,
+ but rather to the referenced symbol. The actual entry
+ will have already been created taking the addend into
+ account, so cancel it out here. */
+ case R_FRV_GOT12:
+ case R_FRV_GOTHI:
+ case R_FRV_GOTLO:
+ case R_FRV_FUNCDESC_GOT12:
+ case R_FRV_FUNCDESC_GOTHI:
+ case R_FRV_FUNCDESC_GOTLO:
+ case R_FRV_FUNCDESC_GOTOFF12:
+ case R_FRV_FUNCDESC_GOTOFFHI:
+ case R_FRV_FUNCDESC_GOTOFFLO:
+ case R_FRV_GETTLSOFF:
+ case R_FRV_GOTTLSDESC12:
+ case R_FRV_GOTTLSDESCHI:
+ case R_FRV_GOTTLSDESCLO:
+ case R_FRV_GOTTLSOFF12:
+ case R_FRV_GOTTLSOFFHI:
+ case R_FRV_GOTTLSOFFLO:
+ /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF12
+ here, since we do want to apply the addend to the others.
+ Note that we've applied the addend to GOTOFFHI before we
+ shifted it right. */
+ case R_FRV_GOTOFFHI:
+ case R_FRV_TLSMOFFHI:
+ relocation -= rel->r_addend;
+ break;
+
+ default:
+ break;
+ }
+
+ if (r_type == R_FRV_HI16)
+ r = elf32_frv_relocate_hi16 (input_bfd, rel, contents, relocation);
+
+ else if (r_type == R_FRV_LO16)
+ r = elf32_frv_relocate_lo16 (input_bfd, rel, contents, relocation);
+
+ else if (r_type == R_FRV_LABEL24 || r_type == R_FRV_GETTLSOFF)
+ r = elf32_frv_relocate_label24 (input_bfd, input_section, rel,
+ contents, relocation);
+
+ else if (r_type == R_FRV_GPREL12)
+ r = elf32_frv_relocate_gprel12 (info, input_bfd, input_section, rel,
+ contents, relocation);
+
+ else if (r_type == R_FRV_GPRELU12)
+ r = elf32_frv_relocate_gprelu12 (info, input_bfd, input_section, rel,
+ contents, relocation);
+
+ else if (r_type == R_FRV_GPRELLO)
+ r = elf32_frv_relocate_gprello (info, input_bfd, input_section, rel,
+ contents, relocation);
+
+ else if (r_type == R_FRV_GPRELHI)
+ r = elf32_frv_relocate_gprelhi (info, input_bfd, input_section, rel,
+ contents, relocation);
+
+ else if (r_type == R_FRV_TLSOFF
+ || r_type == R_FRV_TLSDESC_VALUE)
+ r = bfd_reloc_notsupported;
+
+ else
+ r = frv_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel, relocation);
+
+ if (r != bfd_reloc_ok)
+ {
+ const char * msg = (const char *) NULL;
+
+ switch (r)
+ {
+ case bfd_reloc_overflow:
+ r = info->callbacks->reloc_overflow
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
+ break;
+
+ case bfd_reloc_undefined:
+ r = info->callbacks->undefined_symbol
+ (info, name, input_bfd, input_section, rel->r_offset, TRUE);
+ break;
+
+ case bfd_reloc_outofrange:
+ msg = _("internal error: out of range error");
+ break;
+
+ case bfd_reloc_notsupported:
+ msg = _("internal error: unsupported relocation error");
+ break;
+
+ case bfd_reloc_dangerous:
+ msg = _("internal error: dangerous relocation");
+ break;
+
+ default:
+ msg = _("internal error: unknown error");
+ break;
+ }
+
+ if (msg)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): reloc against `%s': %s"),
+ input_bfd, input_section, (long)rel->r_offset, name, msg);
+ return FALSE;
+ }
+
+ if (! r)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+\f
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+elf32_frv_gc_mark_hook (asection *sec,
+ struct bfd_link_info *info,
+ Elf_Internal_Rela *rel,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ if (h != NULL)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_FRV_GNU_VTINHERIT:
+ case R_FRV_GNU_VTENTRY:
+ return NULL;
+ }
+
+ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
+\f
+/* Hook called by the linker routine which adds symbols from an object
+ file. We use it to put .comm items in .scomm, and not .comm. */
+
+static bfd_boolean
+elf32_frv_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ Elf_Internal_Sym *sym;
+ const char **namep ATTRIBUTE_UNUSED;
+ flagword *flagsp ATTRIBUTE_UNUSED;
+ asection **secp;
+ bfd_vma *valp;
+{
+ if (sym->st_shndx == SHN_COMMON
+ && !info->relocatable
+ && (int)sym->st_size <= (int)bfd_get_gp_size (abfd))
+ {
+ /* Common symbols less than or equal to -G nn bytes are
+ automatically put into .sbss. */
+
+ asection *scomm = bfd_get_section_by_name (abfd, ".scommon");
+
+ if (scomm == NULL)
+ {
+ scomm = bfd_make_section_with_flags (abfd, ".scommon",
+ (SEC_ALLOC
+ | SEC_IS_COMMON
+ | SEC_LINKER_CREATED));
+ if (scomm == NULL)
+ return FALSE;
+ }
+
+ *secp = scomm;
+ *valp = sym->st_size;
+ }
+
+ return TRUE;
+}
+
+/* We need dynamic symbols for every section, since segments can
+ relocate independently. */
+static bfd_boolean
+_frvfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info
+ ATTRIBUTE_UNUSED,
+ asection *p ATTRIBUTE_UNUSED)
+{
+ switch (elf_section_data (p)->this_hdr.sh_type)
+ {
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ /* If sh_type is yet undecided, assume it could be
+ SHT_PROGBITS/SHT_NOBITS. */
+ case SHT_NULL:
+ return FALSE;
+
+ /* There shouldn't be section relative relocations
+ against any other section. */
+ default:
+ return TRUE;
+ }
+}
+
+/* Create a .got section, as well as its additional info field. This
+ is almost entirely copied from
+ elflink.c:_bfd_elf_create_got_section(). */
+
+static bfd_boolean
+_frv_create_got_section (bfd *abfd, struct bfd_link_info *info)
+{
+ flagword flags, pltflags;
+ asection *s;
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ int ptralign;
+ int offset;
+
+ /* This function may be called more than once. */
+ s = bfd_get_section_by_name (abfd, ".got");
+ if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
+ return TRUE;
+
+ /* Machine specific: although pointers are 32-bits wide, we want the
+ GOT to be aligned to a 64-bit boundary, such that function
+ descriptors in it can be accessed with 64-bit loads and
+ stores. */
+ ptralign = 3;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+ pltflags = flags;
+
+ s = bfd_make_section_with_flags (abfd, ".got", flags);
+ if (s == NULL
+ || !bfd_set_section_alignment (abfd, s, ptralign))
+ return FALSE;
+
+ if (bed->want_got_plt)
+ {
+ s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
+ if (s == NULL
+ || !bfd_set_section_alignment (abfd, s, ptralign))
+ return FALSE;
+ }
+
+ if (bed->want_got_sym)
+ {
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
+ (or .got.plt) section. We don't do this in the linker script
+ because we don't want to define the symbol if we are not creating
+ a global offset table. */
+ h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_");
+ elf_hash_table (info)->hgot = h;
+ if (h == NULL)
+ return FALSE;
+
+ /* Machine-specific: we want the symbol for executables as
+ well. */
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ /* The first bit of the global offset table is the header. */
+ s->size += bed->got_header_size;
+
+ /* This is the machine-specific part. Create and initialize section
+ data for the got. */
+ if (IS_FDPIC (abfd))
+ {
+ frvfdpic_got_section (info) = s;
+ frvfdpic_relocs_info (info) = htab_try_create (1,
+ frvfdpic_relocs_info_hash,
+ frvfdpic_relocs_info_eq,
+ (htab_del) NULL);
+ if (! frvfdpic_relocs_info (info))
+ return FALSE;
+
+ s = bfd_make_section_with_flags (abfd, ".rel.got",
+ (flags | SEC_READONLY));
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return FALSE;
+
+ frvfdpic_gotrel_section (info) = s;
+
+ /* Machine-specific. */
+ s = bfd_make_section_with_flags (abfd, ".rofixup",
+ (flags | SEC_READONLY));
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return FALSE;
+
+ frvfdpic_gotfixup_section (info) = s;
+ offset = -2048;
+ flags = BSF_GLOBAL;
+ }
+ else
+ {
+ offset = 2048;
+ flags = BSF_GLOBAL | BSF_WEAK;
+ }
+
+ /* Define _gp in .rofixup, for FDPIC, or .got otherwise. If it
+ turns out that we're linking with a different linker script, the
+ linker script will override it. */
+ bh = NULL;
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, abfd, "_gp", flags, s, offset, (const char *) NULL, FALSE,
+ bed->collect, &bh)))
+ return FALSE;
+ h = (struct elf_link_hash_entry *) bh;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ /* h->other = STV_HIDDEN; */ /* Should we? */
+
+ /* Machine-specific: we want the symbol for executables as well. */
+ if (IS_FDPIC (abfd) && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+
+ if (!IS_FDPIC (abfd))
+ return TRUE;
+
+ /* FDPIC supports Thread Local Storage, and this may require a
+ procedure linkage table for TLS PLT entries. */
+
+ /* This is mostly copied from
+ elflink.c:_bfd_elf_create_dynamic_sections(). */
+
+ flags = pltflags;
+ pltflags |= SEC_CODE;
+ if (bed->plt_not_loaded)
+ pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
+ if (bed->plt_readonly)
+ pltflags |= SEC_READONLY;
+
+ s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+ return FALSE;
+ /* FRV-specific: remember it. */
+ frvfdpic_plt_section (info) = s;
+
+ /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
+ .plt section. */
+ if (bed->want_plt_sym)
+ {
+ h = _bfd_elf_define_linkage_sym (abfd, info, s,
+ "_PROCEDURE_LINKAGE_TABLE_");
+ elf_hash_table (info)->hplt = h;
+ if (h == NULL)
+ return FALSE;
+ }
+
+ /* FRV-specific: we want rel relocations for the plt. */
+ s = bfd_make_section_with_flags (abfd, ".rel.plt",
+ flags | SEC_READONLY);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ return FALSE;
+ /* FRV-specific: remember it. */
+ frvfdpic_pltrel_section (info) = s;
+
+ return TRUE;