/* CRIS-specific support for 32-bit ELF.
- Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Axis Communications AB.
Written by Hans-Peter Nilsson, based on elf32-fr30.c
PIC and shlib bits based primarily on elf32-m68k.c and elf32-i386.c.
static void cris_info_to_howto_rela
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
+static bfd_reloc_status_type cris_elf_pcrel_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+
static bfd_boolean cris_elf_grok_prstatus
PARAMS ((bfd *abfd, Elf_Internal_Note *note));
static void cris_elf_final_write_processing PARAMS ((bfd *, bfd_boolean));
+static bfd_boolean cris_elf_set_mach_from_flags
+ PARAMS ((bfd *, unsigned long int));
+
static bfd_boolean cris_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
static bfd_boolean cris_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
+static bfd_boolean cris_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
struct elf_cris_link_hash_entry;
static bfd_boolean elf_cris_discard_excess_dso_dynamics
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ cris_elf_pcrel_reloc, /* special_function */
"R_CRIS_8_PCREL", /* name */
FALSE, /* partial_inplace */
0x0000, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ cris_elf_pcrel_reloc, /* special_function */
"R_CRIS_16_PCREL", /* name */
FALSE, /* partial_inplace */
0x00000000, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ cris_elf_pcrel_reloc, /* special_function */
"R_CRIS_32_PCREL", /* name */
FALSE, /* partial_inplace */
0x00000000, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ cris_elf_pcrel_reloc, /* special_function */
"R_CRIS_32_PLT_PCREL", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
BFD_ASSERT (r_type < (unsigned int) R_CRIS_max);
cache_ptr->howto = & cris_elf_howto_table [r_type];
}
+
+bfd_reloc_status_type
+cris_elf_pcrel_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ /* By default (using only bfd_elf_generic_reloc when linking to
+ non-ELF formats) PC-relative relocs are relative to the beginning
+ of the reloc. CRIS PC-relative relocs are relative to the position
+ *after* the reloc because that's what pre-CRISv32 PC points to
+ after reading an insn field with that reloc. (For CRISv32, PC is
+ actually relative to the start of the insn, but we keep the old
+ definition.) Still, we use as much generic machinery as we can.
+
+ Only adjust when doing a final link. */
+ if (output_bfd == (bfd *) NULL)
+ reloc_entry->addend -= 1 << reloc_entry->howto->size;
+
+ return
+ bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+}
\f
-/* Support for core dump NOTE sections. */
+/* Support for core dump NOTE sections.
+ The slightly unintuitive code layout is an attempt to keep at least
+ some similarities with other ports, hoping to simplify general
+ changes, while still keeping Linux/CRIS and Linux/CRISv32 code apart. */
static bfd_boolean
cris_elf_grok_prstatus (abfd, note)
int offset;
size_t size;
- switch (note->descsz)
- {
+ if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+ switch (note->descsz)
+ {
+ default:
+ return FALSE;
+
+ case 202: /* Linux/CRISv32 */
+ /* pr_cursig */
+ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+ /* pr_pid */
+ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 22);
+
+ /* pr_reg */
+ offset = 70;
+ size = 128;
+
+ break;
+ }
+ else
+ switch (note->descsz)
+ {
default:
return FALSE;
size = 140;
break;
- }
+ }
/* Make a ".reg/999" section. */
return _bfd_elfcore_make_pseudosection (abfd, ".reg",
bfd *abfd;
Elf_Internal_Note *note;
{
- switch (note->descsz)
- {
+ if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+ switch (note->descsz)
+ {
+ default:
+ return FALSE;
+
+ case 124: /* Linux/CRISv32 elf_prpsinfo */
+ elf_tdata (abfd)->core_program
+ = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+ elf_tdata (abfd)->core_command
+ = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+ }
+ else
+ switch (note->descsz)
+ {
default:
return FALSE;
case 124: /* Linux/CRIS elf_prpsinfo */
elf_tdata (abfd)->core_program
- = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+ = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
elf_tdata (abfd)->core_command
- = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
- }
+ = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+ }
/* Note that for some reason, a spurious space is tacked
onto the end of the args in some (at least one anyway)
/* The size in bytes of an entry in the procedure linkage table. */
#define PLT_ENTRY_SIZE 20
+#define PLT_ENTRY_SIZE_V32 26
/* The first entry in an absolute procedure linkage table looks like this. */
0x30, 0x7a, /* move [...],mof */
0x7f, 0x0d, /* (dip [pc+]) */
0, 0, 0, 0, /* Replaced with address of .got + 8. */
- 0x30, 0x09, /* jump [...] */
+ 0x30, 0x09 /* jump [...] */
+};
+
+static const bfd_byte elf_cris_plt0_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+ 0x84, 0xe2, /* subq 4,$sp */
+ 0x6f, 0xfe, /* move.d 0,$acr */
+ 0, 0, 0, 0, /* Replaced by address of .got + 4. */
+ 0x7e, 0x7a, /* move $mof,[$sp] */
+ 0x3f, 0x7a, /* move [$acr],$mof */
+ 0x04, 0xf2, /* addq 4,acr */
+ 0x6f, 0xfa, /* move.d [$acr],$acr */
+ 0xbf, 0x09, /* jump $acr */
+ 0xb0, 0x05, /* nop */
+ 0, 0 /* Pad out to 26 bytes. */
};
/* Subsequent entries in an absolute procedure linkage table look like
0xff, 0xff /* Replaced with offset to start of .plt. */
};
+static const bfd_byte elf_cris_plt_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+ 0x6f, 0xfe, /* move.d 0,$acr */
+ 0, 0, 0, 0, /* Replaced with address of this symbol in .got. */
+ 0x6f, 0xfa, /* move.d [$acr],$acr */
+ 0xbf, 0x09, /* jump $acr */
+ 0xb0, 0x05, /* nop */
+ 0x3f, 0x7e, /* move 0,mof */
+ 0, 0, 0, 0, /* Replaced with offset into relocation table. */
+ 0xbf, 0x0e, /* ba start_of_plt0_entry */
+ 0, 0, 0, 0, /* Replaced with offset to plt0 entry. */
+ 0xb0, 0x05 /* nop */
+};
+
/* The first entry in a PIC procedure linkage table looks like this. */
static const bfd_byte elf_cris_pic_plt0_entry[PLT_ENTRY_SIZE] =
0, 0, 0, 0, 0, 0, 0, 0, /* Pad out to 20 bytes. */
};
+static const bfd_byte elf_cris_pic_plt0_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+ 0x84, 0xe2, /* subq 4,$sp */
+ 0x04, 0x01, /* addoq 4,$r0,$acr */
+ 0x7e, 0x7a, /* move $mof,[$sp] */
+ 0x3f, 0x7a, /* move [$acr],$mof */
+ 0x04, 0xf2, /* addq 4,$acr */
+ 0x6f, 0xfa, /* move.d [$acr],$acr */
+ 0xbf, 0x09, /* jump $acr */
+ 0xb0, 0x05, /* nop */
+ 0, 0, /* Pad out to 26 bytes. */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
/* Subsequent entries in a PIC procedure linkage table look like this. */
static const bfd_byte elf_cris_pic_plt_entry[PLT_ENTRY_SIZE] =
0xec, 0xff, /* Replaced with offset to start of .plt. */
0xff, 0xff
};
+
+static const bfd_byte elf_cris_pic_plt_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+ 0x6f, 0x0d, /* addo.d 0,$r0,$acr */
+ 0, 0, 0, 0, /* Replaced with offset of this symbol in .got. */
+ 0x6f, 0xfa, /* move.d [$acr],$acr */
+ 0xbf, 0x09, /* jump $acr */
+ 0xb0, 0x05, /* nop */
+ 0x3f, 0x7e, /* move relocoffs,$mof */
+ 0, 0, 0, 0, /* Replaced with offset into relocation table. */
+ 0xbf, 0x0e, /* ba start_of_plt */
+ 0, 0, 0, 0, /* Replaced with offset to start of .plt. */
+ 0xb0, 0x05 /* nop */
+};
\f
/* We copy elf32-m68k.c and elf32-i386.c for the basic linker hash bits
(and most other PIC/shlib stuff). Check that we don't drift away
other targets. */
if (info->shared
&& ((! info->symbolic && h->dynindx != -1)
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ || !h->def_regular)
&& (input_section->flags & SEC_ALLOC) != 0
&& (r_type == R_CRIS_8
|| r_type == R_CRIS_16
else if (unresolved_reloc)
{
_bfd_error_handler
- (_("%B(%A): unresolvable relocation %s against symbol `%s'"),
+ (_("%B, section %A: unresolvable relocation %s against symbol `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
if (h != NULL
&& (h->got.offset == (bfd_vma) -1
|| (!info->shared
- && !((h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) != 0
- || ((h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) == 0
- && h->root.type == bfd_link_hash_undefweak)))))
+ && !(h->def_regular
+ || (!h->def_dynamic
+ && h->root.type == bfd_link_hash_undefweak)))))
{
(*_bfd_error_handler)
((h->got.offset == (bfd_vma) -1)
- ? _("%B(%A): No PLT nor GOT for relocation %s"
+ ? _("%B, section %A: No PLT nor GOT for relocation %s"
" against symbol `%s'")
- : _("%B(%A): No PLT for relocation %s"
+ : _("%B, section %A: No PLT for relocation %s"
" against symbol `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
- symname[0] != '\0' ? symname : _("[whose name is lost]"));
+ (symname != NULL && symname[0] != '\0'
+ ? symname : _("[whose name is lost]")));
/* FIXME: Perhaps blaming input is not the right thing to
do; this is probably an internal error. But it is true
if (!elf_hash_table (info)->dynamic_sections_created
|| (! info->shared
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+ && (h->def_regular
|| h->type == STT_FUNC
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_NEEDS_PLT)))
+ || h->needs_plt))
|| (info->shared
&& (info->symbolic || h->dynindx == -1)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ && h->def_regular))
{
/* This wasn't checked above for ! info->shared, but
must hold there if we get here; the symbol must
or be a function or otherwise need a PLT. */
BFD_ASSERT (!elf_hash_table (info)->dynamic_sections_created
|| info->shared
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) != 0
+ || h->def_regular
|| h->type == STT_FUNC
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_NEEDS_PLT)
+ || h->needs_plt
|| h->root.type == bfd_link_hash_undefweak);
/* This is actually a static link, or it is a
allowed to pass us these kinds of things. */
if (h == NULL)
(*_bfd_error_handler)
- (_("%B(%A): relocation %s with non-zero addend %d"
+ (_("%B, section %A: relocation %s with non-zero addend %d"
" against local symbol"),
input_bfd,
input_section,
rel->r_addend);
else
(*_bfd_error_handler)
- (_("%B(%A): relocation %s with non-zero addend %d"
+ (_("%B, section %A: relocation %s with non-zero addend %d"
" against symbol `%s'"),
input_bfd,
input_section,
if (h != NULL
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& !(!info->shared
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
- || ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ && (h->def_regular
+ || (!h->def_dynamic
&& h->root.type == bfd_link_hash_undefweak))))
{
(*_bfd_error_handler)
- (_("%B(%A): relocation %s is not allowed for global symbol: `%s'"),
+ (_("%B, section %A: relocation %s is"
+ " not allowed for global symbol: `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
if (sgot == NULL)
{
(*_bfd_error_handler)
- (_("%B: relocation %s in section %A with no GOT created"),
+ (_("%B, section %A: relocation %s with no GOT created"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name);
&& r_type != R_CRIS_16_PCREL
&& r_type != R_CRIS_32_PCREL)
|| (!info->symbolic
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+ || !h->def_regular)))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
become local. */
else if (h != NULL
&& ((! info->symbolic && h->dynindx != -1)
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ || !h->def_regular))
{
BFD_ASSERT (h->dynindx != -1);
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
{
case bfd_reloc_overflow:
r = info->callbacks->reloc_overflow
- (info, symname, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset);
+ (info, (h ? &h->root : NULL), symname, howto->name,
+ (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
break;
case bfd_reloc_undefined:
Elf_Internal_Sym *sym;
{
bfd *dynobj;
+
+ /* Where in the plt entry to put values. */
int plt_off1 = 2, plt_off2 = 10, plt_off3 = 16;
+ /* What offset to add to the distance to the first PLT entry for the
+ value at plt_off3. */
+ int plt_off3_value_bias = 4;
+
+ /* Where in the PLT entry the call-dynlink-stub is (happens to be same
+ for PIC and non-PIC for v32 and pre-v32). */
+ int plt_stub_offset = 8;
+ int plt_entry_size = PLT_ENTRY_SIZE;
+ const bfd_byte *plt_entry = elf_cris_plt_entry;
+ const bfd_byte *plt_pic_entry = elf_cris_pic_plt_entry;
+
+ /* Adjust the various PLT entry offsets. */
+ if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32)
+ {
+ plt_off2 = 14;
+ plt_off3 = 20;
+ plt_off3_value_bias = -2;
+ plt_stub_offset = 12;
+ plt_entry_size = PLT_ENTRY_SIZE_V32;
+ plt_entry = elf_cris_plt_entry_v32;
+ plt_pic_entry = elf_cris_pic_plt_entry_v32;
+ }
+
dynobj = elf_hash_table (info)->dynobj;
if (h->plt.offset != (bfd_vma) -1)
/* Fill in the entry in the procedure linkage table. */
if (! info->shared)
{
- memcpy (splt->contents + h->plt.offset, elf_cris_plt_entry,
- PLT_ENTRY_SIZE);
+ memcpy (splt->contents + h->plt.offset, plt_entry,
+ plt_entry_size);
/* We need to enter the absolute address of the GOT entry here. */
bfd_put_32 (output_bfd, got_base + got_offset,
}
else
{
- memcpy (splt->contents + h->plt.offset, elf_cris_pic_plt_entry,
- PLT_ENTRY_SIZE);
+ memcpy (splt->contents + h->plt.offset, plt_pic_entry,
+ plt_entry_size);
bfd_put_32 (output_bfd, got_offset,
splt->contents + h->plt.offset + plt_off1);
}
PLT entry. */
if (has_gotplt)
{
- /* Fill in the offset into the reloc table. */
+ /* Fill in the offset to the reloc table. */
bfd_put_32 (output_bfd,
gotplt_index * sizeof (Elf32_External_Rela),
splt->contents + h->plt.offset + plt_off2);
/* Fill in the offset to the first PLT entry, where to "jump". */
- bfd_put_32 (output_bfd, - (h->plt.offset + plt_off3 + 4),
+ bfd_put_32 (output_bfd,
+ - (h->plt.offset + plt_off3 + plt_off3_value_bias),
splt->contents + h->plt.offset + plt_off3);
/* Fill in the entry in the global offset table with the address of
(splt->output_section->vma
+ splt->output_offset
+ h->plt.offset
- + 8),
+ + plt_stub_offset),
sgotplt->contents + got_offset);
/* Fill in the entry in the .rela.plt section. */
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->def_regular)
{
/* Mark the symbol as undefined, rather than as defined in
the .plt section. Leave the value alone. */
Otherwise, the PLT entry would provide a definition for
the symbol even if the symbol wasn't defined anywhere,
and so the symbol would never be NULL. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
- == 0)
+ if (!h->ref_regular_nonweak)
sym->st_value = 0;
}
}
&& (info->shared
|| (h->dynindx != -1
&& h->plt.offset == (bfd_vma) -1
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ && !h->def_regular
&& h->root.type != bfd_link_hash_undefweak)))
{
asection *sgot;
if (! elf_hash_table (info)->dynamic_sections_created
|| (info->shared
&& (info->symbolic || h->dynindx == -1)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ && h->def_regular))
{
rela.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE);
rela.r_addend = bfd_get_signed_32 (output_bfd, where);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+ if (h->needs_copy)
{
asection *s;
Elf_Internal_Rela rela;
/* Fill in the first entry in the procedure linkage table. */
if (splt->size > 0)
{
- if (info->shared)
- memcpy (splt->contents, elf_cris_pic_plt0_entry, PLT_ENTRY_SIZE);
+ if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32)
+ {
+ if (info->shared)
+ memcpy (splt->contents, elf_cris_pic_plt0_entry_v32,
+ PLT_ENTRY_SIZE_V32);
+ else
+ {
+ memcpy (splt->contents, elf_cris_plt0_entry_v32,
+ PLT_ENTRY_SIZE_V32);
+ bfd_put_32 (output_bfd,
+ sgot->output_section->vma
+ + sgot->output_offset + 4,
+ splt->contents + 4);
+
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize
+ = PLT_ENTRY_SIZE_V32;
+ }
+ }
else
- {
- memcpy (splt->contents, elf_cris_plt0_entry, PLT_ENTRY_SIZE);
- bfd_put_32 (output_bfd,
- sgot->output_section->vma + sgot->output_offset + 4,
- splt->contents + 6);
- bfd_put_32 (output_bfd,
- sgot->output_section->vma + sgot->output_offset + 8,
- splt->contents + 14);
-
- elf_section_data (splt->output_section)->this_hdr.sh_entsize
- = PLT_ENTRY_SIZE;
+ {
+ if (info->shared)
+ memcpy (splt->contents, elf_cris_pic_plt0_entry,
+ PLT_ENTRY_SIZE);
+ else
+ {
+ memcpy (splt->contents, elf_cris_plt0_entry,
+ PLT_ENTRY_SIZE);
+ bfd_put_32 (output_bfd,
+ sgot->output_section->vma
+ + sgot->output_offset + 4,
+ splt->contents + 6);
+ bfd_put_32 (output_bfd,
+ sgot->output_section->vma
+ + sgot->output_offset + 8,
+ splt->contents + 14);
+
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize
+ = PLT_ENTRY_SIZE;
+ }
}
}
}
for (rel = relocs; rel < relend; rel++)
{
unsigned long r_symndx;
- struct elf_link_hash_entry *h;
+ struct elf_link_hash_entry *h = NULL;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ 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;
+ }
switch (ELF32_R_TYPE (rel->r_info))
{
case R_CRIS_16_GOT:
case R_CRIS_32_GOT:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
+ if (h != NULL)
{
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
if (h->got.refcount > 0)
{
--h->got.refcount;
case R_CRIS_16_GOTPLT:
case R_CRIS_32_GOTPLT:
/* For local symbols, treat these like GOT relocs. */
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx < symtab_hdr->sh_info)
+ if (h == NULL)
goto local_got_reloc;
/* Fall through. */
+
case R_CRIS_32_PLT_GOTREL:
/* FIXME: We don't garbage-collect away the .got section. */
if (local_got_refcounts != NULL)
local_got_refcounts[-1]--;
/* Fall through. */
+
case R_CRIS_8_PCREL:
case R_CRIS_16_PCREL:
case R_CRIS_32_PCREL:
case R_CRIS_32_PLT_PCREL:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
+ if (h != NULL)
{
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& h->plt.refcount > 0)
--h->plt.refcount;
Probably not necessary at this stage, but keeping it accurate
helps avoiding surprises later. */
h->root.got.refcount += h->gotplt_refcount;
- h->gotplt_refcount = -1;
+ h->gotplt_refcount = 0;
}
else
{
/* Put an accurate refcount there. */
h->root.got.refcount = h->gotplt_refcount;
- h->gotplt_refcount = -1;
+ h->gotplt_refcount = 0;
/* We always have a .got and a .rela.got section if there were
GOTPLT relocs in input. */
bfd *dynobj;
asection *s;
unsigned int power_of_two;
+ bfd_size_type plt_entry_size;
dynobj = elf_hash_table (info)->dynobj;
/* Make sure we know what is going on here. */
BFD_ASSERT (dynobj != NULL
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
- || h->weakdef != NULL
- || ((h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)));
+ && (h->needs_plt
+ || h->u.weakdef != NULL
+ || (h->def_dynamic
+ && h->ref_regular
+ && !h->def_regular)));
+
+ plt_entry_size
+ = (bfd_get_mach (dynobj) == bfd_mach_cris_v32
+ ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE);
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
when we know the address of the .got section. */
if (h->type == STT_FUNC
- || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ || h->needs_plt)
{
/* If we link a program (not a DSO), we'll get rid of unnecessary
PLT entries; we point to the actual symbols -- even for pic
symbols.
FIXME: m68k and i386 differ here, for unclear reasons. */
if (! info->shared
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0)
+ && !h->def_dynamic)
{
/* This case can occur if we saw a PLT reloc in an input file,
but the symbol was not defined by a dynamic object. In such
a case, we don't actually need to build a procedure linkage
table, and we can just do an absolute or PC reloc instead, or
change a .got.plt index to a .got index for GOTPLT relocs. */
- BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ BFD_ASSERT (h->needs_plt);
+ h->needs_plt = 0;
h->plt.offset = (bfd_vma) -1;
return
elf_cris_adjust_gotplt_to_got ((struct
/* GC or folding may have rendered this entry unused. */
if (h->plt.refcount <= 0)
{
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
h->plt.offset = (bfd_vma) -1;
return TRUE;
}
/* If this is the first .plt entry, make room for the special
first entry. */
if (s->size == 0)
- s->size += PLT_ENTRY_SIZE;
+ s->size += plt_entry_size;
/* If this symbol is not defined in a regular file, and we are
not generating a shared library, then set the symbol to this
location in the .plt. */
if (!info->shared
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ && !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = s->size;
/* Mark the PLT offset to use the GOT entry by setting the low
bit in the plt offset; it is always a multiple of
- pointer-size. */
- BFD_ASSERT ((s->size & 3) == 0);
+ plt_entry_size (which is at least a multiple of 2). */
+ BFD_ASSERT ((s->size % plt_entry_size) == 0);
/* Change the PLT refcount to an offset. */
h->plt.offset = s->size;
h)->gotplt_offset == 0);
/* Make room for this entry. */
- s->size += PLT_ENTRY_SIZE;
+ s->size += plt_entry_size;
return TRUE;
}
h->plt.offset = s->size;
/* Make room for this entry. */
- s->size += PLT_ENTRY_SIZE;
+ s->size += plt_entry_size;
/* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->weakdef != NULL)
+ if (h->u.weakdef != NULL)
{
- BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
- || h->weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->weakdef->root.u.def.section;
- h->root.u.def.value = h->weakdef->root.u.def.value;
+ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+ || h->u.weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->u.weakdef->root.u.def.section;
+ h->root.u.def.value = h->u.weakdef->root.u.def.value;
return TRUE;
}
/* If there are no references to this symbol that do not use the
GOT, we don't need to generate a copy reloc. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
+ if (!h->non_got_ref)
return TRUE;
/* We must allocate the symbol in our .dynbss section, which will
srel = bfd_get_section_by_name (dynobj, ".rela.bss");
BFD_ASSERT (srel != NULL);
srel->size += sizeof (Elf32_External_Rela);
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+ h->needs_copy = 1;
}
/* Historic precedent: m68k and i386 allow max 8-byte alignment for the
{
elf_hash_table (info)->dynobj = dynobj = abfd;
+ /* We could handle this if we can get a handle on the
+ output bfd in elf_cris_adjust_dynamic_symbol. Failing
+ that, we must insist on dynobj being a specific mach. */
+ if (bfd_get_mach (dynobj) == bfd_mach_cris_v10_v32)
+ {
+ (*_bfd_error_handler)
+ (_("%B, section %A:\n v10/v32 compatible object %s"
+ " must not contain a PIC relocation"),
+ abfd, sec);
+ return FALSE;
+ }
+
/* Create the .got section, so we can assume it's always
present whenever there's a dynobj. */
if (!_bfd_elf_create_got_section (dynobj, info))
don't need to generate a procedure linkage table entry
after all. */
- /* If this is a local symbol, we resolve it directly without
- creating a procedure linkage table entry. */
- if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ /* Beware: if we'd check for visibility of the symbol here
+ (and not marking the need for a PLT when non-visible), we'd
+ get into trouble with keeping handling consistent with
+ regards to relocs found before definition and GOTPLT
+ handling. Eliminable PLT entries will be dealt with later
+ anyway. */
+ if (h == NULL)
continue;
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 1;
h->plt.refcount++;
break;
{
/* FIXME: How do we make this optionally a warning only? */
(*_bfd_error_handler)
- (_("%B, section %A:\n relocation %s should not be used in a shared object; recompile with -fPIC"),
+ (_("%B, section %A:\n relocation %s should not"
+ " be used in a shared object; recompile with -fPIC"),
abfd,
sec,
cris_elf_howto_table[r_type].name);
case R_CRIS_32_PCREL:
if (h != NULL)
{
- h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+ h->non_got_ref = 1;
/* Make sure a plt entry is created for this symbol if it
turns out to be a function defined by a dynamic object. */
we can't identify at this time. */
if (info->symbolic
&& h->root.type != bfd_link_hash_defweak
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+ && h->def_regular)
break;
+
+ if ((sec->flags & SEC_READONLY) != 0)
+ {
+ /* FIXME: How do we make this optionally a warning only? */
+ (*_bfd_error_handler)
+ (_("%B, section %A:\n relocation %s should not be used"
+ " in a shared object; recompile with -fPIC"),
+ abfd,
+ sec,
+ cris_elf_howto_table[r_type].name);
+ }
}
/* We create a reloc section in dynobj and make room for this
/* If a symbol has been forced local or we have found a regular
definition for the symbolic link case, then we won't be needing
any relocs. */
- if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
- && ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
+ if (h->root.def_regular
+ && (h->root.forced_local
|| info->symbolic))
{
for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
(or rather, not defined by a DSO) then lose the reloc for the .got
(don't allocate room for it). Likewise for relocs for something
for which we create a PLT. */
- if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ if (!h->root.def_dynamic
|| h->root.plt.refcount > 0)
{
if (h->root.got.refcount > 0
introduce new problems. Of course we don't do this if we're
exporting all dynamic symbols. */
if (! info->export_dynamic
- && (h->root.elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_DYNAMIC|ELF_LINK_HASH_REF_DYNAMIC)) == 0)
+ && h->root.dynindx != -1
+ && !h->root.def_dynamic
+ && !h->root.ref_dynamic)
{
h->root.dynindx = -1;
_bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
cris_elf_object_p (abfd)
bfd *abfd;
{
+ if (! cris_elf_set_mach_from_flags (abfd, elf_elfheader (abfd)->e_flags))
+ return FALSE;
+
if ((elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE))
return (bfd_get_symbol_leading_char (abfd) == '_');
else
return (bfd_get_symbol_leading_char (abfd) == 0);
}
-/* Mark presence or absence of leading underscore. */
+/* Mark presence or absence of leading underscore. Set machine type
+ flags from mach type. */
static void
cris_elf_final_write_processing (abfd, linker)
bfd *abfd;
bfd_boolean linker ATTRIBUTE_UNUSED;
{
+ unsigned long e_flags = elf_elfheader (abfd)->e_flags;
+
+ e_flags &= ~EF_CRIS_UNDERSCORE;
if (bfd_get_symbol_leading_char (abfd) == '_')
- elf_elfheader (abfd)->e_flags |= EF_CRIS_UNDERSCORE;
- else
- elf_elfheader (abfd)->e_flags &= ~EF_CRIS_UNDERSCORE;
+ e_flags |= EF_CRIS_UNDERSCORE;
+
+ switch (bfd_get_mach (abfd))
+ {
+ case bfd_mach_cris_v0_v10:
+ e_flags |= EF_CRIS_VARIANT_ANY_V0_V10;
+ break;
+
+ case bfd_mach_cris_v10_v32:
+ e_flags |= EF_CRIS_VARIANT_COMMON_V10_V32;
+ break;
+
+ case bfd_mach_cris_v32:
+ e_flags |= EF_CRIS_VARIANT_V32;
+ break;
+
+ default:
+ _bfd_abort (__FILE__, __LINE__,
+ _("Unexpected machine number"));
+ }
+
+ elf_elfheader (abfd)->e_flags = e_flags;
+}
+
+/* Set the mach type from e_flags value. */
+
+static bfd_boolean
+cris_elf_set_mach_from_flags (abfd, flags)
+ bfd *abfd;
+ unsigned long flags;
+{
+ switch (flags & EF_CRIS_VARIANT_MASK)
+ {
+ case EF_CRIS_VARIANT_ANY_V0_V10:
+ bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v0_v10);
+ break;
+
+ case EF_CRIS_VARIANT_V32:
+ bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v32);
+ break;
+
+ case EF_CRIS_VARIANT_COMMON_V10_V32:
+ bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v10_v32);
+ break;
+
+ default:
+ /* Since we don't recognize them, we obviously can't support them
+ with this code; we'd have to require that all future handling
+ would be optional. */
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ return TRUE;
}
/* Display the flags field. */
{
FILE *file = (FILE *) ptr;
- BFD_ASSERT (abfd != NULL && ptr != NULL)
+ BFD_ASSERT (abfd != NULL && ptr != NULL);
_bfd_elf_print_private_bfd_data (abfd, ptr);
if (elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE)
fprintf (file, _(" [symbols have a _ prefix]"));
+ if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK)
+ == EF_CRIS_VARIANT_COMMON_V10_V32)
+ fprintf (file, _(" [v10 and v32]"));
+ if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK)
+ == EF_CRIS_VARIANT_V32)
+ fprintf (file, _(" [v32]"));
fputc ('\n', file);
return TRUE;
bfd *ibfd;
bfd *obfd;
{
- flagword old_flags, new_flags;
+ int imach, omach;
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
+ imach = bfd_get_mach (ibfd);
+
if (! elf_flags_init (obfd))
{
/* This happens when ld starts out with a 'blank' output file. */
elf_flags_init (obfd) = TRUE;
- /* Set flags according to current bfd_target. */
- cris_elf_final_write_processing (obfd, FALSE);
+ /* We ignore the linker-set mach, and instead set it according to
+ the first input file. This would also happen if we could
+ somehow filter out the OUTPUT_ARCH () setting from elf.sc.
+ This allows us to keep the same linker config across
+ cris(v0..v10) and crisv32. The drawback is that we can't force
+ the output type, which might be a sane thing to do for a
+ v10+v32 compatibility object. */
+ if (! bfd_set_arch_mach (obfd, bfd_arch_cris, imach))
+ return FALSE;
}
- old_flags = elf_elfheader (obfd)->e_flags;
- new_flags = elf_elfheader (ibfd)->e_flags;
-
- /* Is this good or bad? We'll follow with other excluding flags. */
- if ((old_flags & EF_CRIS_UNDERSCORE) != (new_flags & EF_CRIS_UNDERSCORE))
+ if (bfd_get_symbol_leading_char (ibfd)
+ != bfd_get_symbol_leading_char (obfd))
{
(*_bfd_error_handler)
- ((new_flags & EF_CRIS_UNDERSCORE)
+ (bfd_get_symbol_leading_char (ibfd) == '_'
? _("%B: uses _-prefixed symbols, but writing file with non-prefixed symbols")
: _("%B: uses non-prefixed symbols, but writing file with _-prefixed symbols"),
ibfd);
return FALSE;
}
+ omach = bfd_get_mach (obfd);
+
+ if (imach != omach)
+ {
+ /* We can get an incompatible combination only if either is
+ bfd_mach_cris_v32, and the other one isn't compatible. */
+ if ((imach == bfd_mach_cris_v32
+ && omach != bfd_mach_cris_v10_v32)
+ || (omach == bfd_mach_cris_v32
+ && imach != bfd_mach_cris_v10_v32))
+ {
+ (*_bfd_error_handler)
+ ((imach == bfd_mach_cris_v32)
+ ? _("%B contains CRIS v32 code, incompatible"
+ " with previous objects")
+ : _("%B contains non-CRIS-v32 code, incompatible"
+ " with previous objects"),
+ ibfd);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* We don't have to check the case where the input is compatible
+ with v10 and v32, because the output is already known to be set
+ to the other (compatible) mach. */
+ if (omach == bfd_mach_cris_v10_v32
+ && ! bfd_set_arch_mach (obfd, bfd_arch_cris, imach))
+ return FALSE;
+ }
+
return TRUE;
}
+/* Do side-effects of e_flags copying to obfd. */
+
+static bfd_boolean
+cris_elf_copy_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ /* Call the base function. */
+ if (!_bfd_elf_copy_private_bfd_data (ibfd, obfd))
+ return FALSE;
+
+ /* If output is big-endian for some obscure reason, stop here. */
+ if (_bfd_generic_verify_endian_match (ibfd, obfd) == FALSE)
+ return FALSE;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return TRUE;
+
+ /* Do what we really came here for. */
+ return bfd_set_arch_mach (obfd, bfd_arch_cris, bfd_get_mach (ibfd));
+}
static enum elf_reloc_type_class
elf_cris_reloc_type_class (rela)
cris_elf_print_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data \
cris_elf_merge_private_bfd_data
+#define bfd_elf32_bfd_copy_private_bfd_data \
+ cris_elf_copy_private_bfd_data
#define bfd_elf32_bfd_reloc_type_lookup cris_reloc_type_lookup