#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 bfd_link_info *,
asection *, int));
static boolean mn10300_elf_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static boolean mn10300_elf_relax_section
PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
static bfd_byte * mn10300_elf_get_relocated_section_contents
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *,
bfd_byte *, boolean, asymbol **));
static unsigned long elf_mn10300_mach PARAMS ((flagword));
void _bfd_mn10300_elf_final_write_processing PARAMS ((bfd *, boolean));
boolean _bfd_mn10300_elf_object_p PARAMS ((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, \
(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 *, Elf32_Internal_Rela *));
static boolean mn10300_elf_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static asection *mn10300_elf_gc_mark_hook
PARAMS ((bfd *, struct bfd_link_info *info, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
static boolean mn10300_elf_relax_delete_bytes
PARAMS ((bfd *, asection *, bfd_vma, int));
static boolean mn10300_elf_symbol_address_p
PARAMS ((bfd *, asection *, bfd_vma));
static 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 *));
#define USE_RELA
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),
};
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 },
};
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;
Elf32_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 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;
if (info->relocateable)
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;
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];
switch (ELF32_R_TYPE (rel->r_info))
{
case R_MN10300_GNU_VTINHERIT:
if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return false;
break;
case R_MN10300_GNU_VTENTRY:
if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return false;
break;
}
}
return true;
}
static asection *
mn10300_elf_gc_mark_hook (abfd, info, rel, h, sym)
bfd *abfd;
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 (abfd, 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, 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 bfd_link_info *info ATTRIBUTE_UNUSED;
asection *sym_sec ATTRIBUTE_UNUSED;
int is_local ATTRIBUTE_UNUSED;
{
unsigned long r_type = howto->type;
bfd_byte *hit_data = contents + offset;
switch (r_type)
{
case R_MN10300_NONE:
return bfd_reloc_ok;
case R_MN10300_32:
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;
default:
return bfd_reloc_notsupported;
}
}
static 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 elf32_mn10300_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel, *relend;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = (struct elf32_mn10300_link_hash_entry **)
(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;
if (info->relocateable)
{
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
sec = local_sections[r_symndx];
rel->r_addend += sec->output_offset + sym->st_value;
}
}
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
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.root.type == bfd_link_hash_indirect
|| h->root.root.type == bfd_link_hash_warning)
h = (struct elf32_mn10300_link_hash_entry *) h->root.root.u.i.link;
if (h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
{
sec = h->root.root.u.def.section;
relocation = (h->root.root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else if (h->root.root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.root.string, input_bfd,
input_section, rel->r_offset, true)))
return false;
relocation = 0;
}
}
r = mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
input_section,
contents, rel->r_offset,
relocation, rel->r_addend,
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, 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 boolean
elf32_mn10300_finish_hash_table_entry (gen_entry, in_args)
struct bfd_hash_entry *gen_entry;
PTR in_args ATTRIBUTE_UNUSED;
{
struct elf32_mn10300_link_hash_entry *entry;
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))
{
entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
return true;
}
if (entry->movm_args)
byte_count += 2;
if (entry->stack_size > 0 && entry->stack_size <= 128)
byte_count += 3;
else if (entry->stack_size > 0 && entry->stack_size < 256)
byte_count += 4;
if (byte_count < entry->direct_calls)
entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
return true;
}
static boolean
mn10300_elf_relax_section (abfd, sec, link_info, again)
bfd *abfd;
asection *sec;
struct bfd_link_info *link_info;
boolean *again;
{
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *shndx_hdr;
Elf_Internal_Rela *internal_relocs = NULL;
Elf_Internal_Rela *free_relocs = NULL;
Elf_Internal_Rela *irel, *irelend;
bfd_byte *contents = NULL;
bfd_byte *free_contents = NULL;
Elf32_External_Sym *extsyms = NULL;
Elf32_External_Sym *free_extsyms = NULL;
Elf_External_Sym_Shndx *shndx_buf = NULL;
struct elf32_mn10300_link_hash_table *hash_table;
*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)
{
asection *section;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
if (symtab_hdr->contents != NULL)
extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
else
{
bfd_size_type amt;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf32_External_Sym);
extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
if (extsyms == NULL)
goto error_return;
free_extsyms = extsyms;
if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) extsyms, amt, input_bfd) != amt)
goto error_return;
}
if (shndx_hdr->sh_size != 0)
{
bfd_size_type amt;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf_External_Sym_Shndx);
shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
if (shndx_buf == NULL)
goto error_return;
if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) shndx_buf, amt, input_bfd) != amt)
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->_raw_size != 0)
{
contents = (bfd_byte *) bfd_malloc (section->_raw_size);
if (contents == NULL)
goto error_return;
free_contents = contents;
if (!bfd_get_section_contents (input_bfd, section,
contents, (file_ptr) 0,
section->_raw_size))
goto error_return;
}
else
{
contents = NULL;
free_contents = NULL;
}
if ((section->flags & SEC_RELOC) != 0
&& section->reloc_count != 0)
{
internal_relocs = (_bfd_elf32_link_read_relocs
(input_bfd, section, (PTR) NULL,
(Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
if (! link_info->keep_memory)
free_relocs = internal_relocs;
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)
{
Elf32_External_Sym *esym;
Elf_External_Sym_Shndx *shndx;
Elf_Internal_Sym isym;
struct elf_link_hash_table *elftab;
bfd_size_type amt;
esym = extsyms + r_index;
shndx = shndx_buf + (shndx_buf ? r_index : 0);
bfd_elf32_swap_symbol_in (input_bfd, esym, shndx,
&isym);
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 (r_index < symtab_hdr->sh_info
&& 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, (int) sym_sec);
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_PCREL16)
hash->direct_calls++;
else
hash->flags |= MN10300_CONVERT_CALL_TO_CALLS;
}
}
if ((section->flags & SEC_CODE) != 0)
{
Elf32_External_Sym *esym, *esymend;
Elf_External_Sym_Shndx *shndx;
int idx;
unsigned int sec_shndx;
sec_shndx = _bfd_elf_section_from_bfd_section (input_bfd,
section);
for (esym = extsyms, esymend = esym + symtab_hdr->sh_info,
shndx = shndx_buf;
esym < esymend;
esym++, shndx = (shndx ? shndx + 1 : NULL))
{
Elf_Internal_Sym isym;
bfd_elf32_swap_symbol_in (input_bfd, esym, shndx, &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;
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, (int) sym_sec);
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);
}
}
esym = extsyms + symtab_hdr->sh_info;
esymend = extsyms + (symtab_hdr->sh_size
/ sizeof (Elf32_External_Sym));
for (idx = 0; esym < esymend; esym++, idx++)
{
Elf_Internal_Sym isym;
hash = (struct elf32_mn10300_link_hash_entry *)
elf_sym_hashes (input_bfd)[idx];
if ((hash->root.root.type == bfd_link_hash_defined
|| hash->root.root.type == bfd_link_hash_defweak)
&& hash->root.root.u.def.section == section
&& ELF_ST_TYPE (isym.st_info) == STT_FUNC)
compute_function_info (input_bfd, hash,
(hash)->root.root.u.def.value,
contents);
}
}
if (free_relocs != NULL)
{
free (free_relocs);
free_relocs = NULL;
}
if (free_contents != NULL)
{
if (! link_info->keep_memory)
free (free_contents);
else
{
elf_section_data (section)->this_hdr.contents = contents;
}
free_contents = NULL;
}
}
if (shndx_buf != NULL)
{
free (shndx_buf);
shndx_buf = NULL;
}
if (free_extsyms != NULL)
{
if (! link_info->keep_memory)
free (free_extsyms);
else
{
symtab_hdr->contents = (unsigned char *) extsyms;
}
free_extsyms = NULL;
}
}
elf32_mn10300_link_hash_traverse (hash_table,
elf32_mn10300_finish_hash_table_entry,
NULL);
elf32_mn10300_link_hash_traverse (hash_table->static_hash_table,
elf32_mn10300_finish_hash_table_entry,
NULL);
hash_table->flags |= MN10300_HASH_ENTRIES_INITIALIZED;
for (input_bfd = link_info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
{
asection *section;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
if (symtab_hdr->contents != NULL)
extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
else
{
bfd_size_type amt;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf32_External_Sym);
extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
if (extsyms == NULL)
goto error_return;
free_extsyms = extsyms;
if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) extsyms, amt, input_bfd) != amt)
goto error_return;
symtab_hdr->contents = (bfd_byte *) extsyms;
}
if (shndx_hdr->sh_size != 0)
{
bfd_size_type amt;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf_External_Sym_Shndx);
shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
if (shndx_buf == NULL)
goto error_return;
if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) shndx_buf, amt, input_bfd) != amt)
goto error_return;
shndx_hdr->contents = (bfd_byte *) shndx_buf;
}
for (section = input_bfd->sections;
section != NULL;
section = section->next)
{
unsigned int sec_shndx;
Elf32_External_Sym *esym, *esymend;
Elf_External_Sym_Shndx *shndx;
unsigned int idx;
if ((section->flags & SEC_CODE) == 0 || section->_raw_size == 0)
continue;
if (section->reloc_count != 0)
{
internal_relocs = (_bfd_elf32_link_read_relocs
(input_bfd, section, (PTR) NULL,
(Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
if (! link_info->keep_memory)
free_relocs = internal_relocs;
}
if (elf_section_data (section)->this_hdr.contents != NULL)
contents = elf_section_data (section)->this_hdr.contents;
else
{
contents = (bfd_byte *) bfd_malloc (section->_raw_size);
if (contents == NULL)
goto error_return;
free_contents = contents;
if (!bfd_get_section_contents (input_bfd, section,
contents, (file_ptr) 0,
section->_raw_size))
goto error_return;
}
sec_shndx = _bfd_elf_section_from_bfd_section (input_bfd,
section);
for (esym = extsyms, esymend = esym + symtab_hdr->sh_info,
shndx = shndx_buf;
esym < esymend;
esym++, shndx = (shndx ? shndx + 1 : NULL))
{
Elf_Internal_Sym 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;
bfd_elf32_swap_symbol_in (input_bfd, esym, shndx, &isym);
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, (int) sym_sec);
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;
free_relocs = NULL;
elf_section_data (section)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
if (sym_hash->movm_args)
bytes += 2;
if (sym_hash->stack_size && sym_hash->stack_size <= 128)
bytes += 3;
else if (sym_hash->stack_size
&& sym_hash->stack_size < 256)
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;
}
}
for (idx = 0;
idx < (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
- symtab_hdr->sh_info);
idx++)
{
struct elf32_mn10300_link_hash_entry *sym_hash;
sym_hash = (struct elf32_mn10300_link_hash_entry *)
(elf_sym_hashes (input_bfd)[idx]);
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;
free_relocs = NULL;
elf_section_data (section)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
if (sym_hash->movm_args)
bytes += 2;
if (sym_hash->stack_size && sym_hash->stack_size <= 128)
bytes += 3;
else if (sym_hash->stack_size
&& sym_hash->stack_size < 256)
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 (free_relocs != NULL)
{
free (free_relocs);
free_relocs = NULL;
}
if (free_contents != NULL)
{
if (! link_info->keep_memory)
free (free_contents);
else
{
elf_section_data (section)->this_hdr.contents = contents;
}
free_contents = NULL;
}
}
if (shndx_buf != NULL)
{
shndx_hdr->contents = NULL;
free (shndx_buf);
shndx_buf = NULL;
}
if (free_extsyms != NULL)
{
if (! link_info->keep_memory)
{
symtab_hdr->contents = NULL;
free (free_extsyms);
}
free_extsyms = NULL;
}
}
}
contents = NULL;
extsyms = NULL;
internal_relocs = NULL;
free_relocs = NULL;
free_contents = NULL;
free_extsyms = NULL;
if (link_info->relocateable
|| (sec->flags & SEC_RELOC) == 0
|| sec->reloc_count == 0
|| (sec->flags & SEC_CODE) == 0)
return true;
if (sec->_cooked_size == 0)
sec->_cooked_size = sec->_raw_size;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
internal_relocs = (_bfd_elf32_link_read_relocs
(abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
if (! link_info->keep_memory)
free_relocs = internal_relocs;
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
{
contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
if (contents == NULL)
goto error_return;
free_contents = contents;
if (! bfd_get_section_contents (abfd, sec, contents,
(file_ptr) 0, sec->_raw_size))
goto error_return;
}
}
if (extsyms == NULL)
{
if (symtab_hdr->contents != NULL)
extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
else
{
bfd_size_type amt;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf32_External_Sym);
extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
if (extsyms == NULL)
goto error_return;
free_extsyms = extsyms;
if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) extsyms, amt, abfd) != amt)
goto error_return;
symtab_hdr->contents = (bfd_byte *) extsyms;
}
if (shndx_hdr->sh_size != 0)
{
bfd_size_type amt;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf_External_Sym_Shndx);
shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
if (shndx_buf == NULL)
goto error_return;
if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
goto error_return;
shndx_hdr->contents = (bfd_byte *) shndx_buf;
}
}
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
Elf32_External_Sym *esym;
Elf_External_Sym_Shndx *shndx;
Elf_Internal_Sym isym;
asection *sym_sec = NULL;
const char *sym_name;
char *new_name;
esym = extsyms + ELF32_R_SYM (irel->r_info);
shndx = shndx_buf + (shndx_buf ? ELF32_R_SYM (irel->r_info) : 0);
bfd_elf32_swap_symbol_in (abfd, esym, shndx, &isym);
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);
symval = (isym.st_value
+ sym_sec->output_section->vma
+ sym_sec->output_offset);
sym_name = bfd_elf_string_from_elf_section (abfd,
symtab_hdr->sh_link,
isym.st_name);
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, (int) sym_sec);
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)
{
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 == 0xdd)
{
elf_section_data (sec)->relocs = internal_relocs;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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->_cooked_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, irel->r_offset + 1))
continue;
elf_section_data (sec)->relocs = internal_relocs;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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)
{
bfd_vma value = symval;
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
&& ((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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
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;
free_relocs = NULL;
elf_section_data (sec)->this_hdr.contents = contents;
free_contents = NULL;
free_extsyms = NULL;
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),
R_MN10300_16);
if (!mn10300_elf_relax_delete_bytes (abfd, sec,
irel->r_offset + 2, 2))
goto error_return;
*again = true;
break;
}
}
}
}
if (free_relocs != NULL)
free (free_relocs);
if (free_contents != NULL)
{
if (! link_info->keep_memory)
free (free_contents);
else
{
elf_section_data (sec)->this_hdr.contents = contents;
}
}
if (shndx_buf != NULL)
{
shndx_hdr->contents = NULL;
free (shndx_buf);
}
if (free_extsyms != NULL)
{
if (! link_info->keep_memory)
{
symtab_hdr->contents = NULL;
free (free_extsyms);
}
}
return true;
error_return:
if (free_relocs != NULL)
free (free_relocs);
if (free_contents != NULL)
free (free_contents);
if (shndx_buf != NULL)
{
shndx_hdr->contents = NULL;
free (shndx_buf);
}
if (free_extsyms != NULL)
{
symtab_hdr->contents = NULL;
free (free_extsyms);
}
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)
{
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 boolean
mn10300_elf_relax_delete_bytes (abfd, sec, addr, count)
bfd *abfd;
asection *sec;
bfd_vma addr;
int count;
{
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *shndx_hdr;
Elf32_External_Sym *extsyms;
unsigned int sec_shndx;
bfd_byte *contents;
Elf_Internal_Rela *irel, *irelend;
Elf_Internal_Rela *irelalign;
bfd_vma toaddr;
Elf32_External_Sym *esym, *esymend;
Elf_External_Sym_Shndx *shndx;
struct elf_link_hash_entry **sym_hashes;
struct elf_link_hash_entry **end_hashes;
unsigned int symcount;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
contents = elf_section_data (sec)->this_hdr.contents;
irelalign = NULL;
toaddr = sec->_cooked_size;
irel = elf_section_data (sec)->relocs;
irelend = irel + sec->reloc_count;
memmove (contents + addr, contents + addr + count,
(size_t) (toaddr - addr - count));
sec->_cooked_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;
}
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents;
esym = extsyms;
esymend = esym + symtab_hdr->sh_info;
for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL))
{
Elf_Internal_Sym isym;
Elf_External_Sym_Shndx dummy;
bfd_elf32_swap_symbol_in (abfd, esym, shndx, &isym);
if (isym.st_shndx == sec_shndx
&& isym.st_value > addr
&& isym.st_value < toaddr)
{
isym.st_value -= count;
bfd_elf32_swap_symbol_out (abfd, &isym, (PTR) esym, (PTR) &dummy);
}
}
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 boolean
mn10300_elf_symbol_address_p (abfd, sec, addr)
bfd *abfd;
asection *sec;
bfd_vma addr;
{
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *shndx_hdr;
unsigned int sec_shndx;
Elf32_External_Sym *esym, *esymend;
Elf_External_Sym_Shndx *shndx;
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;
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents;
esym = (Elf32_External_Sym *) symtab_hdr->contents;
esymend = esym + symtab_hdr->sh_info;
for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL))
{
Elf_Internal_Sym isym;
bfd_elf32_swap_symbol_in (abfd, esym, shndx, &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, relocateable, symbols)
bfd *output_bfd;
struct bfd_link_info *link_info;
struct bfd_link_order *link_order;
bfd_byte *data;
boolean relocateable;
asymbol **symbols;
{
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *shndx_hdr;
asection *input_section = link_order->u.indirect.section;
bfd *input_bfd = input_section->owner;
asection **sections = NULL;
Elf_Internal_Rela *internal_relocs = NULL;
Elf32_External_Sym *external_syms = NULL;
Elf_External_Sym_Shndx *shndx_buf = NULL;
Elf_External_Sym_Shndx *shndx;
Elf_Internal_Sym *internal_syms = NULL;
if (relocateable
|| elf_section_data (input_section)->this_hdr.contents == NULL)
return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
link_order, data,
relocateable,
symbols);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
memcpy (data, elf_section_data (input_section)->this_hdr.contents,
(size_t) input_section->_raw_size);
if ((input_section->flags & SEC_RELOC) != 0
&& input_section->reloc_count > 0)
{
Elf_Internal_Sym *isymp;
asection **secpp;
Elf32_External_Sym *esym, *esymend;
bfd_size_type amt;
if (symtab_hdr->contents != NULL)
external_syms = (Elf32_External_Sym *) symtab_hdr->contents;
else if (symtab_hdr->sh_info != 0)
{
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf32_External_Sym);
external_syms = (Elf32_External_Sym *) bfd_malloc (amt);
if (external_syms == NULL)
goto error_return;
if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) external_syms, amt, input_bfd) != amt)
goto error_return;
}
if (symtab_hdr->sh_info != 0 && shndx_hdr->sh_size != 0)
{
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf_External_Sym_Shndx);
shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
if (shndx_buf == NULL)
goto error_return;
if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) shndx_buf, amt, input_bfd) != amt)
goto error_return;
}
internal_relocs = (_bfd_elf32_link_read_relocs
(input_bfd, input_section, (PTR) NULL,
(Elf_Internal_Rela *) NULL, false));
if (internal_relocs == NULL)
goto error_return;
amt = symtab_hdr->sh_info;
amt *= sizeof (Elf_Internal_Sym);
internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
if (internal_syms == NULL && amt != 0)
goto error_return;
amt = symtab_hdr->sh_info;
amt *= sizeof (asection *);
sections = (asection **) bfd_malloc (amt);
if (sections == NULL && amt != 0)
goto error_return;
for (isymp = internal_syms, secpp = sections, shndx = shndx_buf,
esym = external_syms, esymend = esym + symtab_hdr->sh_info;
esym < esymend;
++esym, ++isymp, ++secpp, shndx = (shndx ? shndx + 1 : NULL))
{
asection *isec;
bfd_elf32_swap_symbol_in (input_bfd, esym, shndx, isymp);
if (isymp->st_shndx == SHN_UNDEF)
isec = bfd_und_section_ptr;
else if (isymp->st_shndx == SHN_ABS)
isec = bfd_abs_section_ptr;
else if (isymp->st_shndx == SHN_COMMON)
isec = bfd_com_section_ptr;
else
isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
*secpp = isec;
}
if (! mn10300_elf_relocate_section (output_bfd, link_info, input_bfd,
input_section, data, internal_relocs,
internal_syms, sections))
goto error_return;
if (sections != NULL)
free (sections);
if (internal_syms != NULL)
free (internal_syms);
if (shndx_buf != NULL)
free (shndx_buf);
if (external_syms != NULL && symtab_hdr->contents == NULL)
free (external_syms);
if (internal_relocs != elf_section_data (input_section)->relocs)
free (internal_relocs);
}
return data;
error_return:
if (internal_relocs != NULL
&& internal_relocs != elf_section_data (input_section)->relocs)
free (internal_relocs);
if (shndx_buf != NULL)
free (shndx_buf);
if (external_syms != NULL && symtab_hdr->contents == NULL)
free (external_syms);
if (internal_syms != NULL)
free (internal_syms);
if (sections != NULL)
free (sections);
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_stack_size = 0;
ret->flags = 0;
ret->movm_args = 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;
}
}
void
_bfd_mn10300_elf_final_write_processing (abfd, linker)
bfd *abfd;
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;
}
elf_elfheader (abfd)->e_flags &= ~ (EF_MN10300_MACH);
elf_elfheader (abfd)->e_flags |= val;
}
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;
}
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 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
#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_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
#define elf_symbol_leading_char '_'
#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
#include "elf32-target.h"