* elf32-m68hc1x.c: New file (from elf32-m68hc11.c and elf32-m68hc12.c)

(m68hc11_elf_hash_table_create): New function.
	(elf32_m68hc11_link_hash_table_free): New function.
	(stub_hash_newfunc): New function.
	(m68hc11_add_stub): New function.
	(elf32_m68hc11_add_symbol_hook): New function.
	(elf32_m68hc11_setup_section_lists): New function.
	(elf32_m68hc11_next_input_section): New function.
	(elf32_m68hc11_size_stubs): New function.
	(elf32_m68hc11_build_stubs): New function.
	(m68hc11_get_relocation_value): New function.
	(elf32_m68hc11_relocate_section): Call the above to redirect
	some relocations to the trampoline code.
	(m68hc11_elf_export_one_stub): New function.
	(m68hc11_elf_set_symbol): New function.
	(elf32_m68hc11_build_stubs): Call it via bfd_hash_traverse.
	(m68hc11_elf_get_bank_parameters): Get parameters only when the info
	is not yet initialized.

	* elf32-m68hc1x.h: New file (from elf32-m68hc11.c and elf32-m68hc12.c)
	(elf32_m68hc11_stub_hash_entry): New struct.
	(m68hc11_page_info): Add trampoline handler address.
	(m68hc11_elf_link_hash_table): Add stubs generation members.
	(elf32_m68hc11_add_symbol_hook): Declare.
	(elf32_m68hc11_setup_section_lists): Declare.
	(elf32_m68hc11_size_stubs): Declare.
	(elf32_m68hc11_build_stubs): Declare.

	* elf32-m68hc11.c (m68hc11_elf_ignore_reloc): Move to elf32-m68hc1x.c.
	(elf32_m68hc11_gc_mark_hook, elf32_m68hc11_gc_sweep_hook): Likewise.
	(elf32_m68hc11_check_relocs, elf32_m68hc11_relocate_section): Ditto.
	(_bfd_m68hc11_elf_set_private_flags): Ditto.
	(_bfd_m68hc11_elf_merge_private_bfd_data): Ditto.
	(_bfd_m68hc11_elf_print_private_bfd_data): Ditto.
	(bfd_elf32_bfd_link_hash_table_create): Define.
	(elf_backend_add_symbol_hook): Define.
	(m68hc11_elf_bfd_link_hash_table_create): New function.
	(m68hc11_elf_build_one_stub): New function.
	(m68hc11_elf_size_one_stub): New function.
	(m68hc11_elf_bfd_link_hash_table_create): Install the above.
	(bfd_elf32_bfd_link_hash_table_create): Define.

	* elf32-m68hc12.c (m68hc11_elf_ignore_reloc): Remove.
	(m68hc12_addr_is_banked): Remove, use m68hc11_addr_is_banked.
	(m68hc12_phys_addr): Ditto.
	(m68hc12_phys_page): Ditto.
	(m68hc12_elf_special_reloc): Move to elf32-m68hc1x.c.
	(elf32_m68hc11_gc_mark_hook): Likewise.
	(elf32_m68hc11_gc_sweep_hook): Likewise.
	(elf32_m68hc11_check_relocs): Likewise.
	(elf32_m68hc11_relocate_section): Likewise.
	(_bfd_m68hc12_elf_set_private_flags): Likewise.
	(_bfd_m68hc12_elf_merge_private_bfd_data): Likewise.
	(_bfd_m68hc12_elf_print_private_bfd_data): Likewise.
	(m68hc12_elf_build_one_stub): New function.
	(m68hc12_elf_size_one_stub): New function.
	(m68hc12_elf_bfd_link_hash_table_create): New function, use the above.
	(elf_backend_add_symbol_hook): Define.
	(elf_m68hc11_howto_table): Use TRUE for pcrel relocs; fix masks.
This commit is contained in:
Stephane Carrez
2003-04-21 13:22:14 +00:00
parent 81eca1a78a
commit 3a65329d1f
5 changed files with 2003 additions and 808 deletions

View File

