#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/cris.h"
static reloc_howto_type * cris_reloc_type_lookup
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
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 bfd_boolean cris_elf_grok_psinfo
PARAMS ((bfd *abfd, Elf_Internal_Note *note));
static bfd_boolean cris_elf_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static bfd_reloc_status_type cris_final_link_relocate
PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, bfd_vma));
static bfd_boolean cris_elf_gc_sweep_hook
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static asection * cris_elf_gc_mark_hook
PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
static bfd_boolean cris_elf_object_p PARAMS ((bfd *));
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
PARAMS ((struct elf_cris_link_hash_entry *, PTR));
static bfd_boolean elf_cris_discard_excess_program_dynamics
PARAMS ((struct elf_cris_link_hash_entry *, PTR));
static bfd_boolean elf_cris_adjust_gotplt_to_got
PARAMS ((struct elf_cris_link_hash_entry *, PTR));
static bfd_boolean elf_cris_try_fold_plt_to_got
PARAMS ((struct elf_cris_link_hash_entry *, PTR));
static struct bfd_hash_entry *elf_cris_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct bfd_link_hash_table *elf_cris_link_hash_table_create
PARAMS ((bfd *));
static bfd_boolean elf_cris_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static bfd_boolean cris_elf_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static bfd_boolean elf_cris_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean elf_cris_finish_dynamic_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
Elf_Internal_Sym *));
static bfd_boolean elf_cris_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static void elf_cris_hide_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean));
static enum elf_reloc_type_class elf_cris_reloc_type_class
PARAMS ((const Elf_Internal_Rela *));
static reloc_howto_type cris_elf_howto_table [] =
{
HOWTO (R_CRIS_NONE,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_NONE",
FALSE,
0,
0,
FALSE),
HOWTO (R_CRIS_8,
0,
0,
8,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_8",
FALSE,
0x0000,
0x00ff,
FALSE),
HOWTO (R_CRIS_16,
0,
1,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_16",
FALSE,
0x00000000,
0x0000ffff,
FALSE),
HOWTO (R_CRIS_32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_32",
FALSE,
0x00000000,
0xffffffff,
FALSE),
HOWTO (R_CRIS_8_PCREL,
0,
0,
8,
TRUE,
0,
complain_overflow_bitfield,
cris_elf_pcrel_reloc,
"R_CRIS_8_PCREL",
FALSE,
0x0000,
0x00ff,
TRUE),
HOWTO (R_CRIS_16_PCREL,
0,
1,
16,
TRUE,
0,
complain_overflow_bitfield,
cris_elf_pcrel_reloc,
"R_CRIS_16_PCREL",
FALSE,
0x00000000,
0x0000ffff,
TRUE),
HOWTO (R_CRIS_32_PCREL,
0,
2,
32,
TRUE,
0,
complain_overflow_bitfield,
cris_elf_pcrel_reloc,
"R_CRIS_32_PCREL",
FALSE,
0x00000000,
0xffffffff,
TRUE),
HOWTO (R_CRIS_GNU_VTINHERIT,
0,
2,
0,
FALSE,
0,
complain_overflow_dont,
NULL,
"R_CRIS_GNU_VTINHERIT",
FALSE,
0,
0,
FALSE),
HOWTO (R_CRIS_GNU_VTENTRY,
0,
2,
0,
FALSE,
0,
complain_overflow_dont,
_bfd_elf_rel_vtable_reloc_fn,
"R_CRIS_GNU_VTENTRY",
FALSE,
0,
0,
FALSE),
HOWTO (R_CRIS_COPY,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_COPY",
FALSE,
0,
0,
FALSE),
HOWTO (R_CRIS_GLOB_DAT,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_GLOB_DAT",
FALSE,
0,
0xffffffff,
FALSE),
HOWTO (R_CRIS_JUMP_SLOT,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_JUMP_SLOT",
FALSE,
0,
0,
FALSE),
HOWTO (R_CRIS_RELATIVE,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_RELATIVE",
FALSE,
0,
0xffffffff,
FALSE),
HOWTO (R_CRIS_16_GOT,
0,
1,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_16_GOT",
FALSE,
0,
0xffff,
FALSE),
HOWTO (R_CRIS_32_GOT,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_32_GOT",
FALSE,
0,
0xffffffff,
FALSE),
HOWTO (R_CRIS_16_GOTPLT,
0,
1,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_16_GOTPLT",
FALSE,
0,
0xffff,
FALSE),
HOWTO (R_CRIS_32_GOTPLT,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_32_GOTPLT",
FALSE,
0,
0xffffffff,
FALSE),
HOWTO (R_CRIS_32_GOTREL,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_32_GOTREL",
FALSE,
0,
0xffffffff,
FALSE),
HOWTO (R_CRIS_32_PLT_GOTREL,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_CRIS_32_PLT_GOTREL",
FALSE,
0,
0xffffffff,
FALSE),
HOWTO (R_CRIS_32_PLT_PCREL,
0,
2,
32,
TRUE,
0,
complain_overflow_bitfield,
cris_elf_pcrel_reloc,
"R_CRIS_32_PLT_PCREL",
FALSE,
0,
0xffffffff,
TRUE)
};
struct cris_reloc_map
{
bfd_reloc_code_real_type bfd_reloc_val;
unsigned int cris_reloc_val;
};
static const struct cris_reloc_map cris_reloc_map [] =
{
{ BFD_RELOC_NONE, R_CRIS_NONE },
{ BFD_RELOC_8, R_CRIS_8 },
{ BFD_RELOC_16, R_CRIS_16 },
{ BFD_RELOC_32, R_CRIS_32 },
{ BFD_RELOC_8_PCREL, R_CRIS_8_PCREL },
{ BFD_RELOC_16_PCREL, R_CRIS_16_PCREL },
{ BFD_RELOC_32_PCREL, R_CRIS_32_PCREL },
{ BFD_RELOC_VTABLE_INHERIT, R_CRIS_GNU_VTINHERIT },
{ BFD_RELOC_VTABLE_ENTRY, R_CRIS_GNU_VTENTRY },
{ BFD_RELOC_CRIS_COPY, R_CRIS_COPY },
{ BFD_RELOC_CRIS_GLOB_DAT, R_CRIS_GLOB_DAT },
{ BFD_RELOC_CRIS_JUMP_SLOT, R_CRIS_JUMP_SLOT },
{ BFD_RELOC_CRIS_RELATIVE, R_CRIS_RELATIVE },
{ BFD_RELOC_CRIS_16_GOT, R_CRIS_16_GOT },
{ BFD_RELOC_CRIS_32_GOT, R_CRIS_32_GOT },
{ BFD_RELOC_CRIS_16_GOTPLT, R_CRIS_16_GOTPLT },
{ BFD_RELOC_CRIS_32_GOTPLT, R_CRIS_32_GOTPLT },
{ BFD_RELOC_CRIS_32_GOTREL, R_CRIS_32_GOTREL },
{ BFD_RELOC_CRIS_32_PLT_GOTREL, R_CRIS_32_PLT_GOTREL },
{ BFD_RELOC_CRIS_32_PLT_PCREL, R_CRIS_32_PLT_PCREL }
};
static reloc_howto_type *
cris_reloc_type_lookup (abfd, code)
bfd * abfd ATTRIBUTE_UNUSED;
bfd_reloc_code_real_type code;
{
unsigned int i;
for (i = 0; i < sizeof (cris_reloc_map) / sizeof (cris_reloc_map[0]); i++)
if (cris_reloc_map [i].bfd_reloc_val == code)
return & cris_elf_howto_table [cris_reloc_map[i].cris_reloc_val];
return NULL;
}
static void
cris_info_to_howto_rela (abfd, cache_ptr, dst)
bfd * abfd ATTRIBUTE_UNUSED;
arelent * cache_ptr;
Elf_Internal_Rela * dst;
{
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
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;
{
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);
}
static bfd_boolean
cris_elf_grok_prstatus (abfd, note)
bfd *abfd;
Elf_Internal_Note *note;
{
int offset;
size_t size;
if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
switch (note->descsz)
{
default:
return FALSE;
case 202:
elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 22);
offset = 70;
size = 128;
break;
}
else
switch (note->descsz)
{
default:
return FALSE;
case 214:
elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 22);
offset = 70;
size = 140;
break;
}
return _bfd_elfcore_make_pseudosection (abfd, ".reg",
size, note->descpos + offset);
}
static bfd_boolean
cris_elf_grok_psinfo (abfd, note)
bfd *abfd;
Elf_Internal_Note *note;
{
if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
switch (note->descsz)
{
default:
return FALSE;
case 124:
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:
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);
}
{
char *command = elf_tdata (abfd)->core_command;
int n = strlen (command);
if (0 < n && command[n - 1] == ' ')
command[n - 1] = '\0';
}
return TRUE;
}
#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
#define PLT_ENTRY_SIZE 20
#define PLT_ENTRY_SIZE_V32 26
static const bfd_byte elf_cris_plt0_entry[PLT_ENTRY_SIZE] =
{
0xfc, 0xe1,
0x7e, 0x7e,
0x7f, 0x0d,
0, 0, 0, 0,
0x30, 0x7a,
0x7f, 0x0d,
0, 0, 0, 0,
0x30, 0x09
};
static const bfd_byte elf_cris_plt0_entry_v32[PLT_ENTRY_SIZE_V32] =
{
0x84, 0xe2,
0x6f, 0xfe,
0, 0, 0, 0,
0x7e, 0x7a,
0x3f, 0x7a,
0x04, 0xf2,
0x6f, 0xfa,
0xbf, 0x09,
0xb0, 0x05,
0, 0
};
static const bfd_byte elf_cris_plt_entry[PLT_ENTRY_SIZE] =
{
0x7f, 0x0d,
0, 0, 0, 0,
0x30, 0x09,
0x3f, 0x7e,
0, 0, 0, 0,
0x2f, 0xfe,
0xec, 0xff,
0xff, 0xff
};
static const bfd_byte elf_cris_plt_entry_v32[PLT_ENTRY_SIZE_V32] =
{
0x6f, 0xfe,
0, 0, 0, 0,
0x6f, 0xfa,
0xbf, 0x09,
0xb0, 0x05,
0x3f, 0x7e,
0, 0, 0, 0,
0xbf, 0x0e,
0, 0, 0, 0,
0xb0, 0x05
};
static const bfd_byte elf_cris_pic_plt0_entry[PLT_ENTRY_SIZE] =
{
0xfc, 0xe1, 0x7e, 0x7e,
0x04, 0x01, 0x30, 0x7a,
0x08, 0x01, 0x30, 0x09,
0, 0, 0, 0, 0, 0, 0, 0,
};
static const bfd_byte elf_cris_pic_plt0_entry_v32[PLT_ENTRY_SIZE_V32] =
{
0x84, 0xe2,
0x04, 0x01,
0x7e, 0x7a,
0x3f, 0x7a,
0x04, 0xf2,
0x6f, 0xfa,
0xbf, 0x09,
0xb0, 0x05,
0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
static const bfd_byte elf_cris_pic_plt_entry[PLT_ENTRY_SIZE] =
{
0x6f, 0x0d,
0, 0, 0, 0,
0x30, 0x09,
0x3f, 0x7e,
0, 0, 0, 0,
0x2f, 0xfe,
0xec, 0xff,
0xff, 0xff
};
static const bfd_byte elf_cris_pic_plt_entry_v32[PLT_ENTRY_SIZE_V32] =
{
0x6f, 0x0d,
0, 0, 0, 0,
0x6f, 0xfa,
0xbf, 0x09,
0xb0, 0x05,
0x3f, 0x7e,
0, 0, 0, 0,
0xbf, 0x0e,
0, 0, 0, 0,
0xb0, 0x05
};
struct elf_cris_pcrel_relocs_copied
{
struct elf_cris_pcrel_relocs_copied *next;
asection *section;
bfd_size_type count;
};
struct elf_cris_link_hash_entry
{
struct elf_link_hash_entry root;
struct elf_cris_pcrel_relocs_copied *pcrel_relocs_copied;
bfd_signed_vma gotplt_refcount;
bfd_size_type gotplt_offset;
};
struct elf_cris_link_hash_table
{
struct elf_link_hash_table root;
bfd_size_type next_gotplt_entry;
};
#define elf_cris_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
(bfd_boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \
(info)))
#define elf_cris_hash_table(p) \
((struct elf_cris_link_hash_table *) (p)->hash)
static struct bfd_hash_entry *
elf_cris_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct elf_cris_link_hash_entry *ret =
(struct elf_cris_link_hash_entry *) entry;
if (ret == (struct elf_cris_link_hash_entry *) NULL)
ret = ((struct elf_cris_link_hash_entry *)
bfd_hash_allocate (table,
sizeof (struct elf_cris_link_hash_entry)));
if (ret == (struct elf_cris_link_hash_entry *) NULL)
return (struct bfd_hash_entry *) ret;
ret = ((struct elf_cris_link_hash_entry *)
_bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != (struct elf_cris_link_hash_entry *) NULL)
{
ret->pcrel_relocs_copied = NULL;
ret->gotplt_refcount = 0;
ret->gotplt_offset = 0;
}
return (struct bfd_hash_entry *) ret;
}
static struct bfd_link_hash_table *
elf_cris_link_hash_table_create (abfd)
bfd *abfd;
{
struct elf_cris_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_cris_link_hash_table);
ret = ((struct elf_cris_link_hash_table *) bfd_malloc (amt));
if (ret == (struct elf_cris_link_hash_table *) NULL)
return NULL;
if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
elf_cris_link_hash_newfunc))
{
free (ret);
return NULL;
}
ret->next_gotplt_entry = 12;
return &ret->root.root;
}
static bfd_reloc_status_type
cris_final_link_relocate (howto, input_bfd, input_section, contents, rel,
relocation)
reloc_howto_type * howto;
bfd * input_bfd;
asection * input_section;
bfd_byte * contents;
Elf_Internal_Rela * rel;
bfd_vma relocation;
{
bfd_reloc_status_type r;
switch (ELF32_R_TYPE (rel->r_info))
{
case R_CRIS_16_GOTPLT:
case R_CRIS_16_GOT:
if ((bfd_signed_vma) relocation < 0)
return bfd_reloc_overflow;
break;
case R_CRIS_32_PLT_PCREL:
case R_CRIS_32_PCREL:
relocation -= 2;
case R_CRIS_8_PCREL:
case R_CRIS_16_PCREL:
relocation -= 2;
break;
default:
break;
}
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, rel->r_addend);
return r;
}
static bfd_boolean
cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
contents, relocs, local_syms, local_sections)
bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
Elf_Internal_Rela *relocs;
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets;
asection *sgot;
asection *splt;
asection *sreloc;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
if (info->relocatable)
return TRUE;
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (input_bfd);
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
sgot = NULL;
splt = NULL;
sreloc = NULL;
if (dynobj != NULL)
{
splt = bfd_get_section_by_name (dynobj, ".plt");
sgot = bfd_get_section_by_name (dynobj, ".got");
}
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 *symname = NULL;
int r_type;
r_type = ELF32_R_TYPE (rel->r_info);
if ( r_type == R_CRIS_GNU_VTINHERIT
|| r_type == R_CRIS_GNU_VTENTRY)
continue;
r_symndx = ELF32_R_SYM (rel->r_info);
howto = cris_elf_howto_table + r_type;
h = NULL;
sym = NULL;
sec = NULL;
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);
symname = (bfd_elf_string_from_elf_section
(input_bfd, symtab_hdr->sh_link, sym->st_name));
if (symname == NULL)
symname = bfd_section_name (input_bfd, sec);
}
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);
if (unresolved_reloc
&& (sec->owner->flags & DYNAMIC) != 0)
relocation = 0;
else if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
if (info->shared
&& ((! info->symbolic && h->dynindx != -1)
|| !h->def_regular)
&& (input_section->flags & SEC_ALLOC) != 0
&& (r_type == R_CRIS_8
|| r_type == R_CRIS_16
|| r_type == R_CRIS_32
|| r_type == R_CRIS_8_PCREL
|| r_type == R_CRIS_16_PCREL
|| r_type == R_CRIS_32_PCREL))
relocation = 0;
else if (unresolved_reloc)
{
_bfd_error_handler
(_("%B, section %A: unresolvable relocation %s against symbol `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
symname);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
}
switch (r_type)
{
case R_CRIS_16_GOTPLT:
case R_CRIS_32_GOTPLT:
if (h != NULL
&& ((struct elf_cris_link_hash_entry *) h)->gotplt_offset != 0)
{
asection *sgotplt
= bfd_get_section_by_name (dynobj, ".got.plt");
bfd_vma got_offset;
BFD_ASSERT (h->dynindx != -1);
BFD_ASSERT (sgotplt != NULL);
got_offset
= ((struct elf_cris_link_hash_entry *) h)->gotplt_offset;
relocation = got_offset;
break;
}
if (h != NULL
&& (h->got.offset == (bfd_vma) -1
|| (!info->shared
&& !(h->def_regular
|| (!h->def_dynamic
&& h->root.type == bfd_link_hash_undefweak)))))
{
(*_bfd_error_handler)
((h->got.offset == (bfd_vma) -1)
? _("%B, section %A: No PLT nor GOT for relocation %s"
" against symbol `%s'")
: _("%B, section %A: No PLT for relocation %s"
" against symbol `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
(symname != NULL && symname[0] != '\0'
? symname : _("[whose name is lost]")));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
case R_CRIS_16_GOT:
case R_CRIS_32_GOT:
{
bfd_vma off;
if (h != NULL)
{
off = h->got.offset;
BFD_ASSERT (off != (bfd_vma) -1);
if (!elf_hash_table (info)->dynamic_sections_created
|| (! info->shared
&& (h->def_regular
|| h->type == STT_FUNC
|| h->needs_plt))
|| (info->shared
&& (info->symbolic || h->dynindx == -1)
&& h->def_regular))
{
BFD_ASSERT (!elf_hash_table (info)->dynamic_sections_created
|| info->shared
|| h->def_regular
|| h->type == STT_FUNC
|| h->needs_plt
|| h->root.type == bfd_link_hash_undefweak);
if ((off & 1) != 0)
off &= ~1;
else
{
bfd_put_32 (output_bfd, relocation,
sgot->contents + off);
h->got.offset |= 1;
}
}
}
else
{
BFD_ASSERT (local_got_offsets != NULL
&& local_got_offsets[r_symndx] != (bfd_vma) -1);
off = local_got_offsets[r_symndx];
if ((off & 1) != 0)
off &= ~1;
else
{
bfd_put_32 (output_bfd, relocation, sgot->contents + off);
if (info->shared)
{
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_CRIS_RELATIVE);
outrel.r_addend = relocation;
loc = s->contents;
loc += s->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
}
local_got_offsets[r_symndx] |= 1;
}
}
relocation = sgot->output_offset + off;
if (rel->r_addend != 0)
{
if (h == NULL)
(*_bfd_error_handler)
(_("%B, section %A: relocation %s with non-zero addend %d"
" against local symbol"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
rel->r_addend);
else
(*_bfd_error_handler)
(_("%B, section %A: relocation %s with non-zero addend %d"
" against symbol `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
rel->r_addend,
symname[0] != '\0' ? symname : _("[whose name is lost]"));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
break;
case R_CRIS_32_GOTREL:
if (h != NULL
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& !(!info->shared
&& (h->def_regular
|| (!h->def_dynamic
&& h->root.type == bfd_link_hash_undefweak))))
{
(*_bfd_error_handler)
(_("%B, section %A: relocation %s is"
" not allowed for global symbol: `%s'"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name,
symname);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (sgot == NULL)
{
(*_bfd_error_handler)
(_("%B, section %A: relocation %s with no GOT created"),
input_bfd,
input_section,
cris_elf_howto_table[r_type].name);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
relocation -= sgot->output_section->vma;
break;
case R_CRIS_32_PLT_PCREL:
if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
break;
if (h->plt.offset == (bfd_vma) -1
|| splt == NULL)
{
break;
}
relocation = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset);
break;
case R_CRIS_32_PLT_GOTREL:
relocation -= sgot->output_section->vma;
if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
break;
if (h->plt.offset == (bfd_vma) -1
|| splt == NULL)
{
break;
}
relocation = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset
- sgot->output_section->vma);
break;
case R_CRIS_8_PCREL:
case R_CRIS_16_PCREL:
case R_CRIS_32_PCREL:
if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
break;
case R_CRIS_8:
case R_CRIS_16:
case R_CRIS_32:
if (info->shared
&& r_symndx != 0
&& (input_section->flags & SEC_ALLOC) != 0
&& ((r_type != R_CRIS_8_PCREL
&& r_type != R_CRIS_16_PCREL
&& r_type != R_CRIS_32_PCREL)
|| (!info->symbolic
|| !h->def_regular)))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
bfd_boolean skip, relocate;
if (sreloc == NULL)
{
const char *name;
name = (bfd_elf_string_from_elf_section
(input_bfd,
elf_elfheader (input_bfd)->e_shstrndx,
elf_section_data (input_section)->rel_hdr.sh_name));
if (name == NULL)
return FALSE;
BFD_ASSERT (strncmp (name, ".rela", 5) == 0
&& strcmp (bfd_get_section_name (input_bfd,
input_section),
name + 5) == 0);
sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
{
(*_bfd_error_handler)
(_("%B: Internal inconsistency; no relocation section %s"),
input_bfd,
name);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
skip = FALSE;
relocate = FALSE;
outrel.r_offset =
_bfd_elf_section_offset (output_bfd, info, input_section,
rel->r_offset);
if (outrel.r_offset == (bfd_vma) -1)
skip = TRUE;
else if (outrel.r_offset == (bfd_vma) -2)
skip = TRUE, relocate = TRUE;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
if (skip)
memset (&outrel, 0, sizeof outrel);
else if (h != NULL
&& ((! info->symbolic && h->dynindx != -1)
|| !h->def_regular))
{
BFD_ASSERT (h->dynindx != -1);
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
outrel.r_addend = relocation + rel->r_addend;
}
else
{
if (r_type == R_CRIS_32)
{
relocate = TRUE;
outrel.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE);
outrel.r_addend = relocation + rel->r_addend;
}
else
{
long indx;
if (bfd_is_abs_section (sec))
indx = 0;
else if (sec == NULL || sec->owner == NULL)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
else
{
asection *osec;
osec = sec->output_section;
indx = elf_section_data (osec)->dynindx;
BFD_ASSERT (indx > 0);
}
outrel.r_info = ELF32_R_INFO (indx, r_type);
outrel.r_addend = relocation + rel->r_addend;
}
}
loc = sreloc->contents;
loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
if (!relocate)
continue;
}
break;
}
r = cris_final_link_relocate (howto, input_bfd, input_section,
contents, rel, relocation);
if (r != bfd_reloc_ok)
{
const char * msg = (const char *) NULL;
switch (r)
{
case bfd_reloc_overflow:
r = info->callbacks->reloc_overflow
(info, (h ? &h->root : NULL), symname, howto->name,
(bfd_vma) 0, input_bfd, input_section, rel->r_offset);
break;
case bfd_reloc_undefined:
r = info->callbacks->undefined_symbol
(info, symname, 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, symname, input_bfd, input_section, rel->r_offset);
if (! r)
return FALSE;
}
}
return TRUE;
}
static bfd_boolean
elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
bfd *output_bfd;
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
{
bfd *dynobj;
int plt_off1 = 2, plt_off2 = 10, plt_off3 = 16;
int plt_off3_value_bias = 4;
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;
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)
{
asection *splt;
asection *sgotplt;
asection *sgot;
asection *srela;
bfd_vma got_base;
bfd_vma gotplt_offset
= ((struct elf_cris_link_hash_entry *) h)->gotplt_offset;
Elf_Internal_Rela rela;
bfd_byte *loc;
bfd_boolean has_gotplt = gotplt_offset != 0;
bfd_vma gotplt_index = gotplt_offset/4 - 3;
bfd_vma got_offset
= (has_gotplt
? gotplt_offset
: h->got.offset + elf_cris_hash_table(info)->next_gotplt_entry);
BFD_ASSERT (h->dynindx != -1);
splt = bfd_get_section_by_name (dynobj, ".plt");
sgot = bfd_get_section_by_name (dynobj, ".got");
sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
srela = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (splt != NULL && sgotplt != NULL
&& (! has_gotplt || srela != NULL));
got_base = sgotplt->output_section->vma + sgotplt->output_offset;
if (! info->shared)
{
memcpy (splt->contents + h->plt.offset, plt_entry,
plt_entry_size);
bfd_put_32 (output_bfd, got_base + got_offset,
splt->contents + h->plt.offset + plt_off1);
}
else
{
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);
}
if (has_gotplt)
{
bfd_put_32 (output_bfd,
gotplt_index * sizeof (Elf32_External_Rela),
splt->contents + h->plt.offset + plt_off2);
bfd_put_32 (output_bfd,
- (h->plt.offset + plt_off3 + plt_off3_value_bias),
splt->contents + h->plt.offset + plt_off3);
bfd_put_32 (output_bfd,
(splt->output_section->vma
+ splt->output_offset
+ h->plt.offset
+ plt_stub_offset),
sgotplt->contents + got_offset);
rela.r_offset = (sgotplt->output_section->vma
+ sgotplt->output_offset
+ got_offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_JUMP_SLOT);
rela.r_addend = 0;
loc = srela->contents + gotplt_index * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
if (!h->def_regular)
{
sym->st_shndx = SHN_UNDEF;
if (!h->ref_regular_nonweak)
sym->st_value = 0;
}
}
if (h->got.offset != (bfd_vma) -1
&& (info->shared
|| (h->dynindx != -1
&& h->plt.offset == (bfd_vma) -1
&& !h->def_regular
&& h->root.type != bfd_link_hash_undefweak)))
{
asection *sgot;
asection *srela;
Elf_Internal_Rela rela;
bfd_byte *loc;
bfd_byte *where;
sgot = bfd_get_section_by_name (dynobj, ".got");
srela = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (sgot != NULL && srela != NULL);
rela.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ (h->got.offset &~ (bfd_vma) 1));
where = sgot->contents + (h->got.offset &~ (bfd_vma) 1);
if (! elf_hash_table (info)->dynamic_sections_created
|| (info->shared
&& (info->symbolic || h->dynindx == -1)
&& h->def_regular))
{
rela.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE);
rela.r_addend = bfd_get_signed_32 (output_bfd, where);
}
else
{
bfd_put_32 (output_bfd, (bfd_vma) 0, where);
rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_GLOB_DAT);
rela.r_addend = 0;
}
loc = srela->contents;
loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
if (h->needs_copy)
{
asection *s;
Elf_Internal_Rela rela;
bfd_byte *loc;
BFD_ASSERT (h->dynindx != -1
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak));
s = bfd_get_section_by_name (h->root.u.def.section->owner,
".rela.bss");
BFD_ASSERT (s != NULL);
rela.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_COPY);
rela.r_addend = 0;
loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
sym->st_shndx = SHN_ABS;
return TRUE;
}
static bfd_boolean
elf_cris_finish_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
bfd *dynobj;
asection *sgot;
asection *sdyn;
dynobj = elf_hash_table (info)->dynobj;
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgot != NULL);
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
if (elf_hash_table (info)->dynamic_sections_created)
{
asection *splt;
Elf32_External_Dyn *dyncon, *dynconend;
splt = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (splt != NULL && sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
asection *s;
bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
default:
break;
case DT_PLTGOT:
s = bfd_get_section_by_name (output_bfd, ".got");
BFD_ASSERT (s != NULL);
dyn.d_un.d_ptr = s->vma;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_JMPREL:
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
dyn.d_un.d_ptr = s != NULL ? s->vma : 0;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_PLTRELSZ:
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
if (s == NULL)
dyn.d_un.d_val = 0;
else
dyn.d_un.d_val = s->size;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_RELASZ:
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
if (s != NULL)
dyn.d_un.d_val -= s->size;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
}
}
if (splt->size > 0)
{
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
{
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;
}
}
}
}
if (sgot->size > 0)
{
if (sdyn == NULL)
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
else
bfd_put_32 (output_bfd,
sdyn->output_section->vma + sdyn->output_offset,
sgot->contents);
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
}
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
return TRUE;
}
static asection *
cris_elf_gc_mark_hook (sec, info, rel, h, sym)
asection *sec;
struct bfd_link_info *info ATTRIBUTE_UNUSED;
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_CRIS_GNU_VTINHERIT:
case R_CRIS_GNU_VTENTRY:
break;
default:
switch (h->root.type)
{
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
return h->root.u.def.section;
case bfd_link_hash_common:
return h->root.u.c.p->section;
default:
break;
}
}
}
else
return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
return NULL;
}
static bfd_boolean
cris_elf_gc_sweep_hook (abfd, info, sec, relocs)
bfd *abfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info ATTRIBUTE_UNUSED;
asection *sec ATTRIBUTE_UNUSED;
const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
{
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 = 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:
if (h != NULL)
{
if (h->got.refcount > 0)
{
--h->got.refcount;
if (h->got.refcount == 0)
{
sgot->size -= 4;
srelgot->size -= sizeof (Elf32_External_Rela);
}
}
break;
}
local_got_reloc:
if (local_got_refcounts != NULL)
{
if (local_got_refcounts[r_symndx] > 0)
{
--local_got_refcounts[r_symndx];
if (local_got_refcounts[r_symndx] == 0)
{
sgot->size -= 4;
if (info->shared)
srelgot->size -= sizeof (Elf32_External_Rela);
}
}
}
break;
case R_CRIS_16_GOTPLT:
case R_CRIS_32_GOTPLT:
if (h == NULL)
goto local_got_reloc;
case R_CRIS_32_PLT_GOTREL:
if (local_got_refcounts != NULL)
local_got_refcounts[-1]--;
case R_CRIS_8_PCREL:
case R_CRIS_16_PCREL:
case R_CRIS_32_PCREL:
case R_CRIS_32_PLT_PCREL:
if (h != NULL)
{
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& h->plt.refcount > 0)
--h->plt.refcount;
}
break;
default:
break;
}
}
return TRUE;
}
static bfd_boolean
elf_cris_adjust_gotplt_to_got (h, p)
struct elf_cris_link_hash_entry *h;
PTR p;
{
struct bfd_link_info *info = (struct bfd_link_info *) p;
bfd *dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
if (h->root.root.type == bfd_link_hash_warning)
h = (struct elf_cris_link_hash_entry *) h->root.root.u.i.link;
if (h->gotplt_refcount <= 0)
return TRUE;
if (h->root.got.refcount > 0)
{
h->root.got.refcount += h->gotplt_refcount;
h->gotplt_refcount = 0;
}
else
{
asection *sgot = bfd_get_section_by_name (dynobj, ".got");
asection *srelgot
= bfd_get_section_by_name (dynobj, ".rela.got");
h->root.got.refcount = h->gotplt_refcount;
h->gotplt_refcount = 0;
BFD_ASSERT (sgot != NULL && srelgot != NULL);
sgot->size += 4;
srelgot->size += sizeof (Elf32_External_Rela);
}
return TRUE;
}
static bfd_boolean
elf_cris_try_fold_plt_to_got (h, p)
struct elf_cris_link_hash_entry *h;
PTR p;
{
struct bfd_link_info *info = (struct bfd_link_info *) p;
if (h->root.got.refcount <= 0 || h->root.plt.refcount <= 0)
return TRUE;
BFD_ASSERT (h->gotplt_refcount <= h->root.plt.refcount);
if (h->gotplt_refcount == h->root.plt.refcount)
{
if (! elf_cris_adjust_gotplt_to_got (h, info))
return FALSE;
h->root.plt.offset = (bfd_vma) -1;
}
return TRUE;
}
static void
elf_cris_hide_symbol (info, h, force_local)
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
bfd_boolean force_local;
{
elf_cris_adjust_gotplt_to_got ((struct elf_cris_link_hash_entry *) h, info);
_bfd_elf_link_hash_hide_symbol (info, h, force_local);
}
static bfd_boolean
elf_cris_adjust_dynamic_symbol (info, h)
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
{
bfd *dynobj;
asection *s;
unsigned int power_of_two;
bfd_size_type plt_entry_size;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL
&& (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 (h->type == STT_FUNC
|| h->needs_plt)
{
if (! info->shared
&& !h->def_dynamic)
{
BFD_ASSERT (h->needs_plt);
h->needs_plt = 0;
h->plt.offset = (bfd_vma) -1;
return
elf_cris_adjust_gotplt_to_got ((struct
elf_cris_link_hash_entry *) h,
info);
}
if (info->shared
&& !elf_cris_try_fold_plt_to_got ((struct elf_cris_link_hash_entry*)
h, info))
return FALSE;
if (h->plt.refcount <= 0)
{
h->needs_plt = 0;
h->plt.offset = (bfd_vma) -1;
return TRUE;
}
if (h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
if (s->size == 0)
s->size += plt_entry_size;
if (!info->shared
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = s->size;
}
if (info->shared && h->got.refcount > 0)
{
h->got.refcount += h->plt.refcount;
BFD_ASSERT ((s->size % plt_entry_size) == 0);
h->plt.offset = s->size;
BFD_ASSERT (((struct elf_cris_link_hash_entry *)
h)->gotplt_offset == 0);
s->size += plt_entry_size;
return TRUE;
}
h->plt.offset = s->size;
s->size += plt_entry_size;
((struct elf_cris_link_hash_entry *) h)->gotplt_offset
= elf_cris_hash_table (info)->next_gotplt_entry;
elf_cris_hash_table (info)->next_gotplt_entry += 4;
s = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (s != NULL);
s->size += 4;
s = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (s != NULL);
s->size += sizeof (Elf32_External_Rela);
return TRUE;
}
h->plt.offset = (bfd_vma) -1;
if (h->u.weakdef != NULL)
{
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 (info->shared)
return TRUE;
if (!h->non_got_ref)
return TRUE;
s = bfd_get_section_by_name (dynobj, ".dynbss");
BFD_ASSERT (s != NULL);
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
asection *srel;
srel = bfd_get_section_by_name (dynobj, ".rela.bss");
BFD_ASSERT (srel != NULL);
srel->size += sizeof (Elf32_External_Rela);
h->needs_copy = 1;
}
power_of_two = bfd_log2 (h->size);
if (power_of_two > 3)
power_of_two = 3;
s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
if (power_of_two > bfd_get_section_alignment (dynobj, s))
{
if (!bfd_set_section_alignment (dynobj, s, power_of_two))
return FALSE;
}
h->root.u.def.section = s;
h->root.u.def.value = s->size;
s->size += h->size;
return TRUE;
}
static bfd_boolean
cris_elf_check_relocs (abfd, info, sec, 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, **sym_hashes_end;
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)
return TRUE;
dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
local_got_refcounts = elf_local_got_refcounts (abfd);
sgot = NULL;
srelgot = NULL;
sreloc = NULL;
if (!elf_bad_symtab (abfd))
sym_hashes_end -= symtab_hdr->sh_info;
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
enum elf_cris_reloc_type r_type;
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];
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;
}
r_type = ELF32_R_TYPE (rel->r_info);
switch (r_type)
{
case R_CRIS_16_GOT:
case R_CRIS_32_GOT:
case R_CRIS_32_GOTREL:
case R_CRIS_32_PLT_GOTREL:
case R_CRIS_32_PLT_PCREL:
case R_CRIS_16_GOTPLT:
case R_CRIS_32_GOTPLT:
if (dynobj == NULL)
{
elf_hash_table (info)->dynobj = dynobj = abfd;
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;
}
if (!_bfd_elf_create_got_section (dynobj, info))
return FALSE;
}
break;
default:
break;
}
switch (r_type)
{
case R_CRIS_16_GOTPLT:
case R_CRIS_32_GOTPLT:
case R_CRIS_16_GOT:
case R_CRIS_32_GOT:
if (srelgot == NULL
&& (h != NULL || info->shared))
{
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
if (srelgot == NULL)
{
srelgot = bfd_make_section_with_flags (dynobj,
".rela.got",
(SEC_ALLOC
| SEC_LOAD
| SEC_HAS_CONTENTS
| SEC_IN_MEMORY
| SEC_LINKER_CREATED
| SEC_READONLY));
if (srelgot == NULL
|| !bfd_set_section_alignment (dynobj, srelgot, 2))
return FALSE;
}
}
case R_CRIS_32_GOTREL:
case R_CRIS_32_PLT_GOTREL:
if (sgot == NULL)
sgot = bfd_get_section_by_name (dynobj, ".got");
if (local_got_refcounts == NULL)
{
bfd_size_type amt;
amt = symtab_hdr->sh_info + 1;
amt *= sizeof (bfd_signed_vma);
local_got_refcounts = ((bfd_signed_vma *) bfd_zalloc (abfd, amt));
if (local_got_refcounts == NULL)
return FALSE;
local_got_refcounts++;
elf_local_got_refcounts (abfd) = local_got_refcounts;
}
break;
default:
break;
}
switch (r_type)
{
case R_CRIS_16_GOTPLT:
case R_CRIS_32_GOTPLT:
if (h != NULL)
{
((struct elf_cris_link_hash_entry *) h)->gotplt_refcount++;
goto handle_gotplt_reloc;
}
case R_CRIS_16_GOT:
case R_CRIS_32_GOT:
if (h != NULL)
{
if (h->got.refcount == 0)
{
if (h->dynindx == -1)
{
if (!bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
sgot->size += 4;
srelgot->size += sizeof (Elf32_External_Rela);
}
h->got.refcount++;
}
else
{
if (local_got_refcounts[r_symndx] == 0)
{
sgot->size += 4;
if (info->shared)
{
srelgot->size += sizeof (Elf32_External_Rela);
}
}
local_got_refcounts[r_symndx]++;
}
break;
case R_CRIS_32_GOTREL:
local_got_refcounts[-1]++;
break;
handle_gotplt_reloc:
case R_CRIS_32_PLT_GOTREL:
local_got_refcounts[-1]++;
case R_CRIS_32_PLT_PCREL:
if (h == NULL)
continue;
h->needs_plt = 1;
h->plt.refcount++;
break;
case R_CRIS_8:
case R_CRIS_16:
case R_CRIS_32:
if (info->shared
&& (sec->flags & SEC_ALLOC) != 0
&& (sec->flags & SEC_READONLY) != 0)
{
(*_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);
}
case R_CRIS_8_PCREL:
case R_CRIS_16_PCREL:
case R_CRIS_32_PCREL:
if (h != NULL)
{
h->non_got_ref = 1;
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
h->plt.refcount++;
}
if (! info->shared)
break;
if ((sec->flags & SEC_ALLOC) == 0)
break;
if (r_type == R_CRIS_8_PCREL
|| r_type == R_CRIS_16_PCREL
|| r_type == R_CRIS_32_PCREL)
{
if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
break;
if (info->symbolic
&& h->root.type != bfd_link_hash_defweak
&& h->def_regular)
break;
if ((sec->flags & SEC_READONLY) != 0)
{
(*_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);
}
}
if (sreloc == NULL)
{
const char *name;
name = (bfd_elf_string_from_elf_section
(abfd,
elf_elfheader (abfd)->e_shstrndx,
elf_section_data (sec)->rel_hdr.sh_name));
if (name == NULL)
return FALSE;
BFD_ASSERT (strncmp (name, ".rela", 5) == 0
&& strcmp (bfd_get_section_name (abfd, sec),
name + 5) == 0);
sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
{
sreloc = bfd_make_section_with_flags (dynobj, name,
(SEC_ALLOC
| SEC_LOAD
| SEC_HAS_CONTENTS
| SEC_IN_MEMORY
| SEC_LINKER_CREATED
| SEC_READONLY));
if (sreloc == NULL
|| !bfd_set_section_alignment (dynobj, sreloc, 2))
return FALSE;
}
if (sec->flags & SEC_READONLY)
info->flags |= DF_TEXTREL;
}
sreloc->size += sizeof (Elf32_External_Rela);
if ((r_type == R_CRIS_8_PCREL
|| r_type == R_CRIS_16_PCREL
|| r_type == R_CRIS_32_PCREL)
&& info->symbolic)
{
struct elf_cris_link_hash_entry *eh;
struct elf_cris_pcrel_relocs_copied *p;
eh = (struct elf_cris_link_hash_entry *) h;
for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
if (p->section == sreloc)
break;
if (p == NULL)
{
p = ((struct elf_cris_pcrel_relocs_copied *)
bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
if (p == NULL)
return FALSE;
p->next = eh->pcrel_relocs_copied;
eh->pcrel_relocs_copied = p;
p->section = sreloc;
p->count = 0;
}
++p->count;
}
break;
case R_CRIS_GNU_VTINHERIT:
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return FALSE;
break;
case R_CRIS_GNU_VTENTRY:
if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
default:
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
return TRUE;
}
static bfd_boolean
elf_cris_size_dynamic_sections (output_bfd, info)
bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
bfd *dynobj;
asection *s;
bfd_boolean plt;
bfd_boolean relocs;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
if (elf_hash_table (info)->dynamic_sections_created)
{
if (info->executable)
{
s = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (s != NULL);
s->size = sizeof ELF_DYNAMIC_INTERPRETER;
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
}
}
else
{
elf_cris_link_hash_traverse (elf_cris_hash_table (info),
elf_cris_adjust_gotplt_to_got,
(PTR) info);
s = bfd_get_section_by_name (dynobj, ".rela.got");
if (s != NULL)
s->size = 0;
}
if (info->shared)
elf_cris_link_hash_traverse (elf_cris_hash_table (info),
elf_cris_discard_excess_dso_dynamics,
(PTR) info);
else
elf_cris_link_hash_traverse (elf_cris_hash_table (info),
elf_cris_discard_excess_program_dynamics,
(PTR) info);
plt = FALSE;
relocs = FALSE;
for (s = dynobj->sections; s != NULL; s = s->next)
{
const char *name;
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
name = bfd_get_section_name (dynobj, s);
if (strcmp (name, ".plt") == 0)
{
plt = s->size != 0;
}
else if (strncmp (name, ".rela", 5) == 0)
{
if (s->size != 0)
{
if (strcmp (name, ".rela.plt") != 0)
relocs = TRUE;
s->reloc_count = 0;
}
}
else if (strncmp (name, ".got", 4) != 0
&& strcmp (name, ".dynbss") != 0)
{
continue;
}
if (s->size == 0)
{
s->flags |= SEC_EXCLUDE;
continue;
}
if ((s->flags & SEC_HAS_CONTENTS) == 0)
continue;
s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
if (s->contents == NULL)
return FALSE;
}
if (elf_hash_table (info)->dynamic_sections_created)
{
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
if (!info->shared)
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
}
if (plt)
{
if (!add_dynamic_entry (DT_PLTGOT, 0)
|| !add_dynamic_entry (DT_PLTRELSZ, 0)
|| !add_dynamic_entry (DT_PLTREL, DT_RELA)
|| !add_dynamic_entry (DT_JMPREL, 0))
return FALSE;
}
if (relocs)
{
if (!add_dynamic_entry (DT_RELA, 0)
|| !add_dynamic_entry (DT_RELASZ, 0)
|| !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
return FALSE;
}
if ((info->flags & DF_TEXTREL) != 0)
{
if (!add_dynamic_entry (DT_TEXTREL, 0))
return FALSE;
info->flags |= DF_TEXTREL;
}
}
#undef add_dynamic_entry
return TRUE;
}
static bfd_boolean
elf_cris_discard_excess_dso_dynamics (h, inf)
struct elf_cris_link_hash_entry *h;
PTR inf;
{
struct elf_cris_pcrel_relocs_copied *s;
struct bfd_link_info *info = (struct bfd_link_info *) inf;
if (h->root.root.type == bfd_link_hash_warning)
h = (struct elf_cris_link_hash_entry *) h->root.root.u.i.link;
if (h->root.def_regular
&& (h->root.forced_local
|| info->symbolic))
{
for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
s->section->size -= s->count * sizeof (Elf32_External_Rela);
}
return TRUE;
}
static bfd_boolean
elf_cris_discard_excess_program_dynamics (h, inf)
struct elf_cris_link_hash_entry *h;
PTR inf;
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
if (h->root.root.type == bfd_link_hash_warning)
h = (struct elf_cris_link_hash_entry *) h->root.root.u.i.link;
if (!h->root.def_dynamic
|| h->root.plt.refcount > 0)
{
if (h->root.got.refcount > 0
&& elf_hash_table (info)->dynamic_sections_created)
{
bfd *dynobj = elf_hash_table (info)->dynobj;
asection *srelgot;
BFD_ASSERT (dynobj != NULL);
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (srelgot != NULL);
srelgot->size -= sizeof (Elf32_External_Rela);
}
if (! info->export_dynamic
&& 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,
h->root.dynstr_index);
}
}
return TRUE;
}
static bfd_boolean
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);
}
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) == '_')
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;
}
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:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
return TRUE;
}
static bfd_boolean
cris_elf_print_private_bfd_data (abfd, ptr)
bfd *abfd;
PTR ptr;
{
FILE *file = (FILE *) ptr;
BFD_ASSERT (abfd != NULL && ptr != NULL);
_bfd_elf_print_private_bfd_data (abfd, ptr);
fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
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;
}
static bfd_boolean
cris_elf_merge_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
int imach, omach;
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
imach = bfd_get_mach (ibfd);
if (! elf_flags_init (obfd))
{
elf_flags_init (obfd) = TRUE;
if (! bfd_set_arch_mach (obfd, bfd_arch_cris, imach))
return FALSE;
}
if (bfd_get_symbol_leading_char (ibfd)
!= bfd_get_symbol_leading_char (obfd))
{
(*_bfd_error_handler)
(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);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
omach = bfd_get_mach (obfd);
if (imach != omach)
{
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;
}
if (omach == bfd_mach_cris_v10_v32
&& ! bfd_set_arch_mach (obfd, bfd_arch_cris, imach))
return FALSE;
}
return TRUE;
}
static bfd_boolean
cris_elf_copy_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
if (!_bfd_elf_copy_private_bfd_data (ibfd, obfd))
return FALSE;
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;
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)
const Elf_Internal_Rela *rela;
{
switch ((int) ELF32_R_TYPE (rela->r_info))
{
case R_CRIS_RELATIVE:
return reloc_class_relative;
case R_CRIS_JUMP_SLOT:
return reloc_class_plt;
case R_CRIS_COPY:
return reloc_class_copy;
default:
return reloc_class_normal;
}
}
#define ELF_ARCH bfd_arch_cris
#define ELF_MACHINE_CODE EM_CRIS
#define ELF_MAXPAGESIZE 0x2000
#define TARGET_LITTLE_SYM bfd_elf32_cris_vec
#define TARGET_LITTLE_NAME "elf32-cris"
#define elf_symbol_leading_char 0
#define elf_info_to_howto_rel NULL
#define elf_info_to_howto cris_info_to_howto_rela
#define elf_backend_relocate_section cris_elf_relocate_section
#define elf_backend_gc_mark_hook cris_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook cris_elf_gc_sweep_hook
#define elf_backend_check_relocs cris_elf_check_relocs
#define elf_backend_grok_prstatus cris_elf_grok_prstatus
#define elf_backend_grok_psinfo cris_elf_grok_psinfo
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
#define elf_backend_object_p cris_elf_object_p
#define elf_backend_final_write_processing \
cris_elf_final_write_processing
#define bfd_elf32_bfd_print_private_bfd_data \
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
#define bfd_elf32_bfd_link_hash_table_create \
elf_cris_link_hash_table_create
#define elf_backend_adjust_dynamic_symbol \
elf_cris_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \
elf_cris_size_dynamic_sections
#define elf_backend_finish_dynamic_symbol \
elf_cris_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
elf_cris_finish_dynamic_sections
#define elf_backend_create_dynamic_sections \
_bfd_elf_create_dynamic_sections
#define bfd_elf32_bfd_final_link \
bfd_elf_gc_common_final_link
#define elf_backend_hide_symbol elf_cris_hide_symbol
#define elf_backend_reloc_type_class elf_cris_reloc_type_class
#define elf_backend_want_got_plt 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
#define elf_backend_got_header_size 12
#define elf_backend_may_use_rel_p 0
#define elf_backend_may_use_rela_p 1
#define elf_backend_rela_normal 1
#include "elf32-target.h"
#define INCLUDED_TARGET_FILE
#undef TARGET_LITTLE_SYM
#undef TARGET_LITTLE_NAME
#undef elf_symbol_leading_char
#define TARGET_LITTLE_SYM bfd_elf32_us_cris_vec
#define TARGET_LITTLE_NAME "elf32-us-cris"
#define elf_symbol_leading_char '_'
#include "elf32-target.h"