#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/mn10300.h"
static bfd_reloc_status_type mn10300_elf_final_link_relocate
PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *,
bfd_vma, bfd_vma, bfd_vma,
struct elf_link_hash_entry *, unsigned long, struct bfd_link_info *,
asection *, int));
static bfd_boolean mn10300_elf_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static bfd_boolean mn10300_elf_relax_section
PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
static bfd_byte * mn10300_elf_get_relocated_section_contents
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *,
bfd_byte *, bfd_boolean, asymbol **));
static unsigned long elf_mn10300_mach
PARAMS ((flagword));
void _bfd_mn10300_elf_final_write_processing
PARAMS ((bfd *, bfd_boolean));
bfd_boolean _bfd_mn10300_elf_object_p
PARAMS ((bfd *));
bfd_boolean _bfd_mn10300_elf_merge_private_bfd_data
PARAMS ((bfd *,bfd *));
struct elf32_mn10300_link_hash_entry {
struct elf_link_hash_entry root;
unsigned int direct_calls;
unsigned char stack_size;
unsigned char movm_args;
unsigned char movm_stack_size;
#define MN10300_CONVERT_CALL_TO_CALLS 0x1
#define MN10300_DELETED_PROLOGUE_BYTES 0x2
unsigned char flags;
};
struct elf32_mn10300_link_hash_table {
struct elf_link_hash_table root;
struct elf32_mn10300_link_hash_table *static_hash_table;
#define MN10300_HASH_ENTRIES_INITIALIZED 0x1
char flags;
};
#define elf32_mn10300_hash_table(p) \
((struct elf32_mn10300_link_hash_table *) ((p)->hash))
#define elf32_mn10300_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
(bfd_boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \
(info)))
static struct bfd_hash_entry *elf32_mn10300_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct bfd_link_hash_table *elf32_mn10300_link_hash_table_create
PARAMS ((bfd *));
static void elf32_mn10300_link_hash_table_free
PARAMS ((struct bfd_link_hash_table *));
static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
static void mn10300_info_to_howto
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
static bfd_boolean mn10300_elf_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static asection *mn10300_elf_gc_mark_hook
PARAMS ((asection *, struct bfd_link_info *info, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
static bfd_boolean mn10300_elf_relax_delete_bytes
PARAMS ((bfd *, asection *, bfd_vma, int));
static bfd_boolean mn10300_elf_symbol_address_p
PARAMS ((bfd *, asection *, Elf_Internal_Sym *, bfd_vma));
static bfd_boolean elf32_mn10300_finish_hash_table_entry
PARAMS ((struct bfd_hash_entry *, PTR));
static void compute_function_info
PARAMS ((bfd *, struct elf32_mn10300_link_hash_entry *,
bfd_vma, unsigned char *));
static bfd_boolean _bfd_mn10300_elf_create_got_section
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean _bfd_mn10300_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean _bfd_mn10300_elf_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static bfd_boolean _bfd_mn10300_elf_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean _bfd_mn10300_elf_finish_dynamic_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
Elf_Internal_Sym *));
static bfd_boolean _bfd_mn10300_elf_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static reloc_howto_type elf_mn10300_howto_table[] = {
HOWTO (R_MN10300_NONE,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_NONE",
FALSE,
0,
0,
FALSE),
HOWTO (R_MN10300_32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_32",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_16,
0,
1,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_16",
FALSE,
0xffff,
0xffff,
FALSE),
HOWTO (R_MN10300_8,
0,
0,
8,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_8",
FALSE,
0xff,
0xff,
FALSE),
HOWTO (R_MN10300_PCREL32,
0,
2,
32,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_PCREL32",
FALSE,
0xffffffff,
0xffffffff,
TRUE),
HOWTO (R_MN10300_PCREL16,
0,
1,
16,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_PCREL16",
FALSE,
0xffff,
0xffff,
TRUE),
HOWTO (R_MN10300_PCREL8,
0,
0,
8,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_PCREL8",
FALSE,
0xff,
0xff,
TRUE),
HOWTO (R_MN10300_GNU_VTINHERIT,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
NULL,
"R_MN10300_GNU_VTINHERIT",
FALSE,
0,
0,
FALSE),
HOWTO (R_MN10300_GNU_VTENTRY,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
NULL,
"R_MN10300_GNU_VTENTRY",
FALSE,
0,
0,
FALSE),
HOWTO (R_MN10300_24,
0,
2,
24,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_24",
FALSE,
0xffffff,
0xffffff,
FALSE),
HOWTO (R_MN10300_GOTPC32,
0,
2,
32,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOTPC32",
FALSE,
0xffffffff,
0xffffffff,
TRUE),
HOWTO (R_MN10300_GOTPC16,
0,
1,
16,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOTPC16",
FALSE,
0xffff,
0xffff,
TRUE),
HOWTO (R_MN10300_GOTOFF32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOTOFF32",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_GOTOFF24,
0,
2,
24,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOTOFF24",
FALSE,
0xffffff,
0xffffff,
FALSE),
HOWTO (R_MN10300_GOTOFF16,
0,
1,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOTOFF16",
FALSE,
0xffff,
0xffff,
FALSE),
HOWTO (R_MN10300_PLT32,
0,
2,
32,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_PLT32",
FALSE,
0xffffffff,
0xffffffff,
TRUE),
HOWTO (R_MN10300_PLT16,
0,
1,
16,
TRUE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_PLT16",
FALSE,
0xffff,
0xffff,
TRUE),
HOWTO (R_MN10300_GOT32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOT32",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_GOT24,
0,
2,
24,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOT24",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_GOT16,
0,
1,
16,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GOT16",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_COPY,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_COPY",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_GLOB_DAT,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_GLOB_DAT",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_JMP_SLOT,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_JMP_SLOT",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MN10300_RELATIVE,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
bfd_elf_generic_reloc,
"R_MN10300_RELATIVE",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
};
struct mn10300_reloc_map {
bfd_reloc_code_real_type bfd_reloc_val;
unsigned char elf_reloc_val;
};
static const struct mn10300_reloc_map mn10300_reloc_map[] = {
{ BFD_RELOC_NONE, R_MN10300_NONE, },
{ BFD_RELOC_32, R_MN10300_32, },
{ BFD_RELOC_16, R_MN10300_16, },
{ BFD_RELOC_8, R_MN10300_8, },
{ BFD_RELOC_32_PCREL, R_MN10300_PCREL32, },
{ BFD_RELOC_16_PCREL, R_MN10300_PCREL16, },
{ BFD_RELOC_8_PCREL, R_MN10300_PCREL8, },
{ BFD_RELOC_24, R_MN10300_24, },
{ BFD_RELOC_VTABLE_INHERIT, R_MN10300_GNU_VTINHERIT },
{ BFD_RELOC_VTABLE_ENTRY, R_MN10300_GNU_VTENTRY },
{ BFD_RELOC_32_GOT_PCREL, R_MN10300_GOTPC32 },
{ BFD_RELOC_16_GOT_PCREL, R_MN10300_GOTPC16 },
{ BFD_RELOC_32_GOTOFF, R_MN10300_GOTOFF32 },
{ BFD_RELOC_MN10300_GOTOFF24, R_MN10300_GOTOFF24 },
{ BFD_RELOC_16_GOTOFF, R_MN10300_GOTOFF16 },
{ BFD_RELOC_32_PLT_PCREL, R_MN10300_PLT32 },
{ BFD_RELOC_16_PLT_PCREL, R_MN10300_PLT16 },
{ BFD_RELOC_MN10300_GOT32, R_MN10300_GOT32 },
{ BFD_RELOC_MN10300_GOT24, R_MN10300_GOT24 },
{ BFD_RELOC_MN10300_GOT16, R_MN10300_GOT16 },
{ BFD_RELOC_MN10300_COPY, R_MN10300_COPY },
{ BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT },
{ BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT },
{ BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE },
};
static bfd_boolean
_bfd_mn10300_elf_create_got_section (abfd, info)
bfd * abfd;
struct bfd_link_info * info;
{
flagword flags;
flagword pltflags;
asection * s;
struct bfd_link_hash_entry * bh;
struct elf_link_hash_entry * h;
const struct elf_backend_data * bed = get_elf_backend_data (abfd);
int ptralign;
if (bfd_get_section_by_name (abfd, ".got") != NULL)
return TRUE;
switch (bed->s->arch_size)
{
case 32:
ptralign = 2;
break;
case 64:
ptralign = 3;
break;
default:
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
pltflags = flags;
pltflags |= SEC_CODE;
if (bed->plt_not_loaded)
pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS);
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
return FALSE;
if (bed->want_plt_sym)
{
bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s,
(bfd_vma) 0, (const char *) NULL, FALSE,
get_elf_backend_data (abfd)->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
h->def_regular = 1;
h->type = STT_OBJECT;
if (info->shared
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
s = bfd_make_section_with_flags (abfd, ".got", flags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
if (bed->want_got_plt)
{
s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
}
bh = NULL;
if (!(_bfd_generic_link_add_one_symbol
(info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
0, (const char *) NULL, FALSE, bed->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
h->def_regular = 1;
h->type = STT_OBJECT;
if (info->shared
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
elf_hash_table (info)->hgot = h;
s->size += bed->got_header_size;
return TRUE;
}
static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup (abfd, code)
bfd *abfd ATTRIBUTE_UNUSED;
bfd_reloc_code_real_type code;
{
unsigned int i;
for (i = 0;
i < sizeof (mn10300_reloc_map) / sizeof (struct mn10300_reloc_map);
i++)
{
if (mn10300_reloc_map[i].bfd_reloc_val == code)
return &elf_mn10300_howto_table[mn10300_reloc_map[i].elf_reloc_val];
}
return NULL;
}
static void
mn10300_info_to_howto (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_MN10300_MAX);
cache_ptr->howto = &elf_mn10300_howto_table[r_type];
}
static bfd_boolean
mn10300_elf_check_relocs (abfd, info, sec, relocs)
bfd *abfd;
struct bfd_link_info *info;
asection *sec;
const Elf_Internal_Rela *relocs;
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
bfd * dynobj;
bfd_vma * local_got_offsets;
asection * sgot;
asection * srelgot;
asection * sreloc;
sgot = NULL;
srelgot = NULL;
sreloc = NULL;
if (info->relocatable)
return TRUE;
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);
if (!elf_bad_symtab (abfd))
sym_hashes_end -= symtab_hdr->sh_info;
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
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;
}
if (dynobj == NULL)
{
switch (ELF32_R_TYPE (rel->r_info))
{
case R_MN10300_GOT32:
case R_MN10300_GOT24:
case R_MN10300_GOT16:
case R_MN10300_GOTOFF32:
case R_MN10300_GOTOFF24:
case R_MN10300_GOTOFF16:
case R_MN10300_GOTPC32:
case R_MN10300_GOTPC16:
elf_hash_table (info)->dynobj = dynobj = abfd;
if (! _bfd_mn10300_elf_create_got_section (dynobj, info))
return FALSE;
break;
default:
break;
}
}
switch (ELF32_R_TYPE (rel->r_info))
{
case R_MN10300_GNU_VTINHERIT:
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return FALSE;
break;
case R_MN10300_GNU_VTENTRY:
if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
case R_MN10300_GOT32:
case R_MN10300_GOT24:
case R_MN10300_GOT16:
if (sgot == NULL)
{
sgot = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (sgot != NULL);
}
if (srelgot == NULL
&& (h != NULL || info->shared))
{
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
if (srelgot == NULL)
{
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;
}
}
if (h != NULL)
{
if (h->got.offset != (bfd_vma) -1)
break;
h->got.offset = sgot->size;
if (h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
srelgot->size += sizeof (Elf32_External_Rela);
}
else
{
if (local_got_offsets == NULL)
{
size_t size;
unsigned int i;
size = symtab_hdr->sh_info * sizeof (bfd_vma);
local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
if (local_got_offsets == NULL)
return FALSE;
elf_local_got_offsets (abfd) = local_got_offsets;
for (i = 0; i < symtab_hdr->sh_info; i++)
local_got_offsets[i] = (bfd_vma) -1;
}
if (local_got_offsets[r_symndx] != (bfd_vma) -1)
break;
local_got_offsets[r_symndx] = sgot->size;
if (info->shared)
srelgot->size += sizeof (Elf32_External_Rela);
}
sgot->size += 4;
break;
case R_MN10300_PLT32:
case R_MN10300_PLT16:
if (h == NULL)
continue;
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
break;
h->needs_plt = 1;
break;
case R_MN10300_24:
case R_MN10300_16:
case R_MN10300_8:
case R_MN10300_PCREL32:
case R_MN10300_PCREL16:
case R_MN10300_PCREL8:
if (h != NULL)
h->non_got_ref = 1;
break;
case R_MN10300_32:
if (h != NULL)
h->non_got_ref = 1;
if (info->shared
&& (sec->flags & SEC_ALLOC) != 0)
{
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)
{
flagword flags;
flags = (SEC_HAS_CONTENTS | SEC_READONLY
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
if ((sec->flags & SEC_ALLOC) != 0)
flags |= SEC_ALLOC | SEC_LOAD;
sreloc = bfd_make_section_with_flags (dynobj,
name,
flags);
if (sreloc == NULL
|| ! bfd_set_section_alignment (dynobj, sreloc, 2))
return FALSE;
}
}
sreloc->size += sizeof (Elf32_External_Rela);
}
break;
}
}
return TRUE;
}
static asection *
mn10300_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_MN10300_GNU_VTINHERIT:
case R_MN10300_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_reloc_status_type
mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
input_section, contents, offset, value,
addend, h, symndx, info, sym_sec, is_local)
reloc_howto_type *howto;
bfd *input_bfd;
bfd *output_bfd ATTRIBUTE_UNUSED;
asection *input_section;
bfd_byte *contents;
bfd_vma offset;
bfd_vma value;
bfd_vma addend;
struct elf_link_hash_entry * h;
unsigned long symndx;
struct bfd_link_info *info;
asection *sym_sec ATTRIBUTE_UNUSED;
int is_local ATTRIBUTE_UNUSED;
{
unsigned long r_type = howto->type;
bfd_byte *hit_data = contents + offset;
bfd * dynobj;
bfd_vma * local_got_offsets;
asection * sgot;
asection * splt;
asection * sreloc;
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (input_bfd);
sgot = NULL;
splt = NULL;
sreloc = NULL;
switch (r_type)
{
case R_MN10300_24:
case R_MN10300_16:
case R_MN10300_8:
case R_MN10300_PCREL8:
case R_MN10300_PCREL16:
case R_MN10300_PCREL32:
case R_MN10300_GOTOFF32:
case R_MN10300_GOTOFF24:
case R_MN10300_GOTOFF16:
if (info->shared
&& (input_section->flags & SEC_ALLOC) != 0
&& h != NULL
&& ! SYMBOL_REFERENCES_LOCAL (info, h))
return bfd_reloc_dangerous;
}
switch (r_type)
{
case R_MN10300_NONE:
return bfd_reloc_ok;
case R_MN10300_32:
if (info->shared
&& (input_section->flags & SEC_ALLOC) != 0)
{
Elf_Internal_Rela outrel;
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);
BFD_ASSERT (sreloc != NULL);
}
skip = FALSE;
outrel.r_offset = _bfd_elf_section_offset (input_bfd, info,
input_section, offset);
if (outrel.r_offset == (bfd_vma) -1)
skip = TRUE;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
if (skip)
{
memset (&outrel, 0, sizeof outrel);
relocate = FALSE;
}
else
{
if (h == NULL
|| SYMBOL_REFERENCES_LOCAL (info, h))
{
relocate = TRUE;
outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
outrel.r_addend = value + addend;
}
else
{
BFD_ASSERT (h->dynindx != -1);
relocate = FALSE;
outrel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_32);
outrel.r_addend = value + addend;
}
}
bfd_elf32_swap_reloca_out (output_bfd, &outrel,
(bfd_byte *) (((Elf32_External_Rela *) sreloc->contents)
+ sreloc->reloc_count));
++sreloc->reloc_count;
if (! relocate)
return bfd_reloc_ok;
}
value += addend;
bfd_put_32 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_24:
value += addend;
if ((long) value > 0x7fffff || (long) value < -0x800000)
return bfd_reloc_overflow;
bfd_put_8 (input_bfd, value & 0xff, hit_data);
bfd_put_8 (input_bfd, (value >> 8) & 0xff, hit_data + 1);
bfd_put_8 (input_bfd, (value >> 16) & 0xff, hit_data + 2);
return bfd_reloc_ok;
case R_MN10300_16:
value += addend;
if ((long) value > 0x7fff || (long) value < -0x8000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_8:
value += addend;
if ((long) value > 0x7f || (long) value < -0x80)
return bfd_reloc_overflow;
bfd_put_8 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_PCREL8:
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
if ((long) value > 0xff || (long) value < -0x100)
return bfd_reloc_overflow;
bfd_put_8 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_PCREL16:
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
if ((long) value > 0xffff || (long) value < -0x10000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_PCREL32:
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
bfd_put_32 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_GNU_VTINHERIT:
case R_MN10300_GNU_VTENTRY:
return bfd_reloc_ok;
case R_MN10300_GOTPC32:
value = bfd_get_section_by_name (dynobj,
".got")->output_section->vma;
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
bfd_put_32 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_GOTPC16:
value = bfd_get_section_by_name (dynobj,
".got")->output_section->vma;
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
if ((long) value > 0xffff || (long) value < -0x10000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_GOTOFF32:
value -= bfd_get_section_by_name (dynobj,
".got")->output_section->vma;
value += addend;
bfd_put_32 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_GOTOFF24:
value -= bfd_get_section_by_name (dynobj,
".got")->output_section->vma;
value += addend;
if ((long) value > 0x7fffff || (long) value < -0x800000)
return bfd_reloc_overflow;
bfd_put_8 (input_bfd, value, hit_data);
bfd_put_8 (input_bfd, (value >> 8) & 0xff, hit_data + 1);
bfd_put_8 (input_bfd, (value >> 16) & 0xff, hit_data + 2);
return bfd_reloc_ok;
case R_MN10300_GOTOFF16:
value -= bfd_get_section_by_name (dynobj,
".got")->output_section->vma;
value += addend;
if ((long) value > 0xffff || (long) value < -0x10000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_PLT32:
if (h != NULL
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
&& h->plt.offset != (bfd_vma) -1)
{
asection * splt;
splt = bfd_get_section_by_name (dynobj, ".plt");
value = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset) - value;
}
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
bfd_put_32 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_PLT16:
if (h != NULL
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
&& h->plt.offset != (bfd_vma) -1)
{
asection * splt;
splt = bfd_get_section_by_name (dynobj, ".plt");
value = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset) - value;
}
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
value += addend;
if ((long) value > 0xffff || (long) value < -0x10000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
return bfd_reloc_ok;
case R_MN10300_GOT32:
case R_MN10300_GOT24:
case R_MN10300_GOT16:
{
asection * sgot;
sgot = bfd_get_section_by_name (dynobj, ".got");
if (h != NULL)
{
bfd_vma off;
off = h->got.offset;
BFD_ASSERT (off != (bfd_vma) -1);
if (! elf_hash_table (info)->dynamic_sections_created
|| SYMBOL_REFERENCES_LOCAL (info, h))
bfd_put_32 (output_bfd, value,
sgot->contents + off);
value = sgot->output_offset + off;
}
else
{
bfd_vma off;
off = elf_local_got_offsets (input_bfd)[symndx];
bfd_put_32 (output_bfd, value, sgot->contents + off);
if (info->shared)
{
asection * srelgot;
Elf_Internal_Rela outrel;
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (srelgot != NULL);
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ off);
outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
outrel.r_addend = value;
bfd_elf32_swap_reloca_out (output_bfd, &outrel,
(bfd_byte *) (((Elf32_External_Rela *)
srelgot->contents)
+ srelgot->reloc_count));
++ srelgot->reloc_count;
}
value = sgot->output_offset + off;
}
}
value += addend;
if (r_type == R_MN10300_GOT32)
{
bfd_put_32 (input_bfd, value, hit_data);
return bfd_reloc_ok;
}
else if (r_type == R_MN10300_GOT24)
{
if ((long) value > 0x7fffff || (long) value < -0x800000)
return bfd_reloc_overflow;
bfd_put_8 (input_bfd, value & 0xff, hit_data);
bfd_put_8 (input_bfd, (value >> 8) & 0xff, hit_data + 1);
bfd_put_8 (input_bfd, (value >> 16) & 0xff, hit_data + 2);
return bfd_reloc_ok;
}
else if (r_type == R_MN10300_GOT16)
{
if ((long) value > 0xffff || (long) value < -0x10000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
return bfd_reloc_ok;
}
default:
return bfd_reloc_notsupported;
}
}
static bfd_boolean
mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
contents, relocs, local_syms, local_sections)
bfd *output_bfd;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
Elf_Internal_Rela *relocs;
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel, *relend;
if (info->relocatable)
return TRUE;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
int r_type;
reloc_howto_type *howto;
unsigned long r_symndx;
Elf_Internal_Sym *sym;
asection *sec;
struct elf32_mn10300_link_hash_entry *h;
bfd_vma relocation;
bfd_reloc_status_type r;
r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info);
howto = elf_mn10300_howto_table + r_type;
if (r_type == R_MN10300_GNU_VTINHERIT
|| r_type == R_MN10300_GNU_VTENTRY)
continue;
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);
}
else
{
bfd_boolean unresolved_reloc;
bfd_boolean warned;
struct elf_link_hash_entry *hh;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
hh, sec, relocation,
unresolved_reloc, warned);
h = (struct elf32_mn10300_link_hash_entry *) hh;
if ((h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
&& ( r_type == R_MN10300_GOTPC32
|| r_type == R_MN10300_GOTPC16
|| (( r_type == R_MN10300_PLT32
|| r_type == R_MN10300_PLT16)
&& ELF_ST_VISIBILITY (h->root.other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (h->root.other) != STV_HIDDEN
&& h->root.plt.offset != (bfd_vma) -1)
|| (( r_type == R_MN10300_GOT32
|| r_type == R_MN10300_GOT24
|| r_type == R_MN10300_GOT16)
&& elf_hash_table (info)->dynamic_sections_created
&& !SYMBOL_REFERENCES_LOCAL (info, hh))
|| (r_type == R_MN10300_32
&& !SYMBOL_REFERENCES_LOCAL (info, hh)
&& ((input_section->flags & SEC_ALLOC) != 0
|| ((input_section->flags & SEC_DEBUGGING) != 0
&& h->root.def_dynamic)))))
relocation = 0;
else if (unresolved_reloc)
(*_bfd_error_handler)
(_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
bfd_get_filename (input_bfd), h->root.root.root.string,
bfd_get_section_name (input_bfd, input_section));
}
r = mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
input_section,
contents, rel->r_offset,
relocation, rel->r_addend,
(struct elf_link_hash_entry *)h,
r_symndx,
info, sec, h == NULL);
if (r != bfd_reloc_ok)
{
const char *name;
const char *msg = (const char *) 0;
if (h != NULL)
name = h->root.root.root.string;
else
{
name = (bfd_elf_string_from_elf_section
(input_bfd, symtab_hdr->sh_link, sym->st_name));
if (name == NULL || *name == '\0')
name = bfd_section_name (input_bfd, sec);
}
switch (r)
{
case bfd_reloc_overflow:
if (! ((*info->callbacks->reloc_overflow)
(info, (h ? &h->root.root : NULL), name,
howto->name, (bfd_vma) 0, input_bfd,
input_section, rel->r_offset)))
return FALSE;
break;
case bfd_reloc_undefined:
if (! ((*info->callbacks->undefined_symbol)
(info, name, input_bfd, input_section,
rel->r_offset, TRUE)))
return FALSE;
break;
case bfd_reloc_outofrange:
msg = _("internal error: out of range error");
goto common_error;
case bfd_reloc_notsupported:
msg = _("internal error: unsupported relocation error");
goto common_error;
case bfd_reloc_dangerous:
msg = _("internal error: dangerous error");
goto common_error;
default:
msg = _("internal error: unknown error");
common_error:
if (!((*info->callbacks->warning)
(info, msg, name, input_bfd, input_section,
rel->r_offset)))
return FALSE;
break;
}
}
}
return TRUE;
}
static bfd_boolean
elf32_mn10300_finish_hash_table_entry (gen_entry, in_args)
struct bfd_hash_entry *gen_entry;
PTR in_args;
{
struct elf32_mn10300_link_hash_entry *entry;
struct bfd_link_info *link_info = (struct bfd_link_info *)in_args;
unsigned int byte_count = 0;
entry = (struct elf32_mn10300_link_hash_entry *) gen_entry;
if (entry->root.root.type == bfd_link_hash_warning)
entry = (struct elf32_mn10300_link_hash_entry *) entry->root.root.u.i.link;
if (entry->flags == MN10300_CONVERT_CALL_TO_CALLS)
return TRUE;
if (entry->direct_calls == 0
|| (entry->stack_size == 0 && entry->movm_args == 0)
|| (elf_hash_table (link_info)->dynamic_sections_created
&& ELF_ST_VISIBILITY (entry->root.other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (entry->root.other) != STV_HIDDEN))
{
entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
return TRUE;
}
if (entry->movm_args)
byte_count += 2;
if (entry->stack_size > 0)
{
if (entry->stack_size <= 128)
byte_count += 3;
else
byte_count += 4;
}
if (byte_count < entry->direct_calls)
entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
return TRUE;
}
static bfd_boolean
mn10300_elf_relax_section (abfd, sec, link_info, again)
bfd *abfd;
asection *sec;
struct bfd_link_info *link_info;
bfd_boolean *again;
{
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *internal_relocs = NULL;
Elf_Internal_Rela *irel, *irelend;
bfd_byte *contents = NULL;
Elf_Internal_Sym *isymbuf = NULL;
struct elf32_mn10300_link_hash_table *hash_table;
asection *section = sec;
*again = FALSE;
hash_table = elf32_mn10300_hash_table (link_info);
if ((hash_table->flags & MN10300_HASH_ENTRIES_INITIALIZED) == 0)
{
bfd *input_bfd;
for (input_bfd = link_info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
{
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (symtab_hdr->sh_info != 0)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
goto error_return;
}
for (section = input_bfd->sections;
section != NULL;
section = section->next)
{
struct elf32_mn10300_link_hash_entry *hash;
Elf_Internal_Sym *sym;
asection *sym_sec = NULL;
const char *sym_name;
char *new_name;
if (! (((section->flags & SEC_RELOC) != 0
&& section->reloc_count != 0)
|| (section->flags & SEC_CODE) != 0))
continue;
if (elf_section_data (section)->this_hdr.contents != NULL)
contents = elf_section_data (section)->this_hdr.contents;
else if (section->size != 0)
{
if (!bfd_malloc_and_get_section (input_bfd, section,
&contents))
goto error_return;
}
else
contents = NULL;
if ((section->flags & SEC_RELOC) != 0
&& section->reloc_count != 0)
{
internal_relocs = (_bfd_elf_link_read_relocs
(input_bfd, section, (PTR) NULL,
(Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
irel = internal_relocs;
irelend = irel + section->reloc_count;
for (; irel < irelend; irel++)
{
long r_type;
unsigned long r_index;
unsigned char code;
r_type = ELF32_R_TYPE (irel->r_info);
r_index = ELF32_R_SYM (irel->r_info);
if (r_type < 0 || r_type >= (int) R_MN10300_MAX)
goto error_return;
hash = NULL;
sym = NULL;
sym_sec = NULL;
if (r_index < symtab_hdr->sh_info)
{
Elf_Internal_Sym *isym;
struct elf_link_hash_table *elftab;
bfd_size_type amt;
isym = isymbuf + r_index;
if (isym->st_shndx == SHN_UNDEF)
sym_sec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS)
sym_sec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
sym_sec = bfd_com_section_ptr;
else
sym_sec
= bfd_section_from_elf_index (input_bfd,
isym->st_shndx);
sym_name
= bfd_elf_string_from_elf_section (input_bfd,
(symtab_hdr
->sh_link),
isym->st_name);
if (ELF_ST_TYPE (isym->st_info) != STT_FUNC)
continue;
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
if (new_name == 0)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
elftab = &hash_table->static_hash_table->root;
hash = ((struct elf32_mn10300_link_hash_entry *)
elf_link_hash_lookup (elftab, sym_name,
TRUE, TRUE, FALSE));
free (new_name);
}
else
{
r_index -= symtab_hdr->sh_info;
hash = (struct elf32_mn10300_link_hash_entry *)
elf_sym_hashes (input_bfd)[r_index];
}
code = bfd_get_8 (input_bfd,
contents + irel->r_offset - 1);
if (code != 0xdd && code != 0xcd)
hash->flags |= MN10300_CONVERT_CALL_TO_CALLS;
if (r_type == R_MN10300_PCREL32
|| r_type == R_MN10300_PLT32
|| r_type == R_MN10300_PLT16
|| r_type == R_MN10300_PCREL16)
hash->direct_calls++;
else
hash->flags |= MN10300_CONVERT_CALL_TO_CALLS;
}
}
if ((section->flags & SEC_CODE) != 0)
{
Elf_Internal_Sym *isym, *isymend;
unsigned int sec_shndx;
struct elf_link_hash_entry **hashes;
struct elf_link_hash_entry **end_hashes;
unsigned int symcount;
sec_shndx = _bfd_elf_section_from_bfd_section (input_bfd,
section);
symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
- symtab_hdr->sh_info);
hashes = elf_sym_hashes (input_bfd);
end_hashes = hashes + symcount;
isymend = isymbuf + symtab_hdr->sh_info;
for (isym = isymbuf; isym < isymend; isym++)
{
if (isym->st_shndx == sec_shndx
&& ELF_ST_TYPE (isym->st_info) == STT_FUNC)
{
struct elf_link_hash_table *elftab;
bfd_size_type amt;
struct elf_link_hash_entry **lhashes = hashes;
for (; lhashes < end_hashes; lhashes++)
{
hash = (struct elf32_mn10300_link_hash_entry *) *lhashes;
if ((hash->root.root.type == bfd_link_hash_defined
|| hash->root.root.type == bfd_link_hash_defweak)
&& hash->root.root.u.def.section == section
&& hash->root.type == STT_FUNC
&& hash->root.root.u.def.value == isym->st_value)
break;
}
if (lhashes != end_hashes)
continue;
if (isym->st_shndx == SHN_UNDEF)
sym_sec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS)
sym_sec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
sym_sec = bfd_com_section_ptr;
else
sym_sec
= bfd_section_from_elf_index (input_bfd,
isym->st_shndx);
sym_name = (bfd_elf_string_from_elf_section
(input_bfd, symtab_hdr->sh_link,
isym->st_name));
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
if (new_name == 0)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
elftab = &hash_table->static_hash_table->root;
hash = ((struct elf32_mn10300_link_hash_entry *)
elf_link_hash_lookup (elftab, sym_name,
TRUE, TRUE, FALSE));
free (new_name);
compute_function_info (input_bfd, hash,
isym->st_value, contents);
}
}
for (; hashes < end_hashes; hashes++)
{
hash = (struct elf32_mn10300_link_hash_entry *) *hashes;
if ((hash->root.root.type == bfd_link_hash_defined
|| hash->root.root.type == bfd_link_hash_defweak)
&& hash->root.root.u.def.section == section
&& hash->root.type == STT_FUNC)
compute_function_info (input_bfd, hash,
(hash)->root.root.u.def.value,
contents);
}
}
if (internal_relocs != NULL
&& elf_section_data (section)->relocs != internal_relocs)
free (internal_relocs);
internal_relocs = NULL;
if (contents != NULL
&& elf_section_data (section)->this_hdr.contents != contents)
{
if (! link_info->keep_memory)
free (contents);
else
{
elf_section_data (section)->this_hdr.contents = contents;
}
}
contents = NULL;
}
if (isymbuf != NULL
&& symtab_hdr->contents != (unsigned char *) isymbuf)
{
if (! link_info->keep_memory)
free (isymbuf);
else
{
symtab_hdr->contents = (unsigned char *) isymbuf;
}
}
isymbuf = NULL;
}
elf32_mn10300_link_hash_traverse (hash_table,
elf32_mn10300_finish_hash_table_entry,
link_info);
elf32_mn10300_link_hash_traverse (hash_table->static_hash_table,
elf32_mn10300_finish_hash_table_entry,
link_info);
hash_table->flags |= MN10300_HASH_ENTRIES_INITIALIZED;
for (input_bfd = link_info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
{
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (symtab_hdr->sh_info != 0)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
goto error_return;
}
for (section = input_bfd->sections;
section != NULL;
section = section->next)
{
unsigned int sec_shndx;
Elf_Internal_Sym *isym, *isymend;
struct elf_link_hash_entry **hashes;
struct elf_link_hash_entry **end_hashes;
unsigned int symcount;
if ((section->flags & SEC_CODE) == 0 || section->size == 0)
continue;
if (section->reloc_count != 0)
{
internal_relocs = (_bfd_elf_link_read_relocs
(input_bfd, section, (PTR) NULL,
(Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
}
if (elf_section_data (section)->this_hdr.contents != NULL)
contents = elf_section_data (section)->this_hdr.contents;
else
{
if (!bfd_malloc_and_get_section (input_bfd, section,
&contents))
goto error_return;
}
sec_shndx = _bfd_elf_section_from_bfd_section (input_bfd,
section);
isymend = isymbuf + symtab_hdr->sh_info;
for (isym = isymbuf; isym < isymend; isym++)
{
struct elf32_mn10300_link_hash_entry *sym_hash;
asection *sym_sec = NULL;
const char *sym_name;
char *new_name;
struct elf_link_hash_table *elftab;
bfd_size_type amt;
if (isym->st_shndx != sec_shndx)
continue;
if (isym->st_shndx == SHN_UNDEF)
sym_sec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS)
sym_sec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
sym_sec = bfd_com_section_ptr;
else
sym_sec
= bfd_section_from_elf_index (input_bfd, isym->st_shndx);
sym_name
= bfd_elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
isym->st_name);
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
if (new_name == 0)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
elftab = &hash_table->static_hash_table->root;
sym_hash = ((struct elf32_mn10300_link_hash_entry *)
elf_link_hash_lookup (elftab, sym_name,
FALSE, FALSE, FALSE));
free (new_name);
if (sym_hash == NULL)
continue;
if (! (sym_hash->flags & MN10300_CONVERT_CALL_TO_CALLS)
&& ! (sym_hash->flags & MN10300_DELETED_PROLOGUE_BYTES))
{
int bytes = 0;
elf_section_data (section)->relocs = internal_relocs;
elf_section_data (section)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
if (sym_hash->movm_args)
bytes += 2;
if (sym_hash->stack_size > 0)
{
if (sym_hash->stack_size <= 128)
bytes += 3;
else
bytes += 4;
}
sym_hash->flags |= MN10300_DELETED_PROLOGUE_BYTES;
if (!mn10300_elf_relax_delete_bytes (input_bfd,
section,
isym->st_value,
bytes))
goto error_return;
*again = TRUE;
}
}
symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
- symtab_hdr->sh_info);
hashes = elf_sym_hashes (input_bfd);
end_hashes = hashes + symcount;
for (; hashes < end_hashes; hashes++)
{
struct elf32_mn10300_link_hash_entry *sym_hash;
sym_hash = (struct elf32_mn10300_link_hash_entry *) *hashes;
if ((sym_hash->root.root.type == bfd_link_hash_defined
|| sym_hash->root.root.type == bfd_link_hash_defweak)
&& sym_hash->root.root.u.def.section == section
&& ! (sym_hash->flags & MN10300_CONVERT_CALL_TO_CALLS)
&& ! (sym_hash->flags & MN10300_DELETED_PROLOGUE_BYTES))
{
int bytes = 0;
bfd_vma symval;
elf_section_data (section)->relocs = internal_relocs;
elf_section_data (section)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
if (sym_hash->movm_args)
bytes += 2;
if (sym_hash->stack_size > 0)
{
if (sym_hash->stack_size <= 128)
bytes += 3;
else
bytes += 4;
}
sym_hash->flags |= MN10300_DELETED_PROLOGUE_BYTES;
symval = sym_hash->root.root.u.def.value;
if (!mn10300_elf_relax_delete_bytes (input_bfd,
section,
symval,
bytes))
goto error_return;
*again = TRUE;
}
}
if (internal_relocs != NULL
&& elf_section_data (section)->relocs != internal_relocs)
free (internal_relocs);
internal_relocs = NULL;
if (contents != NULL
&& elf_section_data (section)->this_hdr.contents != contents)
{
if (! link_info->keep_memory)
free (contents);
else
{
elf_section_data (section)->this_hdr.contents = contents;
}
}
contents = NULL;
}
if (isymbuf != NULL
&& symtab_hdr->contents != (unsigned char *) isymbuf)
{
if (! link_info->keep_memory)
free (isymbuf);
else
{
symtab_hdr->contents = (unsigned char *) isymbuf;
}
}
isymbuf = NULL;
}
}
contents = NULL;
internal_relocs = NULL;
isymbuf = NULL;
section = sec;
if (link_info->relocatable
|| (sec->flags & SEC_RELOC) == 0
|| sec->reloc_count == 0
|| (sec->flags & SEC_CODE) == 0)
return TRUE;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
internal_relocs = (_bfd_elf_link_read_relocs
(abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
irelend = internal_relocs + sec->reloc_count;
for (irel = internal_relocs; irel < irelend; irel++)
{
bfd_vma symval;
struct elf32_mn10300_link_hash_entry *h = NULL;
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_NONE
|| ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_8
|| ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_MAX)
continue;
if (contents == NULL)
{
if (elf_section_data (sec)->this_hdr.contents != NULL)
contents = elf_section_data (sec)->this_hdr.contents;
else
{
if (!bfd_malloc_and_get_section (abfd, sec, &contents))
goto error_return;
}
}
if (isymbuf == NULL && symtab_hdr->sh_info != 0)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
goto error_return;
}
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
Elf_Internal_Sym *isym;
asection *sym_sec = NULL;
const char *sym_name;
char *new_name;
bfd_vma saved_addend;
isym = isymbuf + ELF32_R_SYM (irel->r_info);
if (isym->st_shndx == SHN_UNDEF)
sym_sec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS)
sym_sec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
sym_sec = bfd_com_section_ptr;
else
sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
sym_name = bfd_elf_string_from_elf_section (abfd,
symtab_hdr->sh_link,
isym->st_name);
if ((sym_sec->flags & SEC_MERGE)
&& ELF_ST_TYPE (isym->st_info) == STT_SECTION
&& sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
{
saved_addend = irel->r_addend;
symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel);
symval += irel->r_addend;
irel->r_addend = saved_addend;
}
else
{
symval = (isym->st_value
+ sym_sec->output_section->vma
+ sym_sec->output_offset);
}
new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10);
if (new_name == 0)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
h = (struct elf32_mn10300_link_hash_entry *)
elf_link_hash_lookup (&hash_table->static_hash_table->root,
sym_name, FALSE, FALSE, FALSE);
free (new_name);
}
else
{
unsigned long indx;
indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
h = (struct elf32_mn10300_link_hash_entry *)
(elf_sym_hashes (abfd)[indx]);
BFD_ASSERT (h != NULL);
if (h->root.root.type != bfd_link_hash_defined
&& h->root.root.type != bfd_link_hash_defweak)
{
continue;
}
symval = (h->root.root.u.def.value
+ h->root.root.u.def.section->output_section->vma
+ h->root.root.u.def.section->output_offset);
}
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL32
|| ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PLT32)
{
bfd_vma value = symval;
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PLT32
&& h != NULL
&& ELF_ST_VISIBILITY (h->root.other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (h->root.other) != STV_HIDDEN
&& h->root.plt.offset != (bfd_vma) -1)
{
asection * splt;
splt = bfd_get_section_by_name (elf_hash_table (link_info)
->dynobj, ".plt");
value = ((splt->output_section->vma
+ splt->output_offset
+ h->root.plt.offset)
- (sec->output_section->vma
+ sec->output_offset
+ irel->r_offset));
}
if (h && (h->flags & MN10300_CONVERT_CALL_TO_CALLS))
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code == 0xdd)
{
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfc, contents + irel->r_offset - 1);
bfd_put_8 (abfd, 0xff, contents + irel->r_offset);
irel->r_offset += 1;
irel->r_addend += 1;
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 3, 1))
goto error_return;
*again = TRUE;
}
}
else if (h)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code == 0xdd)
{
bfd_put_8 (abfd, h->movm_args, contents + irel->r_offset + 4);
bfd_put_8 (abfd, h->stack_size + h->movm_stack_size,
contents + irel->r_offset + 5);
}
}
value -= (sec->output_section->vma + sec->output_offset);
value -= irel->r_offset;
value += irel->r_addend;
if ((long) value < 0x8001 && (long) value > -0x8000)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code != 0xdc && code != 0xdd && code != 0xff)
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
if (code == 0xdc)
bfd_put_8 (abfd, 0xcc, contents + irel->r_offset - 1);
else if (code == 0xdd)
bfd_put_8 (abfd, 0xcd, contents + irel->r_offset - 1);
else if (code == 0xff)
bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_PLT32)
? R_MN10300_PLT16 :
R_MN10300_PCREL16);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 2))
goto error_return;
*again = TRUE;
}
}
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL16)
{
bfd_vma value = symval;
if (h && (h->flags & MN10300_CONVERT_CALL_TO_CALLS))
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code == 0xcd)
{
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 1);
bfd_put_8 (abfd, 0xff, contents + irel->r_offset);
irel->r_offset += 1;
irel->r_addend += 1;
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 1))
goto error_return;
*again = TRUE;
}
}
else if (h)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code == 0xcd)
{
bfd_put_8 (abfd, h->movm_args, contents + irel->r_offset + 2);
bfd_put_8 (abfd, h->stack_size + h->movm_stack_size,
contents + irel->r_offset + 3);
}
}
value -= (sec->output_section->vma + sec->output_offset);
value -= irel->r_offset;
value += irel->r_addend;
if ((long) value < 0x80 && (long) value > -0x80)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code != 0xcc)
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xca, contents + irel->r_offset - 1);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
R_MN10300_PCREL8);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 1))
goto error_return;
*again = TRUE;
}
}
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL8)
{
Elf_Internal_Rela *nrel;
bfd_vma value = symval;
unsigned char code;
value -= (sec->output_section->vma + sec->output_offset);
value -= irel->r_offset;
value += irel->r_addend;
if (irel->r_offset == sec->size)
continue;
code = bfd_get_8 (abfd, contents + irel->r_offset + 1);
if (code != 0xca)
continue;
nrel = irel + 1;
if (nrel == irelend
|| irel->r_offset + 2 != nrel->r_offset
|| ELF32_R_TYPE (nrel->r_info) != (int) R_MN10300_PCREL8)
continue;
if (symval != (sec->output_section->vma + sec->output_offset
+ irel->r_offset + 3))
continue;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if (code != 0xc0 && code != 0xc1 && code != 0xc2
&& code != 0xc3 && code != 0xc4 && code != 0xc5
&& code != 0xc6 && code != 0xc7 && code != 0xc8
&& code != 0xc9 && code != 0xe8 && code != 0xe9
&& code != 0xea && code != 0xeb)
continue;
if (mn10300_elf_symbol_address_p (abfd, sec, isymbuf,
irel->r_offset + 1))
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
switch (code)
{
case 0xc8:
code = 0xc9;
break;
case 0xc9:
code = 0xc8;
break;
case 0xc0:
code = 0xc2;
break;
case 0xc2:
code = 0xc0;
break;
case 0xc3:
code = 0xc1;
break;
case 0xc1:
code = 0xc3;
break;
case 0xc4:
code = 0xc6;
break;
case 0xc6:
code = 0xc4;
break;
case 0xc7:
code = 0xc5;
break;
case 0xc5:
code = 0xc7;
break;
case 0xe8:
code = 0xe9;
break;
case 0x9d:
code = 0xe8;
break;
case 0xea:
code = 0xeb;
break;
case 0xeb:
code = 0xea;
break;
}
bfd_put_8 (abfd, code, contents + irel->r_offset - 1);
irel->r_info = nrel->r_info;
nrel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info),
R_MN10300_NONE);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 2))
goto error_return;
*again = TRUE;
}
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_24)
{
bfd_vma value = symval;
value += irel->r_addend;
if ((long) value < 0x7f && (long) value > -0x80)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 3);
if (code == 0xfd)
{
code = bfd_get_8 (abfd, contents + irel->r_offset - 2);
if (code != 0x6b && code != 0x7b
&& code != 0x8b && code != 0x9b
&& ((code & 0x0f) == 0x09 || (code & 0x0f) == 0x08
|| (code & 0x0f) == 0x0a || (code & 0x0f) == 0x0b
|| (code & 0x0f) == 0x0e))
{
if ((value & 0x80) == 0)
{
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfb, contents + irel->r_offset - 3);
bfd_put_8 (abfd, code, contents + irel->r_offset - 2);
irel->r_info =
ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
R_MN10300_8);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 2))
goto error_return;
*again = TRUE;
break;
}
}
}
}
}
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_32
|| ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOT32
|| ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTOFF32
|| ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTPC32)
{
bfd_vma value = symval;
if (ELF32_R_TYPE (irel->r_info) != (int) R_MN10300_32)
{
asection * sgot;
sgot = bfd_get_section_by_name (elf_hash_table (link_info)
->dynobj, ".got");
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOT32)
{
value = sgot->output_offset;
if (h)
value += h->root.got.offset;
else
value += (elf_local_got_offsets
(abfd)[ELF32_R_SYM (irel->r_info)]);
}
else if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTOFF32)
value -= sgot->output_section->vma;
else if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTPC32)
value = (sgot->output_section->vma
- (sec->output_section->vma
+ sec->output_offset
+ irel->r_offset));
else
abort ();
}
value += irel->r_addend;
if ((long) value < 0x7fffff && (long) value > -0x800000)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 3);
if (code == 0xfe)
{
code = bfd_get_8 (abfd, contents + irel->r_offset - 2);
if (code != 0x6b && code != 0x7b
&& code != 0x8b && code != 0x9b
&& (ELF32_R_TYPE (irel->r_info)
!= (int) R_MN10300_GOTPC32)
&& ((code & 0x0f) == 0x09 || (code & 0x0f) == 0x08
|| (code & 0x0f) == 0x0a || (code & 0x0f) == 0x0b
|| (code & 0x0f) == 0x0e))
{
if ((value & 0x8000) == 0)
{
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfd, contents + irel->r_offset - 3);
bfd_put_8 (abfd, code, contents + irel->r_offset - 2);
irel->r_info =
ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF24
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT24 :
R_MN10300_24);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 3, 1))
goto error_return;
*again = TRUE;
break;
}
}
}
}
if ((long) value < 0x7fff && (long) value > -0x8000)
{
unsigned char code;
code = bfd_get_8 (abfd, contents + irel->r_offset - 2);
if (code != 0xfc)
continue;
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
if ((code & 0xf0) < 0x80)
switch (code & 0xf0)
{
case 0x00:
case 0x10:
case 0x20:
case 0x30:
case 0x40:
case 0x50:
case 0x60:
case 0x70:
if (code == 0xcc
&& (value & 0x8000))
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2);
bfd_put_8 (abfd, code, contents + irel->r_offset - 1);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTPC32)
? R_MN10300_GOTPC16 :
R_MN10300_16);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 2, 2))
goto error_return;
*again = TRUE;
break;
}
else if ((code & 0xf0) == 0x80
|| (code & 0xf0) == 0x90)
switch (code & 0xf3)
{
case 0x81:
case 0x82:
case 0x83:
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
if ((code & 0xf3) == 0x81)
code = 0x01 + (code & 0x0c);
else if ((code & 0xf3) == 0x82)
code = 0x02 + (code & 0x0c);
else if ((code & 0xf3) == 0x83)
code = 0x03 + (code & 0x0c);
else
abort ();
bfd_put_8 (abfd, code, contents + irel->r_offset - 2);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTPC32)
? R_MN10300_GOTPC16 :
R_MN10300_16);
irel->r_offset -= 1;
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 3))
goto error_return;
*again = TRUE;
break;
case 0x80:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
if (code >= 0x90 && code <= 0x93
&& (long)value < 0)
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2);
bfd_put_8 (abfd, code, contents + irel->r_offset - 1);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTPC32)
? R_MN10300_GOTPC16 :
R_MN10300_16);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 2, 2))
goto error_return;
*again = TRUE;
break;
}
else if ((code & 0xf0) < 0xf0)
switch (code & 0xfc)
{
case 0xcc:
case 0xdc:
case 0xa4:
case 0xa8:
case 0xac:
if (code == 0xcc
&& (value & 0x8000))
continue;
if (code == 0xdc
&& (long)value < 0)
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
if ((code & 0xfc) == 0xcc)
code = 0x2c + (code & 0x03);
else if ((code & 0xfc) == 0xdc)
code = 0x24 + (code & 0x03);
else if ((code & 0xfc) == 0xa4)
code = 0x30 + (code & 0x03);
else if ((code & 0xfc) == 0xa8)
code = 0x34 + (code & 0x03);
else if ((code & 0xfc) == 0xac)
code = 0x38 + (code & 0x03);
else
abort ();
bfd_put_8 (abfd, code, contents + irel->r_offset - 2);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTPC32)
? R_MN10300_GOTPC16 :
R_MN10300_16);
irel->r_offset -= 1;
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 1, 3))
goto error_return;
*again = TRUE;
break;
case 0xa0:
case 0xb0:
case 0xb1:
case 0xb2:
case 0xb3:
case 0xc0:
case 0xc8:
case 0xd0:
case 0xd8:
case 0xe0:
case 0xe1:
case 0xe2:
case 0xe3:
if (code == 0xdc
&& (long)value < 0)
continue;
if (code >= 0xb0 && code <= 0xb3
&& (long)value < 0)
continue;
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2);
bfd_put_8 (abfd, code, contents + irel->r_offset - 1);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTPC32)
? R_MN10300_GOTPC16 :
R_MN10300_16);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 2, 2))
goto error_return;
*again = TRUE;
break;
}
else if (code == 0xfe)
{
elf_section_data (sec)->relocs = internal_relocs;
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2);
bfd_put_8 (abfd, 0xfe, contents + irel->r_offset - 1);
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
(ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOT32)
? R_MN10300_GOT16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTOFF32)
? R_MN10300_GOTOFF16
: (ELF32_R_TYPE (irel->r_info)
== (int) R_MN10300_GOTPC32)
? R_MN10300_GOTPC16 :
R_MN10300_16);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 2, 2))
goto error_return;
*again = TRUE;
break;
}
}
}
}
if (isymbuf != NULL
&& symtab_hdr->contents != (unsigned char *) isymbuf)
{
if (! link_info->keep_memory)
free (isymbuf);
else
{
symtab_hdr->contents = (unsigned char *) isymbuf;
}
}
if (contents != NULL
&& elf_section_data (sec)->this_hdr.contents != contents)
{
if (! link_info->keep_memory)
free (contents);
else
{
elf_section_data (sec)->this_hdr.contents = contents;
}
}
if (internal_relocs != NULL
&& elf_section_data (sec)->relocs != internal_relocs)
free (internal_relocs);
return TRUE;
error_return:
if (isymbuf != NULL
&& symtab_hdr->contents != (unsigned char *) isymbuf)
free (isymbuf);
if (contents != NULL
&& elf_section_data (section)->this_hdr.contents != contents)
free (contents);
if (internal_relocs != NULL
&& elf_section_data (section)->relocs != internal_relocs)
free (internal_relocs);
return FALSE;
}
static void
compute_function_info (abfd, hash, addr, contents)
bfd *abfd;
struct elf32_mn10300_link_hash_entry *hash;
bfd_vma addr;
unsigned char *contents;
{
unsigned char byte1, byte2;
byte1 = bfd_get_8 (abfd, contents + addr);
byte2 = bfd_get_8 (abfd, contents + addr + 1);
if (byte1 == 0xcf)
{
hash->movm_args = byte2;
addr += 2;
byte1 = bfd_get_8 (abfd, contents + addr);
byte2 = bfd_get_8 (abfd, contents + addr + 1);
}
if (hash->movm_args)
{
if (hash->movm_args & 0x80)
hash->movm_stack_size += 4;
if (hash->movm_args & 0x40)
hash->movm_stack_size += 4;
if (hash->movm_args & 0x20)
hash->movm_stack_size += 4;
if (hash->movm_args & 0x10)
hash->movm_stack_size += 4;
if (hash->movm_args & 0x08)
hash->movm_stack_size += 8 * 4;
if (bfd_get_mach (abfd) == bfd_mach_am33
|| bfd_get_mach (abfd) == bfd_mach_am33_2)
{
if (hash->movm_args & 0x1)
hash->movm_stack_size += 6 * 4;
if (hash->movm_args & 0x2)
hash->movm_stack_size += 4 * 4;
if (hash->movm_args & 0x4)
hash->movm_stack_size += 2 * 4;
}
}
if (byte1 == 0xf8 && byte2 == 0xfe)
{
int temp = bfd_get_8 (abfd, contents + addr + 2);
temp = ((temp & 0xff) ^ (~0x7f)) + 0x80;
hash->stack_size = -temp;
}
else if (byte1 == 0xfa && byte2 == 0xfe)
{
int temp = bfd_get_16 (abfd, contents + addr + 2);
temp = ((temp & 0xffff) ^ (~0x7fff)) + 0x8000;
temp = -temp;
if (temp < 255)
hash->stack_size = temp;
}
if (hash->stack_size + hash->movm_stack_size > 255)
hash->stack_size = 0;
return;
}
static bfd_boolean
mn10300_elf_relax_delete_bytes (abfd, sec, addr, count)
bfd *abfd;
asection *sec;
bfd_vma addr;
int count;
{
Elf_Internal_Shdr *symtab_hdr;
unsigned int sec_shndx;
bfd_byte *contents;
Elf_Internal_Rela *irel, *irelend;
Elf_Internal_Rela *irelalign;
bfd_vma toaddr;
Elf_Internal_Sym *isym, *isymend;
struct elf_link_hash_entry **sym_hashes;
struct elf_link_hash_entry **end_hashes;
unsigned int symcount;
sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
contents = elf_section_data (sec)->this_hdr.contents;
irelalign = NULL;
toaddr = sec->size;
irel = elf_section_data (sec)->relocs;
irelend = irel + sec->reloc_count;
memmove (contents + addr, contents + addr + count,
(size_t) (toaddr - addr - count));
sec->size -= count;
for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
{
if ((irel->r_offset > addr
&& irel->r_offset < toaddr))
irel->r_offset -= count;
}
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
{
if (isym->st_shndx == sec_shndx
&& isym->st_value > addr
&& isym->st_value < toaddr)
isym->st_value -= count;
}
symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
- symtab_hdr->sh_info);
sym_hashes = elf_sym_hashes (abfd);
end_hashes = sym_hashes + symcount;
for (; sym_hashes < end_hashes; sym_hashes++)
{
struct elf_link_hash_entry *sym_hash = *sym_hashes;
if ((sym_hash->root.type == bfd_link_hash_defined
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec
&& sym_hash->root.u.def.value > addr
&& sym_hash->root.u.def.value < toaddr)
{
sym_hash->root.u.def.value -= count;
}
}
return TRUE;
}
static bfd_boolean
mn10300_elf_symbol_address_p (abfd, sec, isym, addr)
bfd *abfd;
asection *sec;
Elf_Internal_Sym *isym;
bfd_vma addr;
{
Elf_Internal_Shdr *symtab_hdr;
unsigned int sec_shndx;
Elf_Internal_Sym *isymend;
struct elf_link_hash_entry **sym_hashes;
struct elf_link_hash_entry **end_hashes;
unsigned int symcount;
sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
{
if (isym->st_shndx == sec_shndx
&& isym->st_value == addr)
return TRUE;
}
symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
- symtab_hdr->sh_info);
sym_hashes = elf_sym_hashes (abfd);
end_hashes = sym_hashes + symcount;
for (; sym_hashes < end_hashes; sym_hashes++)
{
struct elf_link_hash_entry *sym_hash = *sym_hashes;
if ((sym_hash->root.type == bfd_link_hash_defined
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec
&& sym_hash->root.u.def.value == addr)
return TRUE;
}
return FALSE;
}
static bfd_byte *
mn10300_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
data, relocatable, symbols)
bfd *output_bfd;
struct bfd_link_info *link_info;
struct bfd_link_order *link_order;
bfd_byte *data;
bfd_boolean relocatable;
asymbol **symbols;
{
Elf_Internal_Shdr *symtab_hdr;
asection *input_section = link_order->u.indirect.section;
bfd *input_bfd = input_section->owner;
asection **sections = NULL;
Elf_Internal_Rela *internal_relocs = NULL;
Elf_Internal_Sym *isymbuf = NULL;
if (relocatable
|| elf_section_data (input_section)->this_hdr.contents == NULL)
return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
link_order, data,
relocatable,
symbols);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
memcpy (data, elf_section_data (input_section)->this_hdr.contents,
(size_t) input_section->size);
if ((input_section->flags & SEC_RELOC) != 0
&& input_section->reloc_count > 0)
{
asection **secpp;
Elf_Internal_Sym *isym, *isymend;
bfd_size_type amt;
internal_relocs = (_bfd_elf_link_read_relocs
(input_bfd, input_section, (PTR) NULL,
(Elf_Internal_Rela *) NULL, FALSE));
if (internal_relocs == NULL)
goto error_return;
if (symtab_hdr->sh_info != 0)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
goto error_return;
}
amt = symtab_hdr->sh_info;
amt *= sizeof (asection *);
sections = (asection **) bfd_malloc (amt);
if (sections == NULL && amt != 0)
goto error_return;
isymend = isymbuf + symtab_hdr->sh_info;
for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp)
{
asection *isec;
if (isym->st_shndx == SHN_UNDEF)
isec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS)
isec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
isec = bfd_com_section_ptr;
else
isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
*secpp = isec;
}
if (! mn10300_elf_relocate_section (output_bfd, link_info, input_bfd,
input_section, data, internal_relocs,
isymbuf, sections))
goto error_return;
if (sections != NULL)
free (sections);
if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
free (isymbuf);
if (internal_relocs != elf_section_data (input_section)->relocs)
free (internal_relocs);
}
return data;
error_return:
if (sections != NULL)
free (sections);
if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
free (isymbuf);
if (internal_relocs != NULL
&& internal_relocs != elf_section_data (input_section)->relocs)
free (internal_relocs);
return NULL;
}
static struct bfd_hash_entry *
elf32_mn10300_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct elf32_mn10300_link_hash_entry *ret =
(struct elf32_mn10300_link_hash_entry *) entry;
if (ret == (struct elf32_mn10300_link_hash_entry *) NULL)
ret = ((struct elf32_mn10300_link_hash_entry *)
bfd_hash_allocate (table,
sizeof (struct elf32_mn10300_link_hash_entry)));
if (ret == (struct elf32_mn10300_link_hash_entry *) NULL)
return (struct bfd_hash_entry *) ret;
ret = ((struct elf32_mn10300_link_hash_entry *)
_bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != (struct elf32_mn10300_link_hash_entry *) NULL)
{
ret->direct_calls = 0;
ret->stack_size = 0;
ret->movm_args = 0;
ret->movm_stack_size = 0;
ret->flags = 0;
}
return (struct bfd_hash_entry *) ret;
}
static struct bfd_link_hash_table *
elf32_mn10300_link_hash_table_create (abfd)
bfd *abfd;
{
struct elf32_mn10300_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf32_mn10300_link_hash_table);
ret = (struct elf32_mn10300_link_hash_table *) bfd_malloc (amt);
if (ret == (struct elf32_mn10300_link_hash_table *) NULL)
return NULL;
if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
elf32_mn10300_link_hash_newfunc))
{
free (ret);
return NULL;
}
ret->flags = 0;
amt = sizeof (struct elf_link_hash_table);
ret->static_hash_table
= (struct elf32_mn10300_link_hash_table *) bfd_malloc (amt);
if (ret->static_hash_table == NULL)
{
free (ret);
return NULL;
}
if (! _bfd_elf_link_hash_table_init (&ret->static_hash_table->root, abfd,
elf32_mn10300_link_hash_newfunc))
{
free (ret->static_hash_table);
free (ret);
return NULL;
}
return &ret->root.root;
}
static void
elf32_mn10300_link_hash_table_free (hash)
struct bfd_link_hash_table *hash;
{
struct elf32_mn10300_link_hash_table *ret
= (struct elf32_mn10300_link_hash_table *) hash;
_bfd_generic_link_hash_table_free
((struct bfd_link_hash_table *) ret->static_hash_table);
_bfd_generic_link_hash_table_free
((struct bfd_link_hash_table *) ret);
}
static unsigned long
elf_mn10300_mach (flags)
flagword flags;
{
switch (flags & EF_MN10300_MACH)
{
case E_MN10300_MACH_MN10300:
default:
return bfd_mach_mn10300;
case E_MN10300_MACH_AM33:
return bfd_mach_am33;
case E_MN10300_MACH_AM33_2:
return bfd_mach_am33_2;
}
}
void
_bfd_mn10300_elf_final_write_processing (abfd, linker)
bfd *abfd;
bfd_boolean linker ATTRIBUTE_UNUSED;
{
unsigned long val;
switch (bfd_get_mach (abfd))
{
default:
case bfd_mach_mn10300:
val = E_MN10300_MACH_MN10300;
break;
case bfd_mach_am33:
val = E_MN10300_MACH_AM33;
break;
case bfd_mach_am33_2:
val = E_MN10300_MACH_AM33_2;
break;
}
elf_elfheader (abfd)->e_flags &= ~ (EF_MN10300_MACH);
elf_elfheader (abfd)->e_flags |= val;
}
bfd_boolean
_bfd_mn10300_elf_object_p (abfd)
bfd *abfd;
{
bfd_default_set_arch_mach (abfd, bfd_arch_mn10300,
elf_mn10300_mach (elf_elfheader (abfd)->e_flags));
return TRUE;
}
bfd_boolean
_bfd_mn10300_elf_merge_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
&& bfd_get_mach (obfd) < bfd_get_mach (ibfd))
{
if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
bfd_get_mach (ibfd)))
return FALSE;
}
return TRUE;
}
#define PLT0_ENTRY_SIZE 15
#define PLT_ENTRY_SIZE 20
#define PIC_PLT_ENTRY_SIZE 24
static const bfd_byte elf_mn10300_plt0_entry[PLT0_ENTRY_SIZE] =
{
0xfc, 0xa0, 0, 0, 0, 0,
0xfe, 0xe, 0x10, 0, 0, 0, 0,
0xf0, 0xf4,
};
static const bfd_byte elf_mn10300_plt_entry[PLT_ENTRY_SIZE] =
{
0xfc, 0xa0, 0, 0, 0, 0,
0xf0, 0xf4,
0xfe, 8, 0, 0, 0, 0, 0,
0xdc, 0, 0, 0, 0,
};
static const bfd_byte elf_mn10300_pic_plt_entry[PIC_PLT_ENTRY_SIZE] =
{
0xfc, 0x22, 0, 0, 0, 0,
0xf0, 0xf4,
0xfe, 8, 0, 0, 0, 0, 0,
0xf8, 0x22, 8,
0xfb, 0xa, 0x1a, 4,
0xf0, 0xf4,
};
#define elf_mn10300_sizeof_plt0(info) \
(info->shared ? PIC_PLT_ENTRY_SIZE : PLT0_ENTRY_SIZE)
#define elf_mn10300_sizeof_plt(info) \
(info->shared ? PIC_PLT_ENTRY_SIZE : PLT_ENTRY_SIZE)
#define elf_mn10300_plt_plt0_offset(info) 16
#define elf_mn10300_plt0_linker_offset(info) 2
#define elf_mn10300_plt0_gotid_offset(info) 9
#define elf_mn10300_plt_temp_offset(info) 8
#define elf_mn10300_plt_symbol_offset(info) 2
#define elf_mn10300_plt_reloc_offset(info) 11
#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
static bfd_boolean
_bfd_mn10300_elf_create_dynamic_sections (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
flagword flags;
asection * s;
const struct elf_backend_data * bed = get_elf_backend_data (abfd);
int ptralign = 0;
switch (bed->s->arch_size)
{
case 32:
ptralign = 2;
break;
case 64:
ptralign = 3;
break;
default:
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
s = bfd_make_section_with_flags (abfd,
(bed->default_use_rela_p
? ".rela.plt" : ".rel.plt"),
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
if (! _bfd_mn10300_elf_create_got_section (abfd, info))
return FALSE;
{
const char * secname;
char * relname;
flagword secflags;
asection * sec;
for (sec = abfd->sections; sec; sec = sec->next)
{
secflags = bfd_get_section_flags (abfd, sec);
if ((secflags & (SEC_DATA | SEC_LINKER_CREATED))
|| ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS))
continue;
secname = bfd_get_section_name (abfd, sec);
relname = (char *) bfd_malloc (strlen (secname) + 6);
strcpy (relname, ".rela");
strcat (relname, secname);
s = bfd_make_section_with_flags (abfd, relname,
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
}
}
if (bed->want_dynbss)
{
s = bfd_make_section_with_flags (abfd, ".dynbss",
SEC_ALLOC | SEC_LINKER_CREATED);
if (s == NULL)
return FALSE;
if (! info->shared)
{
s = bfd_make_section_with_flags (abfd,
(bed->default_use_rela_p
? ".rela.bss" : ".rel.bss"),
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
}
}
return TRUE;
}
static bfd_boolean
_bfd_mn10300_elf_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;
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)));
if (h->type == STT_FUNC
|| h->needs_plt)
{
if (! info->shared
&& !h->def_dynamic
&& !h->ref_dynamic)
{
BFD_ASSERT (h->needs_plt);
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 += elf_mn10300_sizeof_plt0 (info);
if (! info->shared
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = s->size;
}
h->plt.offset = s->size;
s->size += elf_mn10300_sizeof_plt (info);
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;
}
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
_bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
bfd * output_bfd;
struct bfd_link_info * info;
{
bfd * dynobj;
asection * s;
bfd_boolean plt;
bfd_boolean relocs;
bfd_boolean reltext;
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
{
s = bfd_get_section_by_name (dynobj, ".rela.got");
if (s != NULL)
s->size = 0;
}
plt = FALSE;
relocs = FALSE;
reltext = 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)
{
asection * target;
if (strcmp (name, ".rela.plt") != 0)
{
const char * outname;
relocs = TRUE;
outname = bfd_get_section_name (output_bfd,
s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 5);
if (target != NULL
&& (target->flags & SEC_READONLY) != 0
&& (target->flags & SEC_ALLOC) != 0)
reltext = 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)
{
if (! info->shared)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0))
return FALSE;
}
if (plt)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
|| !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0))
return FALSE;
}
if (relocs)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_RELAENT,
sizeof (Elf32_External_Rela)))
return FALSE;
}
if (reltext)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0))
return FALSE;
}
}
return TRUE;
}
static bfd_boolean
_bfd_mn10300_elf_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;
dynobj = elf_hash_table (info)->dynobj;
if (h->plt.offset != (bfd_vma) -1)
{
asection * splt;
asection * sgot;
asection * srel;
bfd_vma plt_index;
bfd_vma got_offset;
Elf_Internal_Rela rel;
BFD_ASSERT (h->dynindx != -1);
splt = bfd_get_section_by_name (dynobj, ".plt");
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
srel = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
plt_index = ((h->plt.offset - elf_mn10300_sizeof_plt0 (info))
/ elf_mn10300_sizeof_plt (info));
got_offset = (plt_index + 3) * 4;
if (! info->shared)
{
memcpy (splt->contents + h->plt.offset, elf_mn10300_plt_entry,
elf_mn10300_sizeof_plt (info));
bfd_put_32 (output_bfd,
(sgot->output_section->vma
+ sgot->output_offset
+ got_offset),
(splt->contents + h->plt.offset
+ elf_mn10300_plt_symbol_offset (info)));
bfd_put_32 (output_bfd,
(1 - h->plt.offset - elf_mn10300_plt_plt0_offset (info)),
(splt->contents + h->plt.offset
+ elf_mn10300_plt_plt0_offset (info)));
}
else
{
memcpy (splt->contents + h->plt.offset, elf_mn10300_pic_plt_entry,
elf_mn10300_sizeof_plt (info));
bfd_put_32 (output_bfd, got_offset,
(splt->contents + h->plt.offset
+ elf_mn10300_plt_symbol_offset (info)));
}
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela),
(splt->contents + h->plt.offset
+ elf_mn10300_plt_reloc_offset (info)));
bfd_put_32 (output_bfd,
(splt->output_section->vma
+ splt->output_offset
+ h->plt.offset
+ elf_mn10300_plt_temp_offset (info)),
sgot->contents + got_offset);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ got_offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_JMP_SLOT);
rel.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &rel,
(bfd_byte *) ((Elf32_External_Rela *) srel->contents
+ plt_index));
if (!h->def_regular)
sym->st_shndx = SHN_UNDEF;
}
if (h->got.offset != (bfd_vma) -1)
{
asection * sgot;
asection * srel;
Elf_Internal_Rela rel;
sgot = bfd_get_section_by_name (dynobj, ".got");
srel = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (sgot != NULL && srel != NULL);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ (h->got.offset &~ 1));
if (info->shared
&& (info->symbolic || h->dynindx == -1)
&& h->def_regular)
{
rel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
rel.r_addend = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
}
else
{
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT);
rel.r_addend = 0;
}
bfd_elf32_swap_reloca_out (output_bfd, &rel,
(bfd_byte *) ((Elf32_External_Rela *) srel->contents
+ srel->reloc_count));
++ srel->reloc_count;
}
if (h->needs_copy)
{
asection * s;
Elf_Internal_Rela rel;
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);
rel.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_COPY);
rel.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &rel,
(bfd_byte *) ((Elf32_External_Rela *) s->contents
+ s->reloc_count));
++ s->reloc_count;
}
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
_bfd_mn10300_elf_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;
Elf32_External_Dyn * dynconend;
BFD_ASSERT (sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
const char * name;
asection * s;
bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
default:
break;
case DT_PLTGOT:
name = ".got";
goto get_vma;
case DT_JMPREL:
name = ".rela.plt";
get_vma:
s = bfd_get_section_by_name (output_bfd, name);
BFD_ASSERT (s != NULL);
dyn.d_un.d_ptr = s->vma;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_PLTRELSZ:
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
BFD_ASSERT (s != NULL);
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;
}
}
splt = bfd_get_section_by_name (dynobj, ".plt");
if (splt && splt->size > 0)
{
if (info->shared)
{
memcpy (splt->contents, elf_mn10300_pic_plt_entry,
elf_mn10300_sizeof_plt (info));
}
else
{
memcpy (splt->contents, elf_mn10300_plt0_entry, PLT0_ENTRY_SIZE);
bfd_put_32 (output_bfd,
sgot->output_section->vma + sgot->output_offset + 4,
splt->contents + elf_mn10300_plt0_gotid_offset (info));
bfd_put_32 (output_bfd,
sgot->output_section->vma + sgot->output_offset + 8,
splt->contents + elf_mn10300_plt0_linker_offset (info));
}
elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
}
}
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 enum elf_reloc_type_class
_bfd_mn10300_elf_reloc_type_class (const Elf_Internal_Rela *rela)
{
switch ((int) ELF32_R_TYPE (rela->r_info))
{
case R_MN10300_RELATIVE:
return reloc_class_relative;
case R_MN10300_JMP_SLOT:
return reloc_class_plt;
case R_MN10300_COPY:
return reloc_class_copy;
default:
return reloc_class_normal;
}
}
#ifndef ELF_ARCH
#define TARGET_LITTLE_SYM bfd_elf32_mn10300_vec
#define TARGET_LITTLE_NAME "elf32-mn10300"
#define ELF_ARCH bfd_arch_mn10300
#define ELF_MACHINE_CODE EM_MN10300
#define ELF_MACHINE_ALT1 EM_CYGNUS_MN10300
#define ELF_MAXPAGESIZE 0x1000
#endif
#define elf_info_to_howto mn10300_info_to_howto
#define elf_info_to_howto_rel 0
#define elf_backend_can_gc_sections 1
#define elf_backend_rela_normal 1
#define elf_backend_check_relocs mn10300_elf_check_relocs
#define elf_backend_gc_mark_hook mn10300_elf_gc_mark_hook
#define elf_backend_relocate_section mn10300_elf_relocate_section
#define bfd_elf32_bfd_relax_section mn10300_elf_relax_section
#define bfd_elf32_bfd_get_relocated_section_contents \
mn10300_elf_get_relocated_section_contents
#define bfd_elf32_bfd_link_hash_table_create \
elf32_mn10300_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_free \
elf32_mn10300_link_hash_table_free
#ifndef elf_symbol_leading_char
#define elf_symbol_leading_char '_'
#endif
#define elf_backend_final_write_processing \
_bfd_mn10300_elf_final_write_processing
#define elf_backend_object_p _bfd_mn10300_elf_object_p
#define bfd_elf32_bfd_merge_private_bfd_data \
_bfd_mn10300_elf_merge_private_bfd_data
#define elf_backend_can_gc_sections 1
#define elf_backend_create_dynamic_sections \
_bfd_mn10300_elf_create_dynamic_sections
#define elf_backend_adjust_dynamic_symbol \
_bfd_mn10300_elf_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \
_bfd_mn10300_elf_size_dynamic_sections
#define elf_backend_finish_dynamic_symbol \
_bfd_mn10300_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
_bfd_mn10300_elf_finish_dynamic_sections
#define elf_backend_reloc_type_class \
_bfd_mn10300_elf_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
#include "elf32-target.h"