@ -24,29 +24,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf32-m68hc1x.h"
#include "elf/m68hc11.h"
#include "opcode/m68hc11.h"
/* Relocation functions. */
static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void m68hc11_info_to_howto_rel
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
static bfd_reloc_status_type m68hc11_elf_ignore_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
/* Trampoline generation. */
static bfd_boolean m68hc11_elf_size_one_stub
PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
static bfd_boolean m68hc11_elf_build_one_stub
PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
static struct bfd_link_hash_table* m68hc11_elf_bfd_link_hash_table_create
PARAMS ((bfd* abfd));
/* GC mark and sweep. */
static asection *elf32_m68hc11_gc_mark_hook
PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
static bfd_boolean elf32_m68hc11_gc_sweep_hook
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static bfd_boolean elf32_m68hc11_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static bfd_boolean elf32_m68hc11_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
/* Linker relaxation. */
static bfd_boolean m68hc11_elf_relax_section
PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
static void m68hc11_elf_relax_delete_bytes
@ -56,18 +52,14 @@ static void m68hc11_relax_group
unsigned long, unsigned long));
static int compare_reloc PARAMS ((const void *, const void *));
bfd_boolean _bfd_m68hc11_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
bfd_boolean _bfd_m68hc11_elf_set_private_flags PARAMS ((bfd *, flagword));
bfd_boolean _bfd_m68hc11_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
/* Use REL instead of RELA to save space */
#define USE_REL 1
/* The Motorola 68HC11 microcontroler only addresses 64Kb.
/* The Motorola 68HC11 microcontroller only addresses 64Kb but we also
support a memory bank switching mechanism similar to 68HC12.
We must handle 8 and 16-bit relocations. The 32-bit relocation
is defined but not used except by gas when -gstabs is used (which
is wrong).
are used for debugging sections (DWARF2) to represent a virtual
address.
The 3-bit and 16-bit PC rel relocation is only used by 68HC12. */
static reloc_howto_type elf_m68hc11_howto_table[] = {
/* This reloc does nothing. */
@ -367,25 +359,6 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
return NULL;
}
/* This function is used for relocs which are only used for relaxing,
which the linker should otherwise ignore. */
static bfd_reloc_status_type
m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
output_bfd, error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
if (output_bfd != NULL)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
/* Set the howto pointer for an M68HC11 ELF reloc. */
static void
@ -401,50 +374,106 @@ m68hc11_info_to_howto_rel (abfd, cache_ptr, dst)
cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
}
static asection *
elf32_m68hc11_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;
/* Far trampoline generation. */
/* Build a 68HC11 trampoline stub. */
static bfd_boolean
m68hc11_elf_build_one_stub (gen_entry, in_arg)
struct bfd_hash_entry *gen_entry;
PTR in_arg;
{
if (h != NULL)
{
switch (ELF32_R_TYPE (rel->r_info))
{
default:
switch (h->root.type)
{
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
return h->root.u.def.section;
struct elf32_m68hc11_stub_hash_entry *stub_entry;
struct bfd_link_info *info;
struct m68hc11_elf_link_hash_table *htab;
asection *stub_sec;
bfd *stub_bfd;
bfd_byte *loc;
bfd_vma sym_value, phys_page, phys_addr;
case bfd_link_hash_common:
return h->root.u.c.p->section;
/* Massage our args to the form they really have. */
stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
info = (struct bfd_link_info *) in_arg;
default:
break;
}
}
}
else
return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
htab = m68hc11_elf_hash_table (info);
return NULL;
stub_sec = stub_entry->stub_sec;
/* Make a note of the offset within the stubs for this entry. */
stub_entry->stub_offset = stub_sec->_raw_size;
stub_sec->_raw_size += 10;
loc = stub_sec->contents + stub_entry->stub_offset;
stub_bfd = stub_sec->owner;
/* Create the trampoline call stub:
pshb
ldab #%page(symbol)
ldy #%addr(symbol)
jmp __trampoline
*/
sym_value = (stub_entry->target_value
+ stub_entry->target_section->output_offset
+ stub_entry->target_section->output_section->vma);
phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
/* pshb; ldab #%page(sym) */
bfd_put_8 (stub_bfd, 0x37, loc);
bfd_put_8 (stub_bfd, 0xC6, loc + 1);
bfd_put_8 (stub_bfd, phys_page, loc + 2);
loc += 3;
/* ldy #%addr(sym) */
bfd_put_8 (stub_bfd, 0x18, loc);
bfd_put_8 (stub_bfd, 0xCE, loc + 1);
bfd_put_16 (stub_bfd, phys_addr, loc + 2);
loc += 4;
/* jmp __trampoline */
bfd_put_8 (stub_bfd, 0x7E, loc);
bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
return TRUE;
}
/* As above, but don't actually build the stub. Just bump offset so
we know stub section sizes. */
static bfd_boolean
elf32_m68hc11_gc_sweep_hook (abfd, info, sec, relocs)
bfd *abfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info ATTRIBUTE_UNUSED;
asection *sec ATTRIBUTE_UNUSED;
const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
m68hc11_elf_size_one_stub (gen_entry, in_arg)
struct bfd_hash_entry *gen_entry;
PTR in_arg ATTRIBUTE_UNUSED;
{
/* We don't use got and plt entries for 68hc11/68hc12. */
struct elf32_m68hc11_stub_hash_entry *stub_entry;
/* Massage our args to the form they really have. */
stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
stub_entry->stub_sec->_raw_size += 10;
return TRUE;
}
/* Create a 68HC11 ELF linker hash table. */
static struct bfd_link_hash_table *
m68hc11_elf_bfd_link_hash_table_create (abfd)
bfd *abfd;
{
struct m68hc11_elf_link_hash_table *ret;
ret = m68hc11_elf_hash_table_create (abfd);
if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
return NULL;
ret->size_one_stub = m68hc11_elf_size_one_stub;
ret->build_one_stub = m68hc11_elf_build_one_stub;
return &ret->root.root;
}
/* 68HC11 Linker Relaxation. */
@ -1251,365 +1280,7 @@ m68hc11_elf_relax_delete_bytes (abfd, sec, addr, count)
}
}
/* Look through the relocs for a section during the first phase.
Since we don't do .gots or .plts, we just need to consider the
virtual table relocs for gc. */
static bfd_boolean
elf32_m68hc11_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;
struct elf_link_hash_entry ** 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))
{
/* This relocation describes the C++ object vtable hierarchy.
Reconstruct it for later use during GC. */
case R_M68HC11_GNU_VTINHERIT:
if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return FALSE;
break;
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_M68HC11_GNU_VTENTRY:
if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
}
}
return TRUE;
}
/* Relocate a 68hc11/68hc12 ELF section. */
static bfd_boolean
elf32_m68hc11_relocate_section (output_bfd, info, input_bfd, input_section,
contents, relocs, local_syms, local_sections)
bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
Elf_Internal_Rela *relocs;
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel, *relend;
const char *name;
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 elf_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);
if (r_type == R_M68HC11_GNU_VTENTRY
|| r_type == R_M68HC11_GNU_VTINHERIT )
continue;
howto = elf_m68hc11_howto_table + r_type;
if (info->relocateable)
{
/* This is a relocateable link. We don't have to change
anything, unless the reloc is against a section symbol,
in which case we have to adjust according to where the
section symbol winds up in the output section. */
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;
}
/* This is a final link. */
h = NULL;
sym = NULL;
sec = NULL;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
}
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 (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
sec = h->root.u.def.section;
relocation = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
if (!((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset, TRUE)))
return FALSE;
relocation = 0;
}
}
if (h != NULL)
name = h->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);
}
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, rel->r_addend);
if (r != bfd_reloc_ok)
{
const char * msg = (const char *) 0;
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");
/* fall through */
common_error:
if (!((*info->callbacks->warning)
(info, msg, name, input_bfd, input_section,
rel->r_offset)))
return FALSE;
break;
}
}
}
return TRUE;
}
/* Set and control ELF flags in ELF header. */
bfd_boolean
_bfd_m68hc11_elf_set_private_flags (abfd, flags)
bfd *abfd;
flagword flags;
{
BFD_ASSERT (!elf_flags_init (abfd)
|| elf_elfheader (abfd)->e_flags == flags);
elf_elfheader (abfd)->e_flags = flags;
elf_flags_init (abfd) = TRUE;
return TRUE;
}
/* Merge backend specific data from an object file to the output
object file when linking. */
bfd_boolean
_bfd_m68hc11_elf_merge_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
flagword old_flags;
flagword new_flags;
bfd_boolean ok = TRUE;
/* Check if we have the same endianess */
if (!_bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
new_flags = elf_elfheader (ibfd)->e_flags;
elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI;
old_flags = elf_elfheader (obfd)->e_flags;
if (! elf_flags_init (obfd))
{
elf_flags_init (obfd) = TRUE;
elf_elfheader (obfd)->e_flags = new_flags;
elf_elfheader (obfd)->e_ident[EI_CLASS]
= elf_elfheader (ibfd)->e_ident[EI_CLASS];
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
&& bfd_get_arch_info (obfd)->the_default)
{
if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
bfd_get_mach (ibfd)))
return FALSE;
}
return TRUE;
}
/* Check ABI compatibility. */
if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
{
(*_bfd_error_handler)
(_("%s: linking files compiled for 16-bit integers (-mshort) "
"and others for 32-bit integers"),
bfd_archive_filename (ibfd));
ok = FALSE;
}
if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
{
(*_bfd_error_handler)
(_("%s: linking files compiled for 32-bit double (-fshort-double) "
"and others for 64-bit double"),
bfd_archive_filename (ibfd));
ok = FALSE;
}
new_flags &= ~EF_M68HC11_ABI;
old_flags &= ~EF_M68HC11_ABI;
/* Warn about any other mismatches */
if (new_flags != old_flags)
{
(*_bfd_error_handler)
(_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
bfd_archive_filename (ibfd), (unsigned long) new_flags,
(unsigned long) old_flags);
ok = FALSE;
}
if (! ok)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
return TRUE;
}
bfd_boolean
_bfd_m68hc11_elf_print_private_bfd_data (abfd, ptr)
bfd *abfd;
PTR ptr;
{
FILE *file = (FILE *) ptr;
BFD_ASSERT (abfd != NULL && ptr != NULL);
/* Print normal ELF private data. */
_bfd_elf_print_private_bfd_data (abfd, ptr);
/* xgettext:c-format */
fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
fprintf (file, _("[abi=32-bit int,"));
else
fprintf (file, _("[abi=16-bit int,"));
if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
fprintf (file, _(" 64-bit double]"));
else
fprintf (file, _(" 32-bit double]"));
if (elf_elfheader (abfd)->e_flags & E_M68HC12_BANKS)
fprintf (file, _(" [memory=bank-model]"));
else
fprintf (file, _(" [memory=flat]"));
fputc ('\n', file);
return TRUE;
}
/* Below is the only difference between elf32-m68hc12.c and elf32-m68hc11.c.
The Motorola spec says to use a different Elf machine code. */
#define ELF_ARCH bfd_arch_m68hc11
#define ELF_MACHINE_CODE EM_68HC11
#define ELF_MAXPAGESIZE 0x1000
@ -1624,9 +1295,15 @@ _bfd_m68hc11_elf_print_private_bfd_data (abfd, ptr)
#define elf_backend_gc_sweep_hook elf32_m68hc11_gc_sweep_hook
#define elf_backend_check_relocs elf32_m68hc11_check_relocs
#define elf_backend_relocate_section elf32_m68hc11_relocate_section
#define elf_backend_add_symbol_hook elf32_m68hc11_add_symbol_hook
#define elf_backend_object_p 0
#define elf_backend_final_write_processing 0
#define elf_backend_can_gc_sections 1
#define bfd_elf32_bfd_link_hash_table_create \
m68hc11_elf_bfd_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_free \
m68hc11_elf_bfd_link_hash_table_free
#define bfd_elf32_bfd_merge_private_bfd_data \
_bfd_m68hc11_elf_merge_private_bfd_data
#define bfd_elf32_bfd_set_private_flags _bfd_m68hc11_elf_set_private_flags