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 *));
static bfd_boolean elf_xtensa_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean elf_xtensa_modify_segment_map
- PARAMS ((bfd *));
+ PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean elf_xtensa_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
/* 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;
}
}
this and it probably ought to be moved into elf.c as well. */
static bfd_boolean
-elf_xtensa_modify_segment_map (abfd)
+elf_xtensa_modify_segment_map (abfd, info)
bfd *abfd;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
{
struct elf_segment_map **m_p;
/ bfd_octets_per_byte (abfd)))
return bfd_reloc_outofrange;
- /* Work out which section the relocation is targetted at and the
+ /* Work out which section the relocation is targeted at and the
initial relocation command value. */
/* Get symbol value. (Common symbols are special.) */
}
-static bfd_boolean
-xtensa_elf_dynamic_symbol_p (info, h)
- struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
-{
- /* ??? What, if anything, needs to happen wrt STV_PROTECTED and PLT
- entries? For now assume the worst. */
- return _bfd_elf_dynamic_symbol_p (h, info, 1);
-}
-
-
/* 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;
}
expensive and unnecessary unless the target section is actually going
to be relaxed. This pass identifies all such sections by checking if
they have L32Rs pointing to them. In the process, the total number
- of relocations targetting each section is also counted so that we
+ of relocations targeting each section is also counted so that we
know how much space to allocate for source_relocs against each
relaxable literal section. */
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)
+ if (strncmp (sec->name, ".gnu.linkonce.", linkonce_len) == 0)
{
- table_sec_name = strdup (base_name);
- }
- else
- {
- 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"