const Elf_Internal_Rela *));
static void elf_xtensa_hide_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean));
-static void elf_xtensa_copy_indirect_symbol
- PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
- struct elf_link_hash_entry *));
static asection *elf_xtensa_gc_mark_hook
PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
/* Local helper functions. */
+static bfd_boolean xtensa_elf_dynamic_symbol_p
+ PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *));
static int property_table_compare
PARAMS ((const PTR, const PTR));
static bfd_boolean elf_xtensa_in_literal_pool
PARAMS ((Elf_Internal_Rela *, bfd *, asection *));
static void do_fix_for_final_link
PARAMS ((Elf_Internal_Rela *, asection *, bfd_vma *));
-static bfd_boolean xtensa_elf_dynamic_symbol_p
- PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static bfd_vma elf_xtensa_create_plt_entry
PARAMS ((bfd *, bfd *, unsigned));
static int elf_xtensa_combine_prop_entries
PARAMS ((asection *));
static int internal_reloc_compare
PARAMS ((const PTR, const PTR));
-static bfd_boolean get_is_linkonce_section
- PARAMS ((bfd *, asection *));
extern char *xtensa_get_property_section_name
- PARAMS ((bfd *, asection *, const char *));
+ PARAMS ((asection *, const char *));
/* Other functions called directly by the linker. */
The actual PLT code must be split into multiple sections and all
the sections have to be created before size_dynamic_sections,
where we figure out the exact number of PLT entries that will be
- needed. It is OK is this count is an overestimate, e.g., some
+ needed. It is OK if this count is an overestimate, e.g., some
relocations may be removed by GC. */
static int plt_reloc_count = 0;
0 /* unused */
};
+
+static inline bfd_boolean
+xtensa_elf_dynamic_symbol_p (h, info)
+ struct elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+{
+ /* Check if we should do dynamic things to this symbol. The
+ "ignore_protected" argument need not be set, because Xtensa code
+ does not require special handling of STV_PROTECTED to make function
+ pointer comparisons work properly. The PLT addresses are never
+ used for function pointers. */
+
+ return _bfd_elf_dynamic_symbol_p (h, info, 0);
+}
+
\f
static int
property_table_compare (ap, bp)
Elf_Internal_Rela *internal_relocs;
table_section_name =
- xtensa_get_property_section_name (abfd, section, sec_name);
+ xtensa_get_property_section_name (section, sec_name);
table_section = bfd_get_section_by_name (abfd, table_section_name);
+ free (table_section_name);
if (table_section != NULL)
table_size = bfd_get_section_size_before_reloc (table_section);
return 0;
}
- num_records = table_size / sizeof (property_table_entry);
+ num_records = table_size / 8;
table_data = retrieve_contents (abfd, table_section, TRUE);
blocks = (property_table_entry *)
bfd_malloc (num_records * sizeof (property_table_entry));
and the addresses are already in the table. */
bfd_vma off;
- for (off = 0; off < table_size; off += sizeof (property_table_entry))
+ for (off = 0; off < table_size; off += 8)
{
bfd_vma address = bfd_get_32 (abfd, table_data + off);
}
-static void
-elf_xtensa_copy_indirect_symbol (bed, dir, ind)
- struct elf_backend_data *bed;
- struct elf_link_hash_entry *dir, *ind;
-{
- _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
-
- /* The standard function doesn't copy the NEEDS_PLT flag. */
- dir->elf_link_hash_flags |=
- (ind->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT);
-}
-
-
/* Return the section that should be marked against GC for a given
relocation. */
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (! xtensa_elf_dynamic_symbol_p (info, h))
+ if (! xtensa_elf_dynamic_symbol_p (h, info))
elf_xtensa_make_sym_local (info, h);
/* If the symbol has a relocation outside the GOT, set the
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
- if (! info->shared)
+ if (info->executable)
{
s = bfd_get_section_by_name (dynobj, ".interp");
if (s == NULL)
continue;
for (s = abfd->sections; s != NULL; s = s->next)
{
- /* Skip input sections that are being discarded. */
- if (!bfd_is_abs_section (s)
- && bfd_is_abs_section (s->output_section))
- continue;
-
- if (xtensa_is_littable_section (s) && s != spltlittbl)
+ if (! elf_discarded_section (s)
+ && xtensa_is_littable_section (s)
+ && s != spltlittbl)
sgotloc->_raw_size += s->_raw_size;
}
}
}
-static bfd_boolean
-xtensa_elf_dynamic_symbol_p (info, h)
- struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
-{
- if (h == NULL)
- return FALSE;
-
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- if (h->dynindx == -1)
- return FALSE;
-
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_defweak)
- return TRUE;
-
- switch (ELF_ST_VISIBILITY (h->other))
- {
- case STV_DEFAULT:
- break;
- case STV_HIDDEN:
- case STV_INTERNAL:
- return FALSE;
- case STV_PROTECTED:
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
- return FALSE;
- break;
- }
-
- if ((info->shared && !info->symbolic)
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- return TRUE;
-
- return FALSE;
-}
-
-
/* Relocate an Xtensa ELF section. This is invoked by the linker for
both relocatable and final links. */
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
}
else
{
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- relocation = 0;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- sec = h->root.u.def.section;
-
- if (sec->output_section == NULL)
- /* Set a flag that will be cleared later if we find a
- relocation value for this symbol. output_section
- is typically NULL for symbols satisfied by a shared
- library. */
- unresolved_reloc = TRUE;
- else
- relocation = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- else if (h->root.type == bfd_link_hash_undefweak)
+ RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx,
+ symtab_hdr, relocation, sec,
+ unresolved_reloc, info,
+ warned);
+
+ if (relocation == 0
+ && !unresolved_reloc
+ && h->root.type == bfd_link_hash_undefweak)
is_weak_undef = TRUE;
- else if (info->shared
- && !info->no_undefined
- && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- ;
- else
- {
- if (! ((*info->callbacks->undefined_symbol)
- (info, h->root.root.string, input_bfd,
- input_section, rel->r_offset,
- (!info->shared || info->no_undefined
- || ELF_ST_VISIBILITY (h->other)))))
- return FALSE;
- warned = TRUE;
- }
}
if (relaxing_section)
/* Generate dynamic relocations. */
if (elf_hash_table (info)->dynamic_sections_created)
{
- bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h);
+ bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (h, info);
if (dynamic_symbol && (r_type == R_XTENSA_OP0
|| r_type == R_XTENSA_OP1
memset (&outrel, 0, sizeof outrel);
else
{
- outrel.r_offset = (input_section->output_section->vma
- + input_section->output_offset);
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
if (dynamic_symbol)
{
sgotloc_size = (sgotloc->_cooked_size != 0
? sgotloc->_cooked_size : sgotloc->_raw_size);
if (sgotloc_size != section_size)
- return -1;
+ {
+ (*_bfd_error_handler)
+ ("internal inconsistency in size of .got.loc section");
+ return -1;
+ }
contents = (bfd_byte *) bfd_malloc (section_size);
table = (property_table_entry *)
memcpy (sgotloc->contents, contents, section_size);
free (contents);
+ free (table);
return num;
}
BFD_ASSERT (! info->relocatable);
sxtlit = bfd_get_section_by_name (output_bfd, ".xt.lit");
sgotloc = bfd_get_section_by_name (dynobj, ".got.loc");
- if (!sxtlit || !sgotloc)
- return FALSE;
+ BFD_ASSERT (sxtlit && sgotloc);
num_xtlit_entries =
elf_xtensa_combine_prop_entries (output_bfd, sxtlit, sgotloc);
if (num_xtlit_entries < 0)
if (out_mach != in_mach)
{
(*_bfd_error_handler)
- ("%s: incompatible machine type. Output is 0x%x. Input is 0x%x\n",
+ ("%s: incompatible machine type. Output is 0x%x. Input is 0x%x",
bfd_archive_filename (ibfd), out_mach, in_mach);
bfd_set_error (bfd_error_wrong_format);
return FALSE;
sec->_cooked_size = section_size - removed_bytes;
/* Also shrink _raw_size. See comments in relax_property_section. */
sec->_raw_size = sec->_cooked_size;
+
+ if (xtensa_is_littable_section (sec))
+ {
+ bfd *dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj)
+ {
+ asection *sgotloc =
+ bfd_get_section_by_name (dynobj, ".got.loc");
+ if (sgotloc)
+ {
+ bfd_size_type sgotloc_size =
+ (sgotloc->_cooked_size ? sgotloc->_cooked_size
+ : sgotloc->_raw_size);
+ sgotloc->_cooked_size = sgotloc_size - removed_bytes;
+ sgotloc->_raw_size = sgotloc_size - removed_bytes;
+ }
+ }
+ }
}
else
{
if (content_length < address)
{
(*_bfd_error_handler)
- ("Attempt to convert L32R/CALLX to CALL failed\n");
+ ("Attempt to convert L32R/CALLX to CALL failed");
return bfd_reloc_other;
}
if (direct_call_opcode == XTENSA_UNDEFINED)
{
(*_bfd_error_handler)
- ("Attempt to convert L32R/CALLX to CALL failed\n");
+ ("Attempt to convert L32R/CALLX to CALL failed");
return bfd_reloc_other;
}
const literal_value *src;
{
unsigned hash_val;
+
if (r_reloc_is_const (&src->r_rel))
return hash_bfd_vma (src->value);
/* Now check for the same section and the same elf_hash. */
if (r_reloc_is_defined (&src->r_rel))
- hash_val += hash_bfd_vma ((bfd_vma) r_reloc_get_section (&src->r_rel));
+ hash_val += hash_bfd_vma ((bfd_vma) (unsigned) r_reloc_get_section (&src->r_rel));
else
- hash_val += hash_bfd_vma ((bfd_vma) r_reloc_get_hash_entry (&src->r_rel));
+ hash_val += hash_bfd_vma ((bfd_vma) (unsigned) r_reloc_get_hash_entry (&src->r_rel));
return hash_val;
}
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h);
+ dynamic_symbol = xtensa_elf_dynamic_symbol_p (h, info);
if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT)
&& (input_section->flags & SEC_ALLOC) != 0
}
+static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+static int insn_sec_len = sizeof (XTENSA_INSN_SEC_NAME) - 1;
+static int lit_sec_len = sizeof (XTENSA_LIT_SEC_NAME) - 1;
+
+
static bfd_boolean
xtensa_is_property_section (sec)
asection *sec;
{
- static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+ if (strncmp (XTENSA_INSN_SEC_NAME, sec->name, insn_sec_len) == 0
+ || strncmp (XTENSA_LIT_SEC_NAME, sec->name, lit_sec_len) == 0)
+ return TRUE;
- if (strncmp (".xt.insn", sec->name, 8) == 0
- || strncmp (".xt.lit", sec->name, 7) == 0)
+ if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0
+ && (sec->name[linkonce_len] == 'x'
+ || sec->name[linkonce_len] == 'p')
+ && sec->name[linkonce_len + 1] == '.')
return TRUE;
- if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0)
- {
- if (strncmp ("x.", sec->name + linkonce_len, 2) == 0
- || strncmp ("p.", sec->name + linkonce_len, 2) == 0)
- return TRUE;
- if (strstr (sec->name + linkonce_len, ".xt.insn") != NULL
- || strstr (sec->name + linkonce_len, ".xt.lit") != NULL)
- return TRUE;
- }
return FALSE;
}
xtensa_is_littable_section (sec)
asection *sec;
{
- static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+ if (strncmp (XTENSA_LIT_SEC_NAME, sec->name, lit_sec_len) == 0)
+ return TRUE;
- if (strncmp (".xt.lit", sec->name, 7) == 0)
+ if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0
+ && sec->name[linkonce_len] == 'p'
+ && sec->name[linkonce_len + 1] == '.')
return TRUE;
- if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0)
- {
- if (strncmp ("p.", sec->name + linkonce_len, 2) == 0)
- return TRUE;
- if (strstr (sec->name + linkonce_len, ".xt.lit") != NULL)
- return TRUE;
- }
return FALSE;
}
}
-static bfd_boolean
-get_is_linkonce_section (abfd, sec)
- bfd *abfd ATTRIBUTE_UNUSED;
- asection *sec;
-{
- flagword flags, link_once_flags;
- bfd_boolean is_linkonce = FALSE;;
-
- flags = bfd_get_section_flags (abfd, sec);
- link_once_flags = (flags & SEC_LINK_ONCE);
- if (link_once_flags != 0)
- is_linkonce = TRUE;
-
- /* In order for this to be useful to the assembler
- before the linkonce flag is set we need to
- check for the GNU extension name. */
- if (!is_linkonce &&
- strncmp (sec->name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
- is_linkonce = TRUE;
-
- return is_linkonce;
-}
-
-
char *
-xtensa_get_property_section_name (abfd, sec, base_name)
- bfd *abfd;
+xtensa_get_property_section_name (sec, base_name)
asection *sec;
- const char * base_name;
+ const char *base_name;
{
- char *table_sec_name = NULL;
- bfd_boolean is_linkonce;
-
- is_linkonce = get_is_linkonce_section (abfd, sec);
-
- if (!is_linkonce)
- {
- table_sec_name = strdup (base_name);
- }
- else
+ if (strncmp (sec->name, ".gnu.linkonce.", linkonce_len) == 0)
{
- static size_t prefix_len = sizeof (".gnu.linkonce.t.") - 1;
- size_t len = strlen (sec->name) + 1;
- char repl_char = '\0';
- const char *segname = sec->name;
-
- if (strncmp (segname, ".gnu.linkonce.t.", prefix_len) == 0)
- {
- if (strcmp (base_name, ".xt.insn") == 0)
- repl_char = 'x';
- else if (strcmp (base_name, ".xt.lit") == 0)
- repl_char = 'p';
- }
-
- if (repl_char != '\0')
- {
- char *name = (char *) bfd_malloc (len);
- memcpy (name, sec->name, len);
- name[prefix_len - 2] = repl_char;
- table_sec_name = name;
- }
+ char *prop_sec_name;
+ const char *suffix;
+ char linkonce_kind = 0;
+
+ if (strcmp (base_name, XTENSA_INSN_SEC_NAME) == 0)
+ linkonce_kind = 'x';
+ else if (strcmp (base_name, XTENSA_LIT_SEC_NAME) == 0)
+ linkonce_kind = 'p';
else
+ abort ();
+
+ prop_sec_name = (char *) bfd_malloc (strlen (sec->name) + 1);
+ memcpy (prop_sec_name, ".gnu.linkonce.", linkonce_len);
+ prop_sec_name[linkonce_len] = linkonce_kind;
+ prop_sec_name[linkonce_len + 1] = '.';
+
+ suffix = sec->name + linkonce_len;
+ while (*suffix)
{
- size_t base_len = strlen (base_name) + 1;
- char *name = (char *) bfd_malloc (len + base_len);
- memcpy (name, sec->name, len - 1);
- memcpy (name + len - 1, base_name, base_len);
- table_sec_name = name;
+ suffix += 1;
+ if (suffix[-1] == '.')
+ break;
}
+ strcpy (prop_sec_name + linkonce_len + 2, suffix);
+
+ return prop_sec_name;
}
- return table_sec_name;
+ return strdup (base_name);
}
\f
return ok;
}
+/* The default literal sections should always be marked as "code" (i.e.,
+ SHF_EXECINSTR). This is particularly important for the Linux kernel
+ module loader so that the literals are not placed after the text. */
+static struct bfd_elf_special_section const elf_xtensa_special_sections[]=
+{
+ { ".literal", 8, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { ".init.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { ".fini.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, 0, 0, 0 }
+};
+
\f
#ifndef ELF_ARCH
#define TARGET_LITTLE_SYM bfd_elf32_xtensa_le_vec
#define elf_backend_adjust_dynamic_symbol elf_xtensa_adjust_dynamic_symbol
#define elf_backend_check_relocs elf_xtensa_check_relocs
-#define elf_backend_copy_indirect_symbol elf_xtensa_copy_indirect_symbol
#define elf_backend_create_dynamic_sections elf_xtensa_create_dynamic_sections
#define elf_backend_discard_info elf_xtensa_discard_info
#define elf_backend_ignore_discarded_relocs elf_xtensa_ignore_discarded_relocs
#define elf_backend_reloc_type_class elf_xtensa_reloc_type_class
#define elf_backend_relocate_section elf_xtensa_relocate_section
#define elf_backend_size_dynamic_sections elf_xtensa_size_dynamic_sections
+#define elf_backend_special_sections elf_xtensa_special_sections
#include "elf32-target.h"