return _bfd_elf_is_local_label_name (abfd, label);
}
+\f
+/* Look through the relocs for a section during the first phase, and
+ allocate space in the global offset table or procedure linkage
+ table. */
-extern const bfd_target bfd_elf32_bfinfdpic_vec;
-#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec)
-
-/* An extension of the elf hash table data structure, containing some
- additional Blackfin-specific data. */
-struct bfinfdpic_elf_link_hash_table
+static bfd_boolean
+bfin_check_relocs (bfd * abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
{
- struct elf_link_hash_table elf;
-
- /* A pointer to the .got section. */
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
asection *sgot;
- /* A pointer to the .rel.got section. */
- asection *sgotrel;
- /* A pointer to the .rofixup section. */
- asection *sgotfixup;
- /* A pointer to the .plt section. */
- asection *splt;
- /* A pointer to the .rel.plt section. */
- asection *spltrel;
- /* GOT base offset. */
- bfd_vma got0;
- /* Location of the first non-lazy PLT entry, i.e., the number of
- bytes taken by lazy PLT entries. */
- bfd_vma plt0;
- /* A hash table holding information about which symbols were
- referenced with which PIC-related relocations. */
- struct htab *relocs_info;
-};
-
-/* Get the Blackfin ELF linker hash table from a link_info structure. */
-
-#define bfinfdpic_hash_table(info) \
- ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
-
-#define bfinfdpic_got_section(info) \
- (bfinfdpic_hash_table (info)->sgot)
-#define bfinfdpic_gotrel_section(info) \
- (bfinfdpic_hash_table (info)->sgotrel)
-#define bfinfdpic_gotfixup_section(info) \
- (bfinfdpic_hash_table (info)->sgotfixup)
-#define bfinfdpic_plt_section(info) \
- (bfinfdpic_hash_table (info)->splt)
-#define bfinfdpic_pltrel_section(info) \
- (bfinfdpic_hash_table (info)->spltrel)
-#define bfinfdpic_relocs_info(info) \
- (bfinfdpic_hash_table (info)->relocs_info)
-#define bfinfdpic_got_initial_offset(info) \
- (bfinfdpic_hash_table (info)->got0)
-#define bfinfdpic_plt_initial_offset(info) \
- (bfinfdpic_hash_table (info)->plt0)
-
-/* Create a Blackfin ELF linker hash table. */
+ asection *srelgot;
+ asection *sreloc;
+ if (info->relocatable)
+ return TRUE;
-static struct bfd_link_hash_table *
-bfinfdpic_elf_link_hash_table_create (bfd *abfd)
-{
- struct bfinfdpic_elf_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
- ret = bfd_zalloc (abfd, amt);
- if (ret == NULL)
- return NULL;
+ sgot = NULL;
+ srelgot = NULL;
+ sreloc = NULL;
- if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
- _bfd_elf_link_hash_newfunc,
- sizeof (struct elf_link_hash_entry)))
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
{
- free (ret);
- return NULL;
- }
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
- return &ret->elf.root;
-}
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-/* Decide whether a reference to a symbol can be resolved locally or
- not. If the symbol is protected, we want the local address, but
- its function descriptor must be assigned by the dynamic linker. */
-#define BFINFDPIC_SYM_LOCAL(INFO, H) \
- (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
- || ! elf_hash_table (INFO)->dynamic_sections_created)
-#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \
- ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_BFIN_GNU_VTINHERIT:
+ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return FALSE;
+ break;
-/* This structure collects information on what kind of GOT, PLT or
- function descriptors are required by relocations that reference a
- certain symbol. */
-struct bfinfdpic_relocs_info
-{
- /* The index of the symbol, as stored in the relocation r_info, if
- we have a local symbol; -1 otherwise. */
- long symndx;
- union
- {
- /* The input bfd in which the symbol is defined, if it's a local
- symbol. */
- bfd *abfd;
- /* If symndx == -1, the hash table entry corresponding to a global
- symbol (even if it turns out to bind locally, in which case it
- should ideally be replaced with section's symndx + addend). */
- struct elf_link_hash_entry *h;
- } d;
- /* The addend of the relocation that references the symbol. */
- bfd_vma addend;
+ /* This relocation describes which C++ vtable entries
+ are actually used. Record for later use during GC. */
+ case R_BFIN_GNU_VTENTRY:
+ BFD_ASSERT (h != NULL);
+ if (h != NULL
+ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return FALSE;
+ break;
- /* The fields above are used to identify an entry. The fields below
- contain information on how an entry is used and, later on, which
- locations it was assigned. */
- /* The following 2 fields record whether the symbol+addend above was
- ever referenced with a GOT relocation. The 17M4 suffix indicates a
- GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs. */
- unsigned got17m4;
- unsigned gothilo;
- /* Whether a FUNCDESC relocation references symbol+addend. */
- unsigned fd;
- /* Whether a FUNCDESC_GOT relocation references symbol+addend. */
- unsigned fdgot17m4;
- unsigned fdgothilo;
- /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */
- unsigned fdgoff17m4;
- unsigned fdgoffhilo;
- /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or
- GOTOFFHI relocations. The addend doesn't really matter, since we
- envision that this will only be used to check whether the symbol
- is mapped to the same segment as the got. */
- unsigned gotoff;
- /* Whether symbol+addend is referenced by a LABEL24 relocation. */
- unsigned call;
- /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE
- relocation. */
- unsigned sym;
- /* Whether we need a PLT entry for a symbol. Should be implied by
- something like:
- (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)) */
- unsigned plt:1;
- /* Whether a function descriptor should be created in this link unit
- for symbol+addend. Should be implied by something like:
- (plt || fdgotoff17m4 || fdgotofflohi
- || ((fd || fdgot17m4 || fdgothilo)
- && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h)))) */
- unsigned privfd:1;
- /* Whether a lazy PLT entry is needed for this symbol+addend.
- Should be implied by something like:
- (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)
- && ! (info->flags & DF_BIND_NOW)) */
- unsigned lazyplt:1;
- /* Whether we've already emitted GOT relocations and PLT entries as
- needed for this symbol. */
- unsigned done:1;
+ case R_got:
+ if (h != NULL
+ && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
+ break;
+ /* Fall through. */
- /* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
- relocations referencing the symbol. */
- unsigned relocs32, relocsfd, relocsfdv;
+ if (dynobj == NULL)
+ {
+ /* Create the .got section. */
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (!_bfd_elf_create_got_section (dynobj, info))
+ return FALSE;
+ }
- /* The number of .rofixups entries and dynamic relocations allocated
- for this symbol, minus any that might have already been used. */
- unsigned fixups, dynrelocs;
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
- /* The offsets of the GOT entries assigned to symbol+addend, to the
- function descriptor's address, and to a function descriptor,
- respectively. Should be zero if unassigned. The offsets are
- counted from the value that will be assigned to the PIC register,
- not from the beginning of the .got section. */
- bfd_signed_vma got_entry, fdgot_entry, fd_entry;
- /* The offsets of the PLT entries assigned to symbol+addend,
- non-lazy and lazy, respectively. If unassigned, should be
- (bfd_vma)-1. */
- bfd_vma plt_entry, lzplt_entry;
-};
+ if (srelgot == NULL && (h != NULL || info->shared))
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ {
+ flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED
+ | SEC_READONLY);
+ srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
+ flags);
+ if (srelgot == NULL
+ || !bfd_set_section_alignment (dynobj, srelgot, 2))
+ return FALSE;
+ }
+ }
-/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry. */
-static hashval_t
-bfinfdpic_relocs_info_hash (const void *entry_)
-{
- const struct bfinfdpic_relocs_info *entry = entry_;
+ if (h != NULL)
+ {
+ if (h->got.refcount == 0)
+ {
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1 && !h->forced_local)
+ {
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
- return (entry->symndx == -1
- ? (long) entry->d.h->root.root.hash
- : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
-}
+ /* Allocate space in the .got section. */
+ sgot->size += 4;
+ /* Allocate relocation space. */
+ srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ h->got.refcount++;
+ }
+ else
+ {
+ /* This is a global offset table entry for a local symbol. */
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size;
-/* Test whether the key fields of two bfinfdpic_relocs_info entries are
- identical. */
-static int
-bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2)
-{
- const struct bfinfdpic_relocs_info *e1 = entry1;
- const struct bfinfdpic_relocs_info *e2 = entry2;
+ size = symtab_hdr->sh_info;
+ size *= sizeof (bfd_signed_vma);
+ local_got_refcounts = ((bfd_signed_vma *)
+ bfd_zalloc (abfd, size));
+ if (local_got_refcounts == NULL)
+ return FALSE;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ }
+ if (local_got_refcounts[r_symndx] == 0)
+ {
+ sgot->size += 4;
+ if (info->shared)
+ {
+ /* If we are generating a shared object, we need to
+ output a R_68K_RELATIVE reloc so that the dynamic
+ linker can adjust this GOT entry. */
+ srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ }
+ local_got_refcounts[r_symndx]++;
+ }
+ break;
- return e1->symndx == e2->symndx && e1->addend == e2->addend
- && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
}
-/* Find or create an entry in a hash table HT that matches the key
- fields of the given ENTRY. If it's not found, memory for a new
- entry is allocated in ABFD's obstack. */
-static struct bfinfdpic_relocs_info *
-bfinfdpic_relocs_info_find (struct htab *ht,
- bfd *abfd,
- const struct bfinfdpic_relocs_info *entry,
- enum insert_option insert)
+static enum elf_reloc_type_class
+elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
{
- struct bfinfdpic_relocs_info **loc =
- (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
+ switch ((int) ELF32_R_TYPE (rela->r_info))
+ {
+ default:
+ return reloc_class_normal;
+ }
+}
+\f
+static bfd_reloc_status_type
+bfin_final_link_relocate (Elf_Internal_Rela *rel, reloc_howto_type *howto,
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents, bfd_vma address,
+ bfd_vma value, bfd_vma addend)
+{
+ int r_type = ELF32_R_TYPE (rel->r_info);
- if (! loc)
- return NULL;
+ if (r_type == R_pcrel24 || r_type == R_pcrel24_jump_l)
+ {
+ bfd_reloc_status_type r = bfd_reloc_ok;
+ bfd_vma x;
- if (*loc)
- return *loc;
+ if (address > bfd_get_section_limit (input_bfd, input_section))
+ return bfd_reloc_outofrange;
- *loc = bfd_zalloc (abfd, sizeof (**loc));
+ value += addend;
- if (! *loc)
- return *loc;
+ /* Perform usual pc-relative correction. */
+ value -= input_section->output_section->vma + input_section->output_offset;
+ value -= address;
- (*loc)->symndx = entry->symndx;
- (*loc)->d = entry->d;
- (*loc)->addend = entry->addend;
- (*loc)->plt_entry = (bfd_vma)-1;
- (*loc)->lzplt_entry = (bfd_vma)-1;
+ /* We are getting reloc_entry->address 2 byte off from
+ the start of instruction. Assuming absolute postion
+ of the reloc data. But, following code had been written assuming
+ reloc address is starting at begining of instruction.
+ To compensate that I have increased the value of
+ relocation by 1 (effectively 2) and used the addr -2 instead of addr. */
- return *loc;
-}
+ value += 2;
+ address -= 2;
-/* Obtain the address of the entry in HT associated with H's symbol +
- addend, creating a new entry if none existed. ABFD is only used
- for memory allocation purposes. */
-inline static struct bfinfdpic_relocs_info *
-bfinfdpic_relocs_info_for_global (struct htab *ht,
- bfd *abfd,
- struct elf_link_hash_entry *h,
- bfd_vma addend,
- enum insert_option insert)
-{
- struct bfinfdpic_relocs_info entry;
+ if ((value & 0xFF000000) != 0
+ && (value & 0xFF000000) != 0xFF000000)
+ r = bfd_reloc_overflow;
- entry.symndx = -1;
- entry.d.h = h;
- entry.addend = addend;
+ value >>= 1;
- return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
-}
+ x = bfd_get_16 (input_bfd, contents + address);
+ x = (x & 0xff00) | ((value >> 16) & 0xff);
+ bfd_put_16 (input_bfd, x, contents + address);
-/* Obtain the address of the entry in HT associated with the SYMNDXth
- local symbol of the input bfd ABFD, plus the addend, creating a new
- entry if none existed. */
-inline static struct bfinfdpic_relocs_info *
-bfinfdpic_relocs_info_for_local (struct htab *ht,
- bfd *abfd,
- long symndx,
- bfd_vma addend,
- enum insert_option insert)
-{
- struct bfinfdpic_relocs_info entry;
+ x = bfd_get_16 (input_bfd, contents + address + 2);
+ x = value & 0xFFFF;
+ bfd_put_16 (input_bfd, x, contents + address + 2);
+ return r;
+ }
- entry.symndx = symndx;
- entry.d.abfd = abfd;
- entry.addend = addend;
+ return _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, value, addend);
- return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
}
-/* Merge fields set by check_relocs() of two entries that end up being
- mapped to the same (presumably global) symbol. */
-
-inline static void
-bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2,
- struct bfinfdpic_relocs_info const *e1)
+static bfd_boolean
+bfin_relocate_section (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)
{
- e2->got17m4 |= e1->got17m4;
- e2->gothilo |= e1->gothilo;
- e2->fd |= e1->fd;
- e2->fdgot17m4 |= e1->fdgot17m4;
- e2->fdgothilo |= e1->fdgothilo;
- e2->fdgoff17m4 |= e1->fdgoff17m4;
- e2->fdgoffhilo |= e1->fdgoffhilo;
- e2->gotoff |= e1->gotoff;
- e2->call |= e1->call;
- e2->sym |= e1->sym;
-}
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_vma *local_got_offsets;
+ asection *sgot;
+ asection *sreloc;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ int i = 0;
-/* Every block of 65535 lazy PLT entries shares a single call to the
- resolver, inserted in the 32768th lazy PLT entry (i.e., entry #
- 32767, counting from 0). All other lazy PLT entries branch to it
- in a single instruction. */
+ 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);
-#define LZPLT_RESOLVER_EXTRA 10
-#define LZPLT_NORMAL_SIZE 6
-#define LZPLT_ENTRIES 1362
+ sgot = NULL;
+ sreloc = NULL;
-#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA)
-#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2)
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++, i++)
+ {
+ 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 = 0;
+ bfd_boolean unresolved_reloc;
+ bfd_reloc_status_type r;
+ bfd_vma address;
-/* Add a dynamic relocation to the SRELOC section. */
+ r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type < 0 || r_type >= 243)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
-inline static bfd_vma
-_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
- int reloc_type, long dynindx, bfd_vma addend,
- struct bfinfdpic_relocs_info *entry)
-{
- Elf_Internal_Rela outrel;
- bfd_vma reloc_offset;
+ if (r_type == R_BFIN_GNU_VTENTRY
+ || r_type == R_BFIN_GNU_VTINHERIT)
+ continue;
- outrel.r_offset = offset;
- outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
- outrel.r_addend = addend;
+ howto = bfin_reloc_type_lookup (input_bfd, r_type);
+ if (howto == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ r_symndx = ELF32_R_SYM (rel->r_info);
- reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
- BFD_ASSERT (reloc_offset < sreloc->size);
- bfd_elf32_swap_reloc_out (output_bfd, &outrel,
- sreloc->contents + reloc_offset);
- sreloc->reloc_count++;
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+ unresolved_reloc = FALSE;
- /* If the entry's index is zero, this relocation was probably to a
- linkonce section that got discarded. We reserved a dynamic
- relocation, but it was for another entry than the one we got at
- the time of emitting the relocation. Unfortunately there's no
- simple way for us to catch this situation, since the relocation
- is cleared right before calling relocate_section, at which point
- we no longer know what the relocation used to point to. */
- if (entry->symndx)
- {
- BFD_ASSERT (entry->dynrelocs > 0);
- entry->dynrelocs--;
- }
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ sec = local_sections[r_symndx];
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+ }
+ else
+ {
+ bfd_boolean warned;
- return reloc_offset;
-}
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation,
+ unresolved_reloc, warned);
+ }
-/* Add a fixup to the ROFIXUP section. */
+ 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;
+ }
-static bfd_vma
-_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
- struct bfinfdpic_relocs_info *entry)
-{
- bfd_vma fixup_offset;
+ if (info->relocatable)
+ continue;
- if (rofixup->flags & SEC_EXCLUDE)
- return -1;
+ address = rel->r_offset;
- fixup_offset = rofixup->reloc_count * 4;
- if (rofixup->contents)
- {
- BFD_ASSERT (fixup_offset < rofixup->size);
- bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
- }
- rofixup->reloc_count++;
+ /* Then, process normally. */
+ switch (r_type)
+ {
+ case R_BFIN_GNU_VTINHERIT:
+ case R_BFIN_GNU_VTENTRY:
+ return bfd_reloc_ok;
- if (entry && entry->symndx)
- {
- /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
- above. */
- BFD_ASSERT (entry->fixups > 0);
- entry->fixups--;
- }
+ case R_got:
+ /* Relocation is to the address of the entry for this symbol
+ in the global offset table. */
+ if (h != NULL
+ && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
+ goto do_default;
+ /* Fall through. */
+ /* Relocation is the offset of the entry for this symbol in
+ the global offset table. */
- return fixup_offset;
-}
+ {
+ bfd_vma off;
-/* Find the segment number in which OSEC, and output section, is
- located. */
+ if (dynobj == NULL)
+ {
+ /* Create the .got section. */
+ elf_hash_table (info)->dynobj = dynobj = output_bfd;
+ if (!_bfd_elf_create_got_section (dynobj, info))
+ return FALSE;
+ }
-static unsigned
-_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
-{
- Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
- return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
-}
+ if (h != NULL)
+ {
+ bfd_boolean dyn;
-inline static bfd_boolean
-_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
-{
- unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
+ off = h->got.offset;
+ BFD_ASSERT (off != (bfd_vma) - 1);
+ dyn = elf_hash_table (info)->dynamic_sections_created;
- return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
-}
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ || (info->shared
+ && (info->symbolic
+ || h->dynindx == -1
+ || h->forced_local)
+ && h->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 4, we
+ use the least significant bit to record whether
+ we have initialized it already.
-/* Generate relocations for GOT entries, function descriptors, and
- code for PLT and lazy PLT entries. */
+ 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_32 (output_bfd, relocation,
+ sgot->contents + off);
+ h->got.offset |= 1;
+ }
+ }
+ else
+ unresolved_reloc = FALSE;
+ }
+ else
+ {
+ BFD_ASSERT (local_got_offsets != NULL);
+ off = local_got_offsets[r_symndx];
+ BFD_ASSERT (off != (bfd_vma) - 1);
-inline static bfd_boolean
-_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
- bfd *output_bfd,
- struct bfd_link_info *info,
- asection *sec,
- Elf_Internal_Sym *sym,
- bfd_vma addend)
+ /* The offset must always be a multiple of 4. We use
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
-{
- bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
- int dynindx = -1;
+ if (info->shared)
+ {
+ asection *s;
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
- if (entry->done)
- return TRUE;
- entry->done = 1;
+ s = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (s != NULL);
- if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
- {
- /* If the symbol is dynamic, consider it for dynamic
- relocations, otherwise decay to section + offset. */
- if (entry->symndx == -1 && entry->d.h->dynindx != -1)
- dynindx = entry->d.h->dynindx;
- else
- {
- if (sec->output_section
- && ! bfd_is_abs_section (sec->output_section)
- && ! bfd_is_und_section (sec->output_section))
- dynindx = elf_section_data (sec->output_section)->dynindx;
- else
- dynindx = 0;
- }
- }
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset + off);
+ outrel.r_info =
+ ELF32_R_INFO (0, R_pcrel24);
+ outrel.r_addend = relocation;
+ loc = s->contents;
+ loc +=
+ s->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
- /* Generate relocation for GOT entry pointing to the symbol. */
- if (entry->got_entry)
- {
- int idx = dynindx;
- bfd_vma ad = addend;
+ local_got_offsets[r_symndx] |= 1;
+ }
+ }
- /* If the symbol is dynamic but binds locally, use
- section+offset. */
- if (sec && (entry->symndx != -1
- || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
- {
- if (entry->symndx == -1)
- ad += entry->d.h->root.u.def.value;
- else
- ad += sym->st_value;
- ad += sec->output_offset;
- if (sec->output_section && elf_section_data (sec->output_section))
- idx = elf_section_data (sec->output_section)->dynindx;
- else
- idx = 0;
+ relocation = sgot->output_offset + off;
+ rel->r_addend = 0;
+ /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */
+ relocation /= 4;
+ }
+ goto do_default;
+
+ default:
+ do_default:
+ r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
+ contents, address,
+ relocation, rel->r_addend);
+
+ break;
}
- /* If we're linking an executable at a fixed address, we can
- omit the dynamic relocation as long as the symbol is local to
- this module. */
- if (info->executable && !info->pie
- && (entry->symndx != -1
- || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
+ if (unresolved_reloc
+ && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic))
{
- if (sec)
- ad += sec->output_section->vma;
- if (entry->symndx != -1
- || entry->d.h->root.type != bfd_link_hash_undefweak)
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section (info),
- bfinfdpic_got_section (info)->output_section
- ->vma
- + bfinfdpic_got_section (info)->output_offset
- + bfinfdpic_got_initial_offset (info)
- + entry->got_entry, entry);
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+ input_bfd,
+ input_section, (long) rel->r_offset, h->root.root.string);
+ return FALSE;
}
- else
- _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info),
- _bfd_elf_section_offset
- (output_bfd, info,
- bfinfdpic_got_section (info),
- bfinfdpic_got_initial_offset (info)
- + entry->got_entry)
- + bfinfdpic_got_section (info)
- ->output_section->vma
- + bfinfdpic_got_section (info)->output_offset,
- R_byte4_data, idx, ad, entry);
-
- bfd_put_32 (output_bfd, ad,
- bfinfdpic_got_section (info)->contents
- + bfinfdpic_got_initial_offset (info)
- + entry->got_entry);
- }
-
- /* Generate relocation for GOT entry pointing to a canonical
- function descriptor. */
- if (entry->fdgot_entry)
- {
- int reloc, idx;
- bfd_vma ad = 0;
- if (! (entry->symndx == -1
- && entry->d.h->root.type == bfd_link_hash_undefweak
- && BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+ if (r != bfd_reloc_ok)
{
- /* 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 (entry->symndx == -1
- && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)
- && BFINFDPIC_SYM_LOCAL (info, entry->d.h)
- && !(info->executable && !info->pie))
+ const char *name;
+
+ if (h != NULL)
+ name = h->root.root.string;
+ else
{
- reloc = R_BFIN_FUNCDESC;
- idx = elf_section_data (entry->d.h->root.u.def.section
- ->output_section)->dynindx;
- ad = entry->d.h->root.u.def.section->output_offset
- + entry->d.h->root.u.def.value;
+ 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);
}
- else if (entry->symndx == -1
- && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))
+
+ if (r == bfd_reloc_overflow)
{
- reloc = R_BFIN_FUNCDESC;
- idx = dynindx;
- ad = addend;
- if (ad)
+ if (!(info->callbacks->reloc_overflow
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
return FALSE;
}
else
{
- /* Otherwise, we know we have a private function descriptor,
- so reference it directly. */
- if (elf_hash_table (info)->dynamic_sections_created)
- BFD_ASSERT (entry->privfd);
- reloc = R_byte4_data;
- idx = elf_section_data (bfinfdpic_got_section (info)
- ->output_section)->dynindx;
- ad = bfinfdpic_got_section (info)->output_offset
- + bfinfdpic_got_initial_offset (info) + entry->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
- && (entry->symndx != -1
- || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)))
- {
- ad += bfinfdpic_got_section (info)->output_section->vma;
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section (info),
- bfinfdpic_got_section (info)
- ->output_section->vma
- + bfinfdpic_got_section (info)
- ->output_offset
- + bfinfdpic_got_initial_offset (info)
- + entry->fdgot_entry, entry);
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): reloc against `%s': error %d"),
+ input_bfd, input_section,
+ (long) rel->r_offset, name, (int) r);
+ return FALSE;
}
- else
- _bfinfdpic_add_dyn_reloc (output_bfd,
- bfinfdpic_gotrel_section (info),
- _bfd_elf_section_offset
- (output_bfd, info,
- bfinfdpic_got_section (info),
- bfinfdpic_got_initial_offset (info)
- + entry->fdgot_entry)
- + bfinfdpic_got_section (info)
- ->output_section->vma
- + bfinfdpic_got_section (info)
- ->output_offset,
- reloc, idx, ad, entry);
}
-
- bfd_put_32 (output_bfd, ad,
- bfinfdpic_got_section (info)->contents
- + bfinfdpic_got_initial_offset (info)
- + entry->fdgot_entry);
}
- /* Generate relocation to fill in a private function descriptor in
- the GOT. */
- if (entry->fd_entry)
- {
- int idx = dynindx;
- bfd_vma ad = addend;
- bfd_vma ofst;
- long lowword, highword;
+ return TRUE;
+}
- /* If the symbol is dynamic but binds locally, use
- section+offset. */
- if (sec && (entry->symndx != -1
- || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
- {
- if (entry->symndx == -1)
- ad += entry->d.h->root.u.def.value;
- else
- ad += sym->st_value;
- ad += sec->output_offset;
- if (sec->output_section && elf_section_data (sec->output_section))
- idx = elf_section_data (sec->output_section)->dynindx;
- else
- idx = 0;
- }
+static asection *
+bfin_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_BFIN_GNU_VTINHERIT:
+ case R_BFIN_GNU_VTENTRY:
+ return NULL;
+ }
- /* If we're linking an executable at a fixed address, we can
- omit the dynamic relocation as long as the symbol is local to
- this module. */
- if (info->executable && !info->pie
- && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
- {
- if (sec)
- ad += sec->output_section->vma;
- ofst = 0;
- if (entry->symndx != -1
- || entry->d.h->root.type != bfd_link_hash_undefweak)
- {
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section (info),
- bfinfdpic_got_section (info)
- ->output_section->vma
- + bfinfdpic_got_section (info)
- ->output_offset
- + bfinfdpic_got_initial_offset (info)
- + entry->fd_entry, entry);
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section (info),
- bfinfdpic_got_section (info)
- ->output_section->vma
- + bfinfdpic_got_section (info)
- ->output_offset
- + bfinfdpic_got_initial_offset (info)
- + entry->fd_entry + 4, entry);
- }
- }
- else
- {
- ofst
- = _bfinfdpic_add_dyn_reloc (output_bfd,
- entry->lazyplt
- ? bfinfdpic_pltrel_section (info)
- : bfinfdpic_gotrel_section (info),
- _bfd_elf_section_offset
- (output_bfd, info,
- bfinfdpic_got_section (info),
- bfinfdpic_got_initial_offset (info)
- + entry->fd_entry)
- + bfinfdpic_got_section (info)
- ->output_section->vma
- + bfinfdpic_got_section (info)
- ->output_offset,
- R_BFIN_FUNCDESC_VALUE, idx, ad, entry);
- }
+ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
- /* 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 && sec && sec->output_section)
- {
- lowword = ad;
- highword = bfinfdpic_got_section (info)->output_section->vma
- + bfinfdpic_got_section (info)->output_offset
- + bfinfdpic_got_initial_offset (info);
- }
- else if (entry->lazyplt)
- {
- if (ad)
- return FALSE;
+/* Update the got entry reference counts for the section being removed. */
- fd_lazy_rel_offset = ofst;
+static bfd_boolean
+bfin_gc_sweep_hook (bfd * abfd,
+ struct bfd_link_info *info,
+ asection * sec,
+ const Elf_Internal_Rela * relocs)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel, *relend;
+ bfd *dynobj;
+ asection *sgot;
+ asection *srelgot;
- /* 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 address of the lazy PLT entry
- entry point, that must be within the memory region
- assigned to that section. */
- lowword = entry->lzplt_entry + 4
- + bfinfdpic_plt_section (info)->output_offset
- + bfinfdpic_plt_section (info)->output_section->vma;
- highword = _bfinfdpic_osec_to_segment
- (output_bfd, bfinfdpic_plt_section (info)->output_section);
- }
- else
- {
- /* A function descriptor for a local function gets the index
- of the section. For a non-local function, it's
- disregarded. */
- lowword = ad;
- if (entry->symndx == -1 && entry->d.h->dynindx != -1
- && entry->d.h->dynindx == idx)
- highword = 0;
- else
- highword = _bfinfdpic_osec_to_segment
- (output_bfd, sec->output_section);
- }
-
- bfd_put_32 (output_bfd, lowword,
- bfinfdpic_got_section (info)->contents
- + bfinfdpic_got_initial_offset (info)
- + entry->fd_entry);
- bfd_put_32 (output_bfd, highword,
- bfinfdpic_got_section (info)->contents
- + bfinfdpic_got_initial_offset (info)
- + entry->fd_entry + 4);
- }
-
- /* Generate code for the PLT entry. */
- if (entry->plt_entry != (bfd_vma) -1)
- {
- bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents
- + entry->plt_entry;
-
- BFD_ASSERT (entry->fd_entry);
-
- /* Figure out what kind of PLT entry we need, depending on the
- location of the function descriptor within the GOT. */
- if (entry->fd_entry >= -(1 << (18 - 1))
- && entry->fd_entry + 4 < (1 << (18 - 1)))
- {
- /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */
- bfd_put_32 (output_bfd,
- 0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000),
- plt_code);
- bfd_put_32 (output_bfd,
- 0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000),
- plt_code + 4);
- plt_code += 8;
- }
- else
- {
- /* P1.L = fd_entry; P1.H = fd_entry;
- P3 = P3 + P1;
- P1 = [P3];
- P3 = [P3 + 4]; */
- bfd_put_32 (output_bfd,
- 0xe109 | (entry->fd_entry << 16),
- plt_code);
- bfd_put_32 (output_bfd,
- 0xe149 | (entry->fd_entry & 0xFFFF0000),
- plt_code + 4);
- bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8);
- bfd_put_16 (output_bfd, 0x9159, plt_code + 10);
- bfd_put_16 (output_bfd, 0xac5b, plt_code + 12);
- plt_code += 14;
- }
- /* JUMP (P1) */
- bfd_put_16 (output_bfd, 0x0051, plt_code);
- }
-
- /* Generate code for the lazy PLT entry. */
- if (entry->lzplt_entry != (bfd_vma) -1)
- {
- bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
- + entry->lzplt_entry;
- bfd_vma resolverStub_addr;
-
- bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code);
- lzplt_code += 4;
-
- resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE
- * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC;
- if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info))
- resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA;
-
- if (entry->lzplt_entry == resolverStub_addr)
- {
- /* This is a lazy PLT entry that includes a resolver call.
- P2 = [P3];
- R3 = [P3 + 4];
- JUMP (P2); */
- bfd_put_32 (output_bfd,
- 0xa05b915a,
- lzplt_code);
- bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4);
- }
- else
- {
- /* JUMP.S resolverStub */
- bfd_put_16 (output_bfd,
- 0x2000
- | (((resolverStub_addr - entry->lzplt_entry)
- / 2) & (((bfd_vma)1 << 12) - 1)),
- lzplt_code);
- }
- }
-
- return TRUE;
-}
-
-
-/* Look through the relocs for a section during the first phase, and
- allocate space in the global offset table or procedure linkage
- table. */
-
-static bfd_boolean
-bfin_check_relocs (bfd * abfd,
- struct bfd_link_info *info,
- asection *sec,
- const Elf_Internal_Rela *relocs)
-{
- bfd *dynobj;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- bfd_signed_vma *local_got_refcounts;
- const Elf_Internal_Rela *rel;
- const Elf_Internal_Rela *rel_end;
- asection *sgot;
- asection *srelgot;
- asection *sreloc;
- if (info->relocatable)
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj == NULL)
return TRUE;
- dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
- sgot = NULL;
- srelgot = NULL;
- sreloc = NULL;
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
- rel_end = relocs + sec->reloc_count;
- for (rel = relocs; rel < rel_end; rel++)
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
{
unsigned long r_symndx;
struct elf_link_hash_entry *h;
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx < symtab_hdr->sh_info)
- h = NULL;
- else
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-
switch (ELF32_R_TYPE (rel->r_info))
{
- /* This relocation describes the C++ object vtable hierarchy.
- Reconstruct it for later use during GC. */
- case R_BFIN_GNU_VTINHERIT:
- if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
- return FALSE;
- break;
-
- /* This relocation describes which C++ vtable entries
- are actually used. Record for later use during GC. */
- case R_BFIN_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
- return FALSE;
- break;
-
case R_got:
- if (h != NULL
- && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
- break;
- /* Fall through. */
-
- if (dynobj == NULL)
- {
- /* Create the .got section. */
- elf_hash_table (info)->dynobj = dynobj = abfd;
- if (!_bfd_elf_create_got_section (dynobj, info))
- return FALSE;
- }
-
- if (sgot == NULL)
- {
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
- }
-
- if (srelgot == NULL && (h != NULL || info->shared))
- {
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
- if (srelgot == NULL)
- {
- flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED
- | SEC_READONLY);
- srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
- flags);
- if (srelgot == NULL
- || !bfd_set_section_alignment (dynobj, srelgot, 2))
- return FALSE;
- }
- }
-
- if (h != NULL)
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
{
- if (h->got.refcount == 0)
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ if (h->got.refcount > 0)
{
- /* Make sure this symbol is output as a dynamic symbol. */
- if (h->dynindx == -1 && !h->forced_local)
+ --h->got.refcount;
+ if (h->got.refcount == 0)
{
- if (!bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ /* We don't need the .got entry any more. */
+ sgot->size -= 4;
+ srelgot->size -= sizeof (Elf32_External_Rela);
}
-
- /* Allocate space in the .got section. */
- sgot->size += 4;
- /* Allocate relocation space. */
- srelgot->size += sizeof (Elf32_External_Rela);
}
- h->got.refcount++;
}
- else
+ else if (local_got_refcounts != NULL)
{
- /* This is a global offset table entry for a local symbol. */
- if (local_got_refcounts == NULL)
- {
- bfd_size_type size;
-
- size = symtab_hdr->sh_info;
- size *= sizeof (bfd_signed_vma);
- local_got_refcounts = ((bfd_signed_vma *)
- bfd_zalloc (abfd, size));
- if (local_got_refcounts == NULL)
- return FALSE;
- elf_local_got_refcounts (abfd) = local_got_refcounts;
- }
- if (local_got_refcounts[r_symndx] == 0)
+ if (local_got_refcounts[r_symndx] > 0)
{
- sgot->size += 4;
- if (info->shared)
+ --local_got_refcounts[r_symndx];
+ if (local_got_refcounts[r_symndx] == 0)
{
- /* If we are generating a shared object, we need to
- output a R_68K_RELATIVE reloc so that the dynamic
- linker can adjust this GOT entry. */
- srelgot->size += sizeof (Elf32_External_Rela);
+ /* We don't need the .got entry any more. */
+ sgot->size -= 4;
+ if (info->shared)
+ srelgot->size -= sizeof (Elf32_External_Rela);
}
}
- local_got_refcounts[r_symndx]++;
}
break;
-
default:
break;
}
}
-
return TRUE;
}
+\f
+extern const bfd_target bfd_elf32_bfinfdpic_vec;
+#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec)
-static enum elf_reloc_type_class
-elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
-{
- switch ((int) ELF32_R_TYPE (rela->r_info))
- {
- default:
- return reloc_class_normal;
- }
-}
-\f
-static bfd_reloc_status_type
-bfin_final_link_relocate (Elf_Internal_Rela *rel, reloc_howto_type *howto,
- bfd *input_bfd, asection *input_section,
- bfd_byte *contents, bfd_vma address,
- bfd_vma value, bfd_vma addend)
+/* An extension of the elf hash table data structure, containing some
+ additional Blackfin-specific data. */
+struct bfinfdpic_elf_link_hash_table
{
- int r_type = ELF32_R_TYPE (rel->r_info);
+ struct elf_link_hash_table elf;
- if (r_type == R_pcrel24 || r_type == R_pcrel24_jump_l)
- {
- bfd_reloc_status_type r = bfd_reloc_ok;
- bfd_vma x;
+ /* A pointer to the .got section. */
+ asection *sgot;
+ /* A pointer to the .rel.got section. */
+ asection *sgotrel;
+ /* A pointer to the .rofixup section. */
+ asection *sgotfixup;
+ /* A pointer to the .plt section. */
+ asection *splt;
+ /* A pointer to the .rel.plt section. */
+ asection *spltrel;
+ /* GOT base offset. */
+ bfd_vma got0;
+ /* Location of the first non-lazy PLT entry, i.e., the number of
+ bytes taken by lazy PLT entries. */
+ bfd_vma plt0;
+ /* A hash table holding information about which symbols were
+ referenced with which PIC-related relocations. */
+ struct htab *relocs_info;
+};
- if (address > bfd_get_section_limit (input_bfd, input_section))
- return bfd_reloc_outofrange;
+/* Get the Blackfin ELF linker hash table from a link_info structure. */
- value += addend;
+#define bfinfdpic_hash_table(info) \
+ ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
- /* Perform usual pc-relative correction. */
- value -= input_section->output_section->vma + input_section->output_offset;
- value -= address;
+#define bfinfdpic_got_section(info) \
+ (bfinfdpic_hash_table (info)->sgot)
+#define bfinfdpic_gotrel_section(info) \
+ (bfinfdpic_hash_table (info)->sgotrel)
+#define bfinfdpic_gotfixup_section(info) \
+ (bfinfdpic_hash_table (info)->sgotfixup)
+#define bfinfdpic_plt_section(info) \
+ (bfinfdpic_hash_table (info)->splt)
+#define bfinfdpic_pltrel_section(info) \
+ (bfinfdpic_hash_table (info)->spltrel)
+#define bfinfdpic_relocs_info(info) \
+ (bfinfdpic_hash_table (info)->relocs_info)
+#define bfinfdpic_got_initial_offset(info) \
+ (bfinfdpic_hash_table (info)->got0)
+#define bfinfdpic_plt_initial_offset(info) \
+ (bfinfdpic_hash_table (info)->plt0)
- /* We are getting reloc_entry->address 2 byte off from
- the start of instruction. Assuming absolute postion
- of the reloc data. But, following code had been written assuming
- reloc address is starting at begining of instruction.
- To compensate that I have increased the value of
- relocation by 1 (effectively 2) and used the addr -2 instead of addr. */
+/* The name of the dynamic interpreter. This is put in the .interp
+ section. */
- value += 2;
- address -= 2;
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
- if ((value & 0xFF000000) != 0
- && (value & 0xFF000000) != 0xFF000000)
- r = bfd_reloc_overflow;
+#define DEFAULT_STACK_SIZE 0x20000
- value >>= 1;
+/* This structure is used to collect the number of entries present in
+ each addressable range of the got. */
+struct _bfinfdpic_dynamic_got_info
+{
+ /* Several bits of information about the current link. */
+ struct bfd_link_info *info;
+ /* Total size needed for GOT entries within the 18- or 32-bit
+ ranges. */
+ bfd_vma got17m4, gothilo;
+ /* Total size needed for function descriptor entries within the 18-
+ or 32-bit ranges. */
+ bfd_vma fd17m4, fdhilo;
+ /* Total size needed function descriptor entries referenced in PLT
+ entries, that would be profitable to place in offsets close to
+ the PIC register. */
+ bfd_vma fdplt;
+ /* Total size needed by lazy PLT entries. */
+ bfd_vma lzplt;
+ /* Number of relocations carried over from input object files. */
+ unsigned long relocs;
+ /* Number of fixups introduced by relocations in input object files. */
+ unsigned long fixups;
+};
- x = bfd_get_16 (input_bfd, contents + address);
- x = (x & 0xff00) | ((value >> 16) & 0xff);
- bfd_put_16 (input_bfd, x, contents + address);
+/* Create a Blackfin ELF linker hash table. */
- x = bfd_get_16 (input_bfd, contents + address + 2);
- x = value & 0xFFFF;
- bfd_put_16 (input_bfd, x, contents + address + 2);
- return r;
- }
+static struct bfd_link_hash_table *
+bfinfdpic_elf_link_hash_table_create (bfd *abfd)
+{
+ struct bfinfdpic_elf_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
- return _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, value, addend);
+ ret = bfd_zalloc (abfd, amt);
+ if (ret == NULL)
+ return NULL;
-}
+ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
+ _bfd_elf_link_hash_newfunc,
+ sizeof (struct elf_link_hash_entry)))
+ {
+ free (ret);
+ return NULL;
+ }
-\f
-/* Relocate an Blackfin ELF section.
+ return &ret->elf.root;
+}
- The RELOCATE_SECTION function is called by the new ELF backend linker
- to handle the relocations for a section.
+/* Decide whether a reference to a symbol can be resolved locally or
+ not. If the symbol is protected, we want the local address, but
+ its function descriptor must be assigned by the dynamic linker. */
+#define BFINFDPIC_SYM_LOCAL(INFO, H) \
+ (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
+ || ! elf_hash_table (INFO)->dynamic_sections_created)
+#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \
+ ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
- The relocs are always passed as Rela structures; if the section
- actually uses Rel structures, the r_addend field will always be
- zero.
+/* This structure collects information on what kind of GOT, PLT or
+ function descriptors are required by relocations that reference a
+ certain symbol. */
+struct bfinfdpic_relocs_info
+{
+ /* The index of the symbol, as stored in the relocation r_info, if
+ we have a local symbol; -1 otherwise. */
+ long symndx;
+ union
+ {
+ /* The input bfd in which the symbol is defined, if it's a local
+ symbol. */
+ bfd *abfd;
+ /* If symndx == -1, the hash table entry corresponding to a global
+ symbol (even if it turns out to bind locally, in which case it
+ should ideally be replaced with section's symndx + addend). */
+ struct elf_link_hash_entry *h;
+ } d;
+ /* The addend of the relocation that references the symbol. */
+ bfd_vma addend;
- 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.
+ /* The fields above are used to identify an entry. The fields below
+ contain information on how an entry is used and, later on, which
+ locations it was assigned. */
+ /* The following 2 fields record whether the symbol+addend above was
+ ever referenced with a GOT relocation. The 17M4 suffix indicates a
+ GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs. */
+ unsigned got17m4;
+ unsigned gothilo;
+ /* Whether a FUNCDESC relocation references symbol+addend. */
+ unsigned fd;
+ /* Whether a FUNCDESC_GOT relocation references symbol+addend. */
+ unsigned fdgot17m4;
+ unsigned fdgothilo;
+ /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */
+ unsigned fdgoff17m4;
+ unsigned fdgoffhilo;
+ /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or
+ GOTOFFHI relocations. The addend doesn't really matter, since we
+ envision that this will only be used to check whether the symbol
+ is mapped to the same segment as the got. */
+ unsigned gotoff;
+ /* Whether symbol+addend is referenced by a LABEL24 relocation. */
+ unsigned call;
+ /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE
+ relocation. */
+ unsigned sym;
+ /* Whether we need a PLT entry for a symbol. Should be implied by
+ something like:
+ (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)) */
+ unsigned plt:1;
+ /* Whether a function descriptor should be created in this link unit
+ for symbol+addend. Should be implied by something like:
+ (plt || fdgotoff17m4 || fdgotofflohi
+ || ((fd || fdgot17m4 || fdgothilo)
+ && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h)))) */
+ unsigned privfd:1;
+ /* Whether a lazy PLT entry is needed for this symbol+addend.
+ Should be implied by something like:
+ (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)
+ && ! (info->flags & DF_BIND_NOW)) */
+ unsigned lazyplt:1;
+ /* Whether we've already emitted GOT relocations and PLT entries as
+ needed for this symbol. */
+ unsigned done:1;
- This function does not have to worry about setting the reloc
- address or the reloc symbol index.
+ /* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
+ relocations referencing the symbol. */
+ unsigned relocs32, relocsfd, relocsfdv;
- LOCAL_SYMS is a pointer to the swapped in local symbols.
+ /* The number of .rofixups entries and dynamic relocations allocated
+ for this symbol, minus any that might have already been used. */
+ unsigned fixups, dynrelocs;
- LOCAL_SECTIONS is an array giving the section in the input file
- corresponding to the st_shndx field of each local symbol.
+ /* The offsets of the GOT entries assigned to symbol+addend, to the
+ function descriptor's address, and to a function descriptor,
+ respectively. Should be zero if unassigned. The offsets are
+ counted from the value that will be assigned to the PIC register,
+ not from the beginning of the .got section. */
+ bfd_signed_vma got_entry, fdgot_entry, fd_entry;
+ /* The offsets of the PLT entries assigned to symbol+addend,
+ non-lazy and lazy, respectively. If unassigned, should be
+ (bfd_vma)-1. */
+ bfd_vma plt_entry, lzplt_entry;
+};
- The global hash table entry for the global symbols can be found
- via elf_sym_hashes (input_bfd).
+/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry. */
+static hashval_t
+bfinfdpic_relocs_info_hash (const void *entry_)
+{
+ const struct bfinfdpic_relocs_info *entry = entry_;
- 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. */
+ return (entry->symndx == -1
+ ? (long) entry->d.h->root.root.hash
+ : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
+}
-static bfd_boolean
-bfinfdpic_relocate_section (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)
+/* Test whether the key fields of two bfinfdpic_relocs_info entries are
+ identical. */
+static int
+bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2)
{
- 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,
- check_segment[2];
- int silence_segment_error = !(info->shared || info->pie);
+ const struct bfinfdpic_relocs_info *e1 = entry1;
+ const struct bfinfdpic_relocs_info *e2 = entry2;
- symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (input_bfd);
- relend = relocs + input_section->reloc_count;
+ return e1->symndx == e2->symndx && e1->addend == e2->addend
+ && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
+}
- isec_segment = _bfinfdpic_osec_to_segment (output_bfd,
- input_section->output_section);
- if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info))
- got_segment = _bfinfdpic_osec_to_segment (output_bfd,
- bfinfdpic_got_section (info)
- ->output_section);
- else
- got_segment = -1;
- if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created)
- plt_segment = _bfinfdpic_osec_to_segment (output_bfd,
- bfinfdpic_plt_section (info)
- ->output_section);
- else
- plt_segment = -1;
+/* Find or create an entry in a hash table HT that matches the key
+ fields of the given ENTRY. If it's not found, memory for a new
+ entry is allocated in ABFD's obstack. */
+static struct bfinfdpic_relocs_info *
+bfinfdpic_relocs_info_find (struct htab *ht,
+ bfd *abfd,
+ const struct bfinfdpic_relocs_info *entry,
+ enum insert_option insert)
+{
+ struct bfinfdpic_relocs_info **loc =
+ (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
- 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 bfinfdpic_relocs_info *picrel;
- bfd_vma orig_addend = rel->r_addend;
+ if (! loc)
+ return NULL;
- r_type = ELF32_R_TYPE (rel->r_info);
+ if (*loc)
+ return *loc;
- if (r_type == R_BFIN_GNU_VTINHERIT
- || r_type == R_BFIN_GNU_VTENTRY)
- continue;
+ *loc = bfd_zalloc (abfd, sizeof (**loc));
- r_symndx = ELF32_R_SYM (rel->r_info);
- howto = bfin_reloc_type_lookup (input_bfd, r_type);
- if (howto == NULL)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ if (! *loc)
+ return *loc;
- h = NULL;
- sym = NULL;
- sec = NULL;
+ (*loc)->symndx = entry->symndx;
+ (*loc)->d = entry->d;
+ (*loc)->addend = entry->addend;
+ (*loc)->plt_entry = (bfd_vma)-1;
+ (*loc)->lzplt_entry = (bfd_vma)-1;
- 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);
+ return *loc;
+}
- 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;
+/* Obtain the address of the entry in HT associated with H's symbol +
+ addend, creating a new entry if none existed. ABFD is only used
+ for memory allocation purposes. */
+inline static struct bfinfdpic_relocs_info *
+bfinfdpic_relocs_info_for_global (struct htab *ht,
+ bfd *abfd,
+ struct elf_link_hash_entry *h,
+ bfd_vma addend,
+ enum insert_option insert)
+{
+ struct bfinfdpic_relocs_info entry;
- RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
- r_symndx, symtab_hdr, sym_hashes,
- h, sec, relocation,
- unresolved_reloc, warned);
- osec = sec;
- }
+ entry.symndx = -1;
+ entry.d.h = h;
+ entry.addend = addend;
- 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;
- }
+ return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
+}
- if (info->relocatable)
- continue;
+/* Obtain the address of the entry in HT associated with the SYMNDXth
+ local symbol of the input bfd ABFD, plus the addend, creating a new
+ entry if none existed. */
+inline static struct bfinfdpic_relocs_info *
+bfinfdpic_relocs_info_for_local (struct htab *ht,
+ bfd *abfd,
+ long symndx,
+ bfd_vma addend,
+ enum insert_option insert)
+{
+ struct bfinfdpic_relocs_info entry;
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && !BFINFDPIC_SYM_LOCAL (info, h))
- {
- osec = sec = NULL;
- relocation = 0;
- }
+ entry.symndx = symndx;
+ entry.d.abfd = abfd;
+ entry.addend = addend;
- switch (r_type)
- {
- case R_pcrel24:
- case R_pcrel24_jump_l:
- case R_byte4_data:
- if (! IS_FDPIC (output_bfd))
- goto non_fdpic;
+ return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
+}
- case R_BFIN_GOT17M4:
- case R_BFIN_GOTHI:
- case R_BFIN_GOTLO:
- case R_BFIN_FUNCDESC_GOT17M4:
- case R_BFIN_FUNCDESC_GOTHI:
- case R_BFIN_FUNCDESC_GOTLO:
- case R_BFIN_GOTOFF17M4:
- case R_BFIN_GOTOFFHI:
- case R_BFIN_GOTOFFLO:
- case R_BFIN_FUNCDESC_GOTOFF17M4:
- case R_BFIN_FUNCDESC_GOTOFFHI:
- case R_BFIN_FUNCDESC_GOTOFFLO:
- case R_BFIN_FUNCDESC:
- case R_BFIN_FUNCDESC_VALUE:
- if (h != NULL)
- picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_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 = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
- (info), input_bfd, r_symndx,
- orig_addend, INSERT);
- if (! picrel)
- return FALSE;
+/* Merge fields set by check_relocs() of two entries that end up being
+ mapped to the same (presumably global) symbol. */
- if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
- osec, sym,
- rel->r_addend))
- {
- (*_bfd_error_handler)
- (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
- input_bfd, input_section, rel->r_offset, name);
- return FALSE;
+inline static void
+bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2,
+ struct bfinfdpic_relocs_info const *e1)
+{
+ e2->got17m4 |= e1->got17m4;
+ e2->gothilo |= e1->gothilo;
+ e2->fd |= e1->fd;
+ e2->fdgot17m4 |= e1->fdgot17m4;
+ e2->fdgothilo |= e1->fdgothilo;
+ e2->fdgoff17m4 |= e1->fdgoff17m4;
+ e2->fdgoffhilo |= e1->fdgoffhilo;
+ e2->gotoff |= e1->gotoff;
+ e2->call |= e1->call;
+ e2->sym |= e1->sym;
+}
- }
+/* Every block of 65535 lazy PLT entries shares a single call to the
+ resolver, inserted in the 32768th lazy PLT entry (i.e., entry #
+ 32767, counting from 0). All other lazy PLT entries branch to it
+ in a single instruction. */
- break;
+#define LZPLT_RESOLVER_EXTRA 10
+#define LZPLT_NORMAL_SIZE 6
+#define LZPLT_ENTRIES 1362
- default:
- non_fdpic:
- picrel = NULL;
- if (h && ! BFINFDPIC_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;
- }
+#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA)
+#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2)
- switch (r_type)
- {
- case R_pcrel24:
- case R_pcrel24_jump_l:
- check_segment[0] = isec_segment;
- if (! IS_FDPIC (output_bfd))
- check_segment[1] = isec_segment;
- else if (picrel->plt)
- {
- relocation = bfinfdpic_plt_section (info)->output_section->vma
- + bfinfdpic_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
- ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
- : (unsigned)-1;
- break;
+/* Add a dynamic relocation to the SRELOC section. */
- case R_BFIN_GOT17M4:
- case R_BFIN_GOTHI:
- case R_BFIN_GOTLO:
- relocation = picrel->got_entry;
- check_segment[0] = check_segment[1] = got_segment;
- break;
+inline static bfd_vma
+_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
+ int reloc_type, long dynindx, bfd_vma addend,
+ struct bfinfdpic_relocs_info *entry)
+{
+ Elf_Internal_Rela outrel;
+ bfd_vma reloc_offset;
- case R_BFIN_FUNCDESC_GOT17M4:
- case R_BFIN_FUNCDESC_GOTHI:
- case R_BFIN_FUNCDESC_GOTLO:
- relocation = picrel->fdgot_entry;
- check_segment[0] = check_segment[1] = got_segment;
- break;
+ outrel.r_offset = offset;
+ outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
+ outrel.r_addend = addend;
- case R_BFIN_GOTOFFHI:
- case R_BFIN_GOTOFF17M4:
- case R_BFIN_GOTOFFLO:
- relocation -= bfinfdpic_got_section (info)->output_section->vma
- + bfinfdpic_got_section (info)->output_offset
- + bfinfdpic_got_initial_offset (info);
- check_segment[0] = got_segment;
- check_segment[1] = sec
- ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
- : (unsigned)-1;
- break;
+ reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
+ BFD_ASSERT (reloc_offset < sreloc->size);
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel,
+ sreloc->contents + reloc_offset);
+ sreloc->reloc_count++;
- case R_BFIN_FUNCDESC_GOTOFF17M4:
- case R_BFIN_FUNCDESC_GOTOFFHI:
- case R_BFIN_FUNCDESC_GOTOFFLO:
- relocation = picrel->fd_entry;
- check_segment[0] = check_segment[1] = got_segment;
- break;
+ /* If the entry's index is zero, this relocation was probably to a
+ linkonce section that got discarded. We reserved a dynamic
+ relocation, but it was for another entry than the one we got at
+ the time of emitting the relocation. Unfortunately there's no
+ simple way for us to catch this situation, since the relocation
+ is cleared right before calling relocate_section, at which point
+ we no longer know what the relocation used to point to. */
+ if (entry->symndx)
+ {
+ BFD_ASSERT (entry->dynrelocs > 0);
+ entry->dynrelocs--;
+ }
- case R_BFIN_FUNCDESC:
- {
- int dynindx;
- bfd_vma addend = rel->r_addend;
+ return reloc_offset;
+}
- if (! (h && h->root.type == bfd_link_hash_undefweak
- && BFINFDPIC_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 && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)
- && BFINFDPIC_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 && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
- {
- if (addend)
- {
- info->callbacks->warning
- (info, _("R_BFIN_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_byte4_data;
- dynindx = elf_section_data (bfinfdpic_got_section (info)
- ->output_section)->dynindx;
- addend = bfinfdpic_got_section (info)->output_offset
- + bfinfdpic_got_initial_offset (info)
- + picrel->fd_entry;
- }
+/* Add a fixup to the ROFIXUP section. */
- /* 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 || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
- {
- addend += bfinfdpic_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))
- {
- if (_bfinfdpic_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;
- }
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section
- (info),
- _bfd_elf_section_offset
- (output_bfd, info,
- input_section, rel->r_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;
+static bfd_vma
+_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
+ struct bfinfdpic_relocs_info *entry)
+{
+ bfd_vma fixup_offset;
- if (_bfinfdpic_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);
- /* Only output a reloc for a not deleted entry. */
- if (offset >= (bfd_vma) -2)
- _bfinfdpic_add_dyn_reloc (output_bfd,
- bfinfdpic_gotrel_section (info),
- 0,
- R_unused0,
- dynindx, addend, picrel);
- else
- _bfinfdpic_add_dyn_reloc (output_bfd,
- bfinfdpic_gotrel_section (info),
- offset + input_section
- ->output_section->vma
- + input_section->output_offset,
- r_type,
- dynindx, addend, picrel);
- }
- else
- addend += bfinfdpic_got_section (info)->output_section->vma;
- }
+ if (rofixup->flags & SEC_EXCLUDE)
+ return -1;
- /* 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;
+ fixup_offset = rofixup->reloc_count * 4;
+ if (rofixup->contents)
+ {
+ BFD_ASSERT (fixup_offset < rofixup->size);
+ bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
+ }
+ rofixup->reloc_count++;
- case R_byte4_data:
- if (! IS_FDPIC (output_bfd))
- {
- check_segment[0] = check_segment[1] = -1;
- break;
- }
- /* Fall through. */
- case R_BFIN_FUNCDESC_VALUE:
- {
- int dynindx;
- bfd_vma addend = rel->r_addend;
- bfd_vma offset;
- offset = _bfd_elf_section_offset (output_bfd, info,
- input_section, rel->r_offset);
+ if (entry && entry->symndx)
+ {
+ /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
+ above. */
+ BFD_ASSERT (entry->fixups > 0);
+ entry->fixups--;
+ }
- /* If the symbol is dynamic but binds locally, use
- section+offset. */
- if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
- {
- if (addend && r_type == R_BFIN_FUNCDESC_VALUE)
- {
- info->callbacks->warning
- (info, _("R_BFIN_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;
- }
+ return fixup_offset;
+}
- /* 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 || BFINFDPIC_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 (_bfinfdpic_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)
- {
- /* Only output a reloc for a not deleted entry. */
- if (offset >= (bfd_vma)-2)
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section
- (info), -1, picrel);
- else
- _bfinfdpic_add_rofixup (output_bfd,
- bfinfdpic_gotfixup_section
- (info),
- offset + input_section
- ->output_section->vma
- + input_section->output_offset,
- picrel);
+/* Find the segment number in which OSEC, and output section, is
+ located. */
- if (r_type == R_BFIN_FUNCDESC_VALUE)
- {
- if (offset >= (bfd_vma)-2)
- _bfinfdpic_add_rofixup
- (output_bfd,
- bfinfdpic_gotfixup_section (info),
- -1, picrel);
- else
- _bfinfdpic_add_rofixup
- (output_bfd,
- bfinfdpic_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))
- {
- if (_bfinfdpic_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;
- }
- /* Only output a reloc for a not deleted entry. */
- if (offset >= (bfd_vma)-2)
- _bfinfdpic_add_dyn_reloc (output_bfd,
- bfinfdpic_gotrel_section (info),
- 0, R_unused0, dynindx, addend, picrel);
- else
- _bfinfdpic_add_dyn_reloc (output_bfd,
- bfinfdpic_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;
- }
+static unsigned
+_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
+{
+ Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
- if (r_type == R_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2)
- {
- /* 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 || BFINFDPIC_SYM_LOCAL (info, h)))
- bfd_put_32 (output_bfd,
- bfinfdpic_got_section (info)->output_section->vma
- + bfinfdpic_got_section (info)->output_offset
- + bfinfdpic_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 && ! BFINFDPIC_SYM_LOCAL (info, h)
- ? 0
- : _bfinfdpic_osec_to_segment (output_bfd,
- sec
- ->output_section),
- contents + rel->r_offset + 4);
- }
- }
- check_segment[0] = check_segment[1] = got_segment;
- break;
+ return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
+}
+
+inline static bfd_boolean
+_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
+{
+ unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
+
+ return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
+}
+
+/* Generate relocations for GOT entries, function descriptors, and
+ code for PLT and lazy PLT entries. */
+
+inline static bfd_boolean
+_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
+ bfd *output_bfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ Elf_Internal_Sym *sym,
+ bfd_vma addend)
+
+{
+ bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
+ int dynindx = -1;
+
+ if (entry->done)
+ return TRUE;
+ entry->done = 1;
+
+ if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
+ {
+ /* If the symbol is dynamic, consider it for dynamic
+ relocations, otherwise decay to section + offset. */
+ if (entry->symndx == -1 && entry->d.h->dynindx != -1)
+ dynindx = entry->d.h->dynindx;
+ else
+ {
+ if (sec->output_section
+ && ! bfd_is_abs_section (sec->output_section)
+ && ! bfd_is_und_section (sec->output_section))
+ dynindx = elf_section_data (sec->output_section)->dynindx;
+ else
+ dynindx = 0;
+ }
+ }
+
+ /* Generate relocation for GOT entry pointing to the symbol. */
+ if (entry->got_entry)
+ {
+ int idx = dynindx;
+ bfd_vma ad = addend;
+
+ /* If the symbol is dynamic but binds locally, use
+ section+offset. */
+ if (sec && (entry->symndx != -1
+ || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+ {
+ if (entry->symndx == -1)
+ ad += entry->d.h->root.u.def.value;
+ else
+ ad += sym->st_value;
+ ad += sec->output_offset;
+ if (sec->output_section && elf_section_data (sec->output_section))
+ idx = elf_section_data (sec->output_section)->dynindx;
+ else
+ idx = 0;
+ }
+
+ /* If we're linking an executable at a fixed address, we can
+ omit the dynamic relocation as long as the symbol is local to
+ this module. */
+ if (info->executable && !info->pie
+ && (entry->symndx != -1
+ || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+ {
+ if (sec)
+ ad += sec->output_section->vma;
+ if (entry->symndx != -1
+ || entry->d.h->root.type != bfd_link_hash_undefweak)
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section (info),
+ bfinfdpic_got_section (info)->output_section
+ ->vma
+ + bfinfdpic_got_section (info)->output_offset
+ + bfinfdpic_got_initial_offset (info)
+ + entry->got_entry, entry);
+ }
+ else
+ _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info),
+ _bfd_elf_section_offset
+ (output_bfd, info,
+ bfinfdpic_got_section (info),
+ bfinfdpic_got_initial_offset (info)
+ + entry->got_entry)
+ + bfinfdpic_got_section (info)
+ ->output_section->vma
+ + bfinfdpic_got_section (info)->output_offset,
+ R_byte4_data, idx, ad, entry);
+
+ bfd_put_32 (output_bfd, ad,
+ bfinfdpic_got_section (info)->contents
+ + bfinfdpic_got_initial_offset (info)
+ + entry->got_entry);
+ }
+
+ /* Generate relocation for GOT entry pointing to a canonical
+ function descriptor. */
+ if (entry->fdgot_entry)
+ {
+ int reloc, idx;
+ bfd_vma ad = 0;
+
+ if (! (entry->symndx == -1
+ && entry->d.h->root.type == bfd_link_hash_undefweak
+ && BFINFDPIC_SYM_LOCAL (info, entry->d.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 (entry->symndx == -1
+ && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)
+ && BFINFDPIC_SYM_LOCAL (info, entry->d.h)
+ && !(info->executable && !info->pie))
+ {
+ reloc = R_BFIN_FUNCDESC;
+ idx = elf_section_data (entry->d.h->root.u.def.section
+ ->output_section)->dynindx;
+ ad = entry->d.h->root.u.def.section->output_offset
+ + entry->d.h->root.u.def.value;
+ }
+ else if (entry->symndx == -1
+ && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))
+ {
+ reloc = R_BFIN_FUNCDESC;
+ idx = dynindx;
+ ad = addend;
+ if (ad)
+ return FALSE;
+ }
+ else
+ {
+ /* Otherwise, we know we have a private function descriptor,
+ so reference it directly. */
+ if (elf_hash_table (info)->dynamic_sections_created)
+ BFD_ASSERT (entry->privfd);
+ reloc = R_byte4_data;
+ idx = elf_section_data (bfinfdpic_got_section (info)
+ ->output_section)->dynindx;
+ ad = bfinfdpic_got_section (info)->output_offset
+ + bfinfdpic_got_initial_offset (info) + entry->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
+ && (entry->symndx != -1
+ || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)))
+ {
+ ad += bfinfdpic_got_section (info)->output_section->vma;
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section (info),
+ bfinfdpic_got_section (info)
+ ->output_section->vma
+ + bfinfdpic_got_section (info)
+ ->output_offset
+ + bfinfdpic_got_initial_offset (info)
+ + entry->fdgot_entry, entry);
+ }
+ else
+ _bfinfdpic_add_dyn_reloc (output_bfd,
+ bfinfdpic_gotrel_section (info),
+ _bfd_elf_section_offset
+ (output_bfd, info,
+ bfinfdpic_got_section (info),
+ bfinfdpic_got_initial_offset (info)
+ + entry->fdgot_entry)
+ + bfinfdpic_got_section (info)
+ ->output_section->vma
+ + bfinfdpic_got_section (info)
+ ->output_offset,
+ reloc, idx, ad, entry);
+ }
- default:
- check_segment[0] = isec_segment;
- check_segment[1] = sec
- ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
- : (unsigned)-1;
- break;
+ bfd_put_32 (output_bfd, ad,
+ bfinfdpic_got_section (info)->contents
+ + bfinfdpic_got_initial_offset (info)
+ + entry->fdgot_entry);
+ }
+
+ /* Generate relocation to fill in a private function descriptor in
+ the GOT. */
+ if (entry->fd_entry)
+ {
+ int idx = dynindx;
+ bfd_vma ad = addend;
+ bfd_vma ofst;
+ long lowword, highword;
+
+ /* If the symbol is dynamic but binds locally, use
+ section+offset. */
+ if (sec && (entry->symndx != -1
+ || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+ {
+ if (entry->symndx == -1)
+ ad += entry->d.h->root.u.def.value;
+ else
+ ad += sym->st_value;
+ ad += sec->output_offset;
+ if (sec->output_section && elf_section_data (sec->output_section))
+ idx = elf_section_data (sec->output_section)->dynindx;
+ else
+ idx = 0;
}
- if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
+ /* If we're linking an executable at a fixed address, we can
+ omit the dynamic relocation as long as the symbol is local to
+ this module. */
+ if (info->executable && !info->pie
+ && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
{
-#if 1 /* 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;
-#endif
- 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))
- info->callbacks->warning
- (info,
- (info->shared || info->pie)
- ? _("relocations between different segments are not supported")
- : _("warning: 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_BFIN_PIC;
+ if (sec)
+ ad += sec->output_section->vma;
+ ofst = 0;
+ if (entry->symndx != -1
+ || entry->d.h->root.type != bfd_link_hash_undefweak)
+ {
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section (info),
+ bfinfdpic_got_section (info)
+ ->output_section->vma
+ + bfinfdpic_got_section (info)
+ ->output_offset
+ + bfinfdpic_got_initial_offset (info)
+ + entry->fd_entry, entry);
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section (info),
+ bfinfdpic_got_section (info)
+ ->output_section->vma
+ + bfinfdpic_got_section (info)
+ ->output_offset
+ + bfinfdpic_got_initial_offset (info)
+ + entry->fd_entry + 4, entry);
+ }
+ }
+ else
+ {
+ ofst
+ = _bfinfdpic_add_dyn_reloc (output_bfd,
+ entry->lazyplt
+ ? bfinfdpic_pltrel_section (info)
+ : bfinfdpic_gotrel_section (info),
+ _bfd_elf_section_offset
+ (output_bfd, info,
+ bfinfdpic_got_section (info),
+ bfinfdpic_got_initial_offset (info)
+ + entry->fd_entry)
+ + bfinfdpic_got_section (info)
+ ->output_section->vma
+ + bfinfdpic_got_section (info)
+ ->output_offset,
+ R_BFIN_FUNCDESC_VALUE, idx, ad, entry);
}
- switch (r_type)
+ /* 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 && sec && sec->output_section)
{
- case R_BFIN_GOTOFFHI:
- /* We need the addend to be applied before we shift the
- value right. */
- relocation += rel->r_addend;
- /* Fall through. */
- case R_BFIN_GOTHI:
- case R_BFIN_FUNCDESC_GOTHI:
- case R_BFIN_FUNCDESC_GOTOFFHI:
- relocation >>= 16;
- /* Fall through. */
+ lowword = ad;
+ highword = bfinfdpic_got_section (info)->output_section->vma
+ + bfinfdpic_got_section (info)->output_offset
+ + bfinfdpic_got_initial_offset (info);
+ }
+ else if (entry->lazyplt)
+ {
+ if (ad)
+ return FALSE;
- case R_BFIN_GOTLO:
- case R_BFIN_FUNCDESC_GOTLO:
- case R_BFIN_GOTOFFLO:
- case R_BFIN_FUNCDESC_GOTOFFLO:
- relocation &= 0xffff;
- break;
+ fd_lazy_rel_offset = ofst;
- default:
- break;
+ /* 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 address of the lazy PLT entry
+ entry point, that must be within the memory region
+ assigned to that section. */
+ lowword = entry->lzplt_entry + 4
+ + bfinfdpic_plt_section (info)->output_offset
+ + bfinfdpic_plt_section (info)->output_section->vma;
+ highword = _bfinfdpic_osec_to_segment
+ (output_bfd, bfinfdpic_plt_section (info)->output_section);
+ }
+ else
+ {
+ /* A function descriptor for a local function gets the index
+ of the section. For a non-local function, it's
+ disregarded. */
+ lowword = ad;
+ if (entry->symndx == -1 && entry->d.h->dynindx != -1
+ && entry->d.h->dynindx == idx)
+ highword = 0;
+ else
+ highword = _bfinfdpic_osec_to_segment
+ (output_bfd, sec->output_section);
}
- switch (r_type)
+ bfd_put_32 (output_bfd, lowword,
+ bfinfdpic_got_section (info)->contents
+ + bfinfdpic_got_initial_offset (info)
+ + entry->fd_entry);
+ bfd_put_32 (output_bfd, highword,
+ bfinfdpic_got_section (info)->contents
+ + bfinfdpic_got_initial_offset (info)
+ + entry->fd_entry + 4);
+ }
+
+ /* Generate code for the PLT entry. */
+ if (entry->plt_entry != (bfd_vma) -1)
+ {
+ bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents
+ + entry->plt_entry;
+
+ BFD_ASSERT (entry->fd_entry);
+
+ /* Figure out what kind of PLT entry we need, depending on the
+ location of the function descriptor within the GOT. */
+ if (entry->fd_entry >= -(1 << (18 - 1))
+ && entry->fd_entry + 4 < (1 << (18 - 1)))
{
- case R_pcrel24:
- case R_pcrel24_jump_l:
- if (! IS_FDPIC (output_bfd) || ! picrel->plt)
- break;
- /* Fall through. */
+ /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */
+ bfd_put_32 (output_bfd,
+ 0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000),
+ plt_code);
+ bfd_put_32 (output_bfd,
+ 0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000),
+ plt_code + 4);
+ plt_code += 8;
+ }
+ else
+ {
+ /* P1.L = fd_entry; P1.H = fd_entry;
+ P3 = P3 + P1;
+ P1 = [P3];
+ P3 = [P3 + 4]; */
+ bfd_put_32 (output_bfd,
+ 0xe109 | (entry->fd_entry << 16),
+ plt_code);
+ bfd_put_32 (output_bfd,
+ 0xe149 | (entry->fd_entry & 0xFFFF0000),
+ plt_code + 4);
+ bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8);
+ bfd_put_16 (output_bfd, 0x9159, plt_code + 10);
+ bfd_put_16 (output_bfd, 0xac5b, plt_code + 12);
+ plt_code += 14;
+ }
+ /* JUMP (P1) */
+ bfd_put_16 (output_bfd, 0x0051, plt_code);
+ }
- /* 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_BFIN_GOT17M4:
- case R_BFIN_GOTHI:
- case R_BFIN_GOTLO:
- case R_BFIN_FUNCDESC_GOT17M4:
- case R_BFIN_FUNCDESC_GOTHI:
- case R_BFIN_FUNCDESC_GOTLO:
- case R_BFIN_FUNCDESC_GOTOFF17M4:
- case R_BFIN_FUNCDESC_GOTOFFHI:
- case R_BFIN_FUNCDESC_GOTOFFLO:
- /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4
- 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_BFIN_GOTOFFHI:
- relocation -= rel->r_addend;
- break;
+ /* Generate code for the lazy PLT entry. */
+ if (entry->lzplt_entry != (bfd_vma) -1)
+ {
+ bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
+ + entry->lzplt_entry;
+ bfd_vma resolverStub_addr;
- default:
- break;
- }
+ bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code);
+ lzplt_code += 4;
- r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
- contents, rel->r_offset,
- relocation, rel->r_addend);
+ resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE
+ * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC;
+ if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info))
+ resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA;
- if (r != bfd_reloc_ok)
+ if (entry->lzplt_entry == resolverStub_addr)
{
- const char * msg = (const char *) NULL;
+ /* This is a lazy PLT entry that includes a resolver call.
+ P2 = [P3];
+ R3 = [P3 + 4];
+ JUMP (P2); */
+ bfd_put_32 (output_bfd,
+ 0xa05b915a,
+ lzplt_code);
+ bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4);
+ }
+ else
+ {
+ /* JUMP.S resolverStub */
+ bfd_put_16 (output_bfd,
+ 0x2000
+ | (((resolverStub_addr - entry->lzplt_entry)
+ / 2) & (((bfd_vma)1 << 12) - 1)),
+ lzplt_code);
+ }
+ }
- 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;
+ return TRUE;
+}
+\f
+/* Relocate an Blackfin ELF section.
- case bfd_reloc_undefined:
- r = info->callbacks->undefined_symbol
- (info, name, input_bfd, input_section, rel->r_offset, TRUE);
- break;
+ The RELOCATE_SECTION function is called by the new ELF backend linker
+ to handle the relocations for a section.
- case bfd_reloc_outofrange:
- msg = _("internal error: out of range error");
- break;
+ The relocs are always passed as Rela structures; if the section
+ actually uses Rel structures, the r_addend field will always be
+ zero.
- case bfd_reloc_notsupported:
- msg = _("internal error: unsupported relocation error");
- break;
+ 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.
- case bfd_reloc_dangerous:
- msg = _("internal error: dangerous relocation");
- break;
+ This function does not have to worry about setting the reloc
+ address or the reloc symbol index.
- default:
- msg = _("internal error: unknown error");
- break;
- }
+ LOCAL_SYMS is a pointer to the swapped in local symbols.
- if (msg)
- r = info->callbacks->warning
- (info, msg, name, input_bfd, input_section, rel->r_offset);
+ LOCAL_SECTIONS is an array giving the section in the input file
+ corresponding to the st_shndx field of each local symbol.
- if (! r)
- return FALSE;
- }
- }
+ The global hash table entry for the global symbols can be found
+ via elf_sym_hashes (input_bfd).
- return TRUE;
-}
+ 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
-bfin_relocate_section (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)
+bfinfdpic_relocate_section (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;
- asection *sgot;
- asection *sreloc;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- int i = 0;
+ unsigned isec_segment, got_segment, plt_segment,
+ check_segment[2];
+ int silence_segment_error = !(info->shared || info->pie);
- dynobj = elf_hash_table (info)->dynobj;
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
- local_got_offsets = elf_local_got_offsets (input_bfd);
+ relend = relocs + input_section->reloc_count;
- sgot = NULL;
- sreloc = NULL;
+ isec_segment = _bfinfdpic_osec_to_segment (output_bfd,
+ input_section->output_section);
+ if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info))
+ got_segment = _bfinfdpic_osec_to_segment (output_bfd,
+ bfinfdpic_got_section (info)
+ ->output_section);
+ else
+ got_segment = -1;
+ if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created)
+ plt_segment = _bfinfdpic_osec_to_segment (output_bfd,
+ bfinfdpic_plt_section (info)
+ ->output_section);
+ else
+ plt_segment = -1;
- rel = relocs;
- relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++, i++)
+ for (rel = relocs; 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 = 0;
- bfd_boolean unresolved_reloc;
+ struct elf_link_hash_entry *h;
+ bfd_vma relocation;
bfd_reloc_status_type r;
- bfd_vma address;
+ const char * name = NULL;
+ int r_type;
+ asection *osec;
+ struct bfinfdpic_relocs_info *picrel;
+ bfd_vma orig_addend = rel->r_addend;
r_type = ELF32_R_TYPE (rel->r_info);
- if (r_type < 0 || r_type >= 243)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- if (r_type == R_BFIN_GNU_VTENTRY
- || r_type == R_BFIN_GNU_VTINHERIT)
+ if (r_type == R_BFIN_GNU_VTINHERIT
+ || r_type == R_BFIN_GNU_VTENTRY)
continue;
+ r_symndx = ELF32_R_SYM (rel->r_info);
howto = bfin_reloc_type_lookup (input_bfd, r_type);
if (howto == NULL)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
- r_symndx = ELF32_R_SYM (rel->r_info);
- h = NULL;
- sym = NULL;
- sec = NULL;
- unresolved_reloc = FALSE;
+ 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 (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !BFINFDPIC_SYM_LOCAL (info, h))
+ {
+ osec = sec = NULL;
+ relocation = 0;
+ }
+
+ switch (r_type)
+ {
+ case R_pcrel24:
+ case R_pcrel24_jump_l:
+ case R_byte4_data:
+ if (! IS_FDPIC (output_bfd))
+ goto non_fdpic;
+
+ case R_BFIN_GOT17M4:
+ case R_BFIN_GOTHI:
+ case R_BFIN_GOTLO:
+ case R_BFIN_FUNCDESC_GOT17M4:
+ case R_BFIN_FUNCDESC_GOTHI:
+ case R_BFIN_FUNCDESC_GOTLO:
+ case R_BFIN_GOTOFF17M4:
+ case R_BFIN_GOTOFFHI:
+ case R_BFIN_GOTOFFLO:
+ case R_BFIN_FUNCDESC_GOTOFF17M4:
+ case R_BFIN_FUNCDESC_GOTOFFHI:
+ case R_BFIN_FUNCDESC_GOTOFFLO:
+ case R_BFIN_FUNCDESC:
+ case R_BFIN_FUNCDESC_VALUE:
+ if (h != NULL)
+ picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_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 = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
+ (info), input_bfd, r_symndx,
+ orig_addend, INSERT);
+ if (! picrel)
+ return FALSE;
+
+ if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
+ osec, sym,
+ rel->r_addend))
+ {
+ (*_bfd_error_handler)
+ (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
+ input_bfd, input_section, rel->r_offset, name);
+ return FALSE;
+
+ }
- if (r_symndx < symtab_hdr->sh_info)
- {
- sym = local_syms + r_symndx;
- sec = local_sections[r_symndx];
- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
- }
- else
- {
- bfd_boolean warned;
+ break;
- RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
- r_symndx, symtab_hdr, sym_hashes,
- h, sec, relocation,
- unresolved_reloc, warned);
+ default:
+ non_fdpic:
+ picrel = NULL;
+ if (h && ! BFINFDPIC_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;
}
- if (sec != NULL && elf_discarded_section (sec))
+ switch (r_type)
{
- /* 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;
- }
+ case R_pcrel24:
+ case R_pcrel24_jump_l:
+ check_segment[0] = isec_segment;
+ if (! IS_FDPIC (output_bfd))
+ check_segment[1] = isec_segment;
+ else if (picrel->plt)
+ {
+ relocation = bfinfdpic_plt_section (info)->output_section->vma
+ + bfinfdpic_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
+ ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
- if (info->relocatable)
- continue;
+ case R_BFIN_GOT17M4:
+ case R_BFIN_GOTHI:
+ case R_BFIN_GOTLO:
+ relocation = picrel->got_entry;
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
- address = rel->r_offset;
+ case R_BFIN_FUNCDESC_GOT17M4:
+ case R_BFIN_FUNCDESC_GOTHI:
+ case R_BFIN_FUNCDESC_GOTLO:
+ relocation = picrel->fdgot_entry;
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
- /* Then, process normally. */
- switch (r_type)
- {
- case R_BFIN_GNU_VTINHERIT:
- case R_BFIN_GNU_VTENTRY:
- return bfd_reloc_ok;
+ case R_BFIN_GOTOFFHI:
+ case R_BFIN_GOTOFF17M4:
+ case R_BFIN_GOTOFFLO:
+ relocation -= bfinfdpic_got_section (info)->output_section->vma
+ + bfinfdpic_got_section (info)->output_offset
+ + bfinfdpic_got_initial_offset (info);
+ check_segment[0] = got_segment;
+ check_segment[1] = sec
+ ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
- case R_got:
- /* Relocation is to the address of the entry for this symbol
- in the global offset table. */
- if (h != NULL
- && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
- goto do_default;
- /* Fall through. */
- /* Relocation is the offset of the entry for this symbol in
- the global offset table. */
+ case R_BFIN_FUNCDESC_GOTOFF17M4:
+ case R_BFIN_FUNCDESC_GOTOFFHI:
+ case R_BFIN_FUNCDESC_GOTOFFLO:
+ relocation = picrel->fd_entry;
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+ case R_BFIN_FUNCDESC:
{
- bfd_vma off;
+ int dynindx;
+ bfd_vma addend = rel->r_addend;
- if (dynobj == NULL)
+ if (! (h && h->root.type == bfd_link_hash_undefweak
+ && BFINFDPIC_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 && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)
+ && BFINFDPIC_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 && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
+ {
+ if (addend)
+ {
+ info->callbacks->warning
+ (info, _("R_BFIN_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_byte4_data;
+ dynindx = elf_section_data (bfinfdpic_got_section (info)
+ ->output_section)->dynindx;
+ addend = bfinfdpic_got_section (info)->output_offset
+ + bfinfdpic_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 || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
+ {
+ addend += bfinfdpic_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))
+ {
+ if (_bfinfdpic_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;
+ }
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section
+ (info),
+ _bfd_elf_section_offset
+ (output_bfd, info,
+ input_section, rel->r_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 (_bfinfdpic_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);
+ /* Only output a reloc for a not deleted entry. */
+ if (offset >= (bfd_vma) -2)
+ _bfinfdpic_add_dyn_reloc (output_bfd,
+ bfinfdpic_gotrel_section (info),
+ 0,
+ R_unused0,
+ dynindx, addend, picrel);
+ else
+ _bfinfdpic_add_dyn_reloc (output_bfd,
+ bfinfdpic_gotrel_section (info),
+ offset + input_section
+ ->output_section->vma
+ + input_section->output_offset,
+ r_type,
+ dynindx, addend, picrel);
+ }
+ else
+ addend += bfinfdpic_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_byte4_data:
+ if (! IS_FDPIC (output_bfd))
{
- /* Create the .got section. */
- elf_hash_table (info)->dynobj = dynobj = output_bfd;
- if (!_bfd_elf_create_got_section (dynobj, info))
- return FALSE;
+ check_segment[0] = check_segment[1] = -1;
+ break;
}
+ /* Fall through. */
+ case R_BFIN_FUNCDESC_VALUE:
+ {
+ int dynindx;
+ bfd_vma addend = rel->r_addend;
+ bfd_vma offset;
+ offset = _bfd_elf_section_offset (output_bfd, info,
+ input_section, rel->r_offset);
- if (sgot == NULL)
+ /* If the symbol is dynamic but binds locally, use
+ section+offset. */
+ if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
{
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
+ if (addend && r_type == R_BFIN_FUNCDESC_VALUE)
+ {
+ info->callbacks->warning
+ (info, _("R_BFIN_FUNCDESC_VALUE references dynamic symbol with nonzero addend"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+ dynindx = h->dynindx;
}
-
- if (h != NULL)
+ else
{
- bfd_boolean dyn;
-
- off = h->got.offset;
- BFD_ASSERT (off != (bfd_vma) - 1);
- dyn = elf_hash_table (info)->dynamic_sections_created;
+ 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 (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
- || (info->shared
- && (info->symbolic
- || h->dynindx == -1
- || h->forced_local)
- && h->def_regular))
+ /* 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 || BFINFDPIC_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))
{
- /* 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 4, 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
+ if (_bfinfdpic_osec_readonly_p (output_bfd,
+ input_section
+ ->output_section))
{
- bfd_put_32 (output_bfd, relocation,
- sgot->contents + off);
- h->got.offset |= 1;
+ 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)
+ {
+ /* Only output a reloc for a not deleted entry. */
+ if (offset >= (bfd_vma)-2)
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section
+ (info), -1, picrel);
+ else
+ _bfinfdpic_add_rofixup (output_bfd,
+ bfinfdpic_gotfixup_section
+ (info),
+ offset + input_section
+ ->output_section->vma
+ + input_section->output_offset,
+ picrel);
+
+ if (r_type == R_BFIN_FUNCDESC_VALUE)
+ {
+ if (offset >= (bfd_vma)-2)
+ _bfinfdpic_add_rofixup
+ (output_bfd,
+ bfinfdpic_gotfixup_section (info),
+ -1, picrel);
+ else
+ _bfinfdpic_add_rofixup
+ (output_bfd,
+ bfinfdpic_gotfixup_section (info),
+ offset + input_section->output_section->vma
+ + input_section->output_offset + 4, picrel);
+ }
}
}
- else
- unresolved_reloc = FALSE;
}
else
{
- 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 4. We use
- the least significant bit to record whether we have
- already generated the necessary reloc. */
- if ((off & 1) != 0)
- off &= ~1;
- else
+ if ((bfd_get_section_flags (output_bfd,
+ input_section->output_section)
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
{
- bfd_put_32 (output_bfd, relocation, sgot->contents + off);
-
- if (info->shared)
+ if (_bfinfdpic_osec_readonly_p (output_bfd,
+ input_section
+ ->output_section))
{
- asection *s;
- Elf_Internal_Rela outrel;
- bfd_byte *loc;
-
- s = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (s != NULL);
-
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset + off);
- outrel.r_info =
- ELF32_R_INFO (0, R_pcrel24);
- outrel.r_addend = relocation;
- loc = s->contents;
- loc +=
- s->reloc_count++ * sizeof (Elf32_External_Rela);
- bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ info->callbacks->warning
+ (info,
+ _("cannot emit dynamic relocations in read-only section"),
+ name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
}
-
- local_got_offsets[r_symndx] |= 1;
+ /* Only output a reloc for a not deleted entry. */
+ if (offset >= (bfd_vma)-2)
+ _bfinfdpic_add_dyn_reloc (output_bfd,
+ bfinfdpic_gotrel_section (info),
+ 0, R_unused0, dynindx, addend, picrel);
+ else
+ _bfinfdpic_add_dyn_reloc (output_bfd,
+ bfinfdpic_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_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2)
+ {
+ /* 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 || BFINFDPIC_SYM_LOCAL (info, h)))
+ bfd_put_32 (output_bfd,
+ bfinfdpic_got_section (info)->output_section->vma
+ + bfinfdpic_got_section (info)->output_offset
+ + bfinfdpic_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 && ! BFINFDPIC_SYM_LOCAL (info, h)
+ ? 0
+ : _bfinfdpic_osec_to_segment (output_bfd,
+ sec
+ ->output_section),
+ contents + rel->r_offset + 4);
}
+ }
+ check_segment[0] = check_segment[1] = got_segment;
+ break;
+
+ default:
+ check_segment[0] = isec_segment;
+ check_segment[1] = sec
+ ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
+ : (unsigned)-1;
+ break;
+ }
+
+ if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
+ {
+#if 1 /* 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;
+#endif
+ 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))
+ info->callbacks->warning
+ (info,
+ (info->shared || info->pie)
+ ? _("relocations between different segments are not supported")
+ : _("warning: 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_BFIN_PIC;
+ }
+
+ switch (r_type)
+ {
+ case R_BFIN_GOTOFFHI:
+ /* We need the addend to be applied before we shift the
+ value right. */
+ relocation += rel->r_addend;
+ /* Fall through. */
+ case R_BFIN_GOTHI:
+ case R_BFIN_FUNCDESC_GOTHI:
+ case R_BFIN_FUNCDESC_GOTOFFHI:
+ relocation >>= 16;
+ /* Fall through. */
- relocation = sgot->output_offset + off;
- rel->r_addend = 0;
- /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */
- relocation /= 4;
- }
- goto do_default;
+ case R_BFIN_GOTLO:
+ case R_BFIN_FUNCDESC_GOTLO:
+ case R_BFIN_GOTOFFLO:
+ case R_BFIN_FUNCDESC_GOTOFFLO:
+ relocation &= 0xffff;
+ break;
default:
- do_default:
- r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
- contents, address,
- relocation, rel->r_addend);
-
break;
}
- /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
- because such sections are not SEC_ALLOC and thus ld.so will
- not process them. */
- if (unresolved_reloc
- && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic))
+ switch (r_type)
{
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
- input_bfd,
- input_section, (long) rel->r_offset, h->root.root.string);
- return FALSE;
+ case R_pcrel24:
+ case R_pcrel24_jump_l:
+ 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_BFIN_GOT17M4:
+ case R_BFIN_GOTHI:
+ case R_BFIN_GOTLO:
+ case R_BFIN_FUNCDESC_GOT17M4:
+ case R_BFIN_FUNCDESC_GOTHI:
+ case R_BFIN_FUNCDESC_GOTLO:
+ case R_BFIN_FUNCDESC_GOTOFF17M4:
+ case R_BFIN_FUNCDESC_GOTOFFHI:
+ case R_BFIN_FUNCDESC_GOTOFFLO:
+ /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4
+ 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_BFIN_GOTOFFHI:
+ relocation -= rel->r_addend;
+ break;
+
+ default:
+ break;
}
+ r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
+
if (r != bfd_reloc_ok)
{
- const char *name;
+ const char * msg = (const char *) NULL;
- if (h != NULL)
- name = h->root.root.string;
- else
+ switch (r)
{
- 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);
- }
+ 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;
- if (r == bfd_reloc_overflow)
- {
- if (!(info->callbacks->reloc_overflow
- (info, (h ? &h->root : NULL), name, howto->name,
- (bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
- return FALSE;
- }
- else
- {
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): reloc against `%s': error %d"),
- input_bfd, input_section,
- (long) rel->r_offset, name, (int) r);
- return FALSE;
+ 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)
+ r = info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+
+ if (! r)
+ return FALSE;
}
}
return TRUE;
}
-static asection *
-bfin_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_BFIN_GNU_VTINHERIT:
- case R_BFIN_GNU_VTENTRY:
- return NULL;
- }
-
- return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
-}
-
/* Update the relocation information for the relocations of the section
being removed. */
return TRUE;
}
-/* Update the got entry reference counts for the section being removed. */
-
-static bfd_boolean
-bfin_gc_sweep_hook (bfd * abfd,
- struct bfd_link_info *info,
- asection * sec,
- const Elf_Internal_Rela * relocs)
-{
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- bfd_signed_vma *local_got_refcounts;
- const Elf_Internal_Rela *rel, *relend;
- bfd *dynobj;
- asection *sgot;
- asection *srelgot;
-
- dynobj = elf_hash_table (info)->dynobj;
- if (dynobj == NULL)
- return TRUE;
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (abfd);
- local_got_refcounts = elf_local_got_refcounts (abfd);
-
- sgot = bfd_get_section_by_name (dynobj, ".got");
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-
- relend = relocs + sec->reloc_count;
- for (rel = relocs; rel < relend; rel++)
- {
- unsigned long r_symndx;
- struct elf_link_hash_entry *h;
-
- switch (ELF32_R_TYPE (rel->r_info))
- {
- case R_got:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->got.refcount > 0)
- {
- --h->got.refcount;
- if (h->got.refcount == 0)
- {
- /* We don't need the .got entry any more. */
- sgot->size -= 4;
- srelgot->size -= sizeof (Elf32_External_Rela);
- }
- }
- }
- else if (local_got_refcounts != NULL)
- {
- if (local_got_refcounts[r_symndx] > 0)
- {
- --local_got_refcounts[r_symndx];
- if (local_got_refcounts[r_symndx] == 0)
- {
- /* We don't need the .got entry any more. */
- sgot->size -= 4;
- if (info->shared)
- srelgot->size -= sizeof (Elf32_External_Rela);
- }
- }
- }
- break;
- default:
- break;
- }
- }
- return TRUE;
-}
-
/* We need dynamic symbols for every section, since segments can
relocate independently. */
static bfd_boolean
return TRUE;
}
-/* The name of the dynamic interpreter. This is put in the .interp
- section. */
-
-#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
-
-#define DEFAULT_STACK_SIZE 0x20000
-
-/* This structure is used to collect the number of entries present in
- each addressable range of the got. */
-struct _bfinfdpic_dynamic_got_info
-{
- /* Several bits of information about the current link. */
- struct bfd_link_info *info;
- /* Total size needed for GOT entries within the 18- or 32-bit
- ranges. */
- bfd_vma got17m4, gothilo;
- /* Total size needed for function descriptor entries within the 18-
- or 32-bit ranges. */
- bfd_vma fd17m4, fdhilo;
- /* Total size needed function descriptor entries referenced in PLT
- entries, that would be profitable to place in offsets close to
- the PIC register. */
- bfd_vma fdplt;
- /* Total size needed by lazy PLT entries. */
- bfd_vma lzplt;
- /* Number of relocations carried over from input object files. */
- unsigned long relocs;
- /* Number of fixups introduced by relocations in input object files. */
- unsigned long fixups;
-};
-
/* Compute the total GOT size required by each symbol in each range.
Symbols may require up to 4 words in the GOT: an entry pointing to
the symbol, an entry pointing to its function descriptor, and a