diff options
Diffstat (limited to 'bfd/elf32-z80.c')
-rw-r--r-- | bfd/elf32-z80.c | 350 |
1 files changed, 301 insertions, 49 deletions
diff --git a/bfd/elf32-z80.c b/bfd/elf32-z80.c index 888606e..89089f5 100644 --- a/bfd/elf32-z80.c +++ b/bfd/elf32-z80.c @@ -30,12 +30,6 @@ /* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */ #define OCTETS_PER_BYTE(ABFD, SEC) 1 -/* Relocation functions. */ -static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static bfd_boolean z80_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); - typedef struct { bfd_reloc_code_real_type r_type; reloc_howto_type howto; @@ -44,6 +38,11 @@ typedef struct { #define BFD_EMPTY_HOWTO(rt,x) {rt, EMPTY_HOWTO(x)} #define BFD_HOWTO(rt,a,b,c,d,e,f,g,h,i,j,k,l,m) {rt, HOWTO(a,b,c,d,e,f,g,h,i,j,k,l,m)} +static bfd_reloc_status_type +z80_elf_16_be_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, + char **error_message); + static const bfd_howto_type elf_z80_howto_table[] = { @@ -253,11 +252,27 @@ bfd_howto_type elf_z80_howto_table[] = 0, /* src_mask */ 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + /* An 16 bit big endian absolute relocation */ + BFD_HOWTO (BFD_RELOC_Z80_16_BE, + R_Z80_16_BE, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + z80_elf_16_be_reloc, /* special_function */ + "r_imm16be", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ }; static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) +z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) { enum { @@ -268,16 +283,16 @@ bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, for (i = 0; i < table_size; i++) { if (elf_z80_howto_table[i].r_type == code) - return &elf_z80_howto_table[i].howto; + return &elf_z80_howto_table[i].howto; } - printf ("%s:%d Not found type %d\n", __FILE__, __LINE__, code); + printf ("%s:%d Not found BFD reloc type %d\n", __FILE__, __LINE__, code); return NULL; } static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) +z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) { enum { @@ -288,82 +303,308 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) for (i = 0; i < table_size; i++) { if (elf_z80_howto_table[i].howto.name != NULL - && strcasecmp (elf_z80_howto_table[i].howto.name, r_name) == 0) - return &elf_z80_howto_table[i].howto; + && strcasecmp (elf_z80_howto_table[i].howto.name, r_name) == 0) + return &elf_z80_howto_table[i].howto; } + printf ("%s:%d Not found ELF reloc name `%s'\n", __FILE__, __LINE__, r_name); + return NULL; } -/* Set the howto pointer for an z80 ELF reloc. */ - -static bfd_boolean -z80_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) +static reloc_howto_type * +z80_rtype_to_howto (bfd *abfd, unsigned r_type) { enum { table_size = sizeof (elf_z80_howto_table) / sizeof (elf_z80_howto_table[0]) }; - unsigned int i; - unsigned int r_type = ELF32_R_TYPE (dst->r_info); + unsigned int i; for (i = 0; i < table_size; i++) { if (elf_z80_howto_table[i].howto.type == r_type) - { - cache_ptr->howto = &elf_z80_howto_table[i].howto; - return TRUE; - } + return &elf_z80_howto_table[i].howto; } /* xgettext:c-format */ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), - abfd, r_type); + abfd, r_type); + return NULL; +} + +/* Set the howto pointer for an z80 ELF reloc. */ + +static bfd_boolean +z80_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) +{ + unsigned int r_type = ELF32_R_TYPE (dst->r_info); + reloc_howto_type *howto = z80_rtype_to_howto (abfd, r_type); + if (howto != NULL) + { + cache_ptr->howto = howto; + return TRUE; + } bfd_set_error (bfd_error_bad_value); return FALSE; } +static bfd_reloc_status_type +z80_elf_final_link_relocate (unsigned long r_type, + bfd *input_bfd, + bfd *output_bfd ATTRIBUTE_UNUSED, + asection *input_section ATTRIBUTE_UNUSED, + 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) +{ + bfd_boolean r; + reloc_howto_type *howto; + + switch (r_type) + { + case R_Z80_16_BE: + value += addend; + bfd_put_8 (input_bfd, value >> 8, contents + offset + 0); + bfd_put_8 (input_bfd, value >> 0, contents + offset + 1); + return bfd_reloc_ok; + } + + howto = z80_rtype_to_howto (input_bfd, r_type); + if (howto == NULL) + return bfd_reloc_notsupported; + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + offset, value, addend); + return r ? bfd_reloc_ok : bfd_reloc_notsupported; +} + +static bfd_boolean +z80_elf_relocate_section (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; + + 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++) + { + unsigned int r_type; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma relocation; + + /* This is a final link. */ + r_symndx = ELF32_R_SYM (rel->r_info); + r_type = ELF32_R_TYPE (rel->r_info); + 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, warned, ignored; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned, ignored); + } + + if (sec != NULL && discarded_section (sec)) + { + /* For relocs against symbols from removed linkonce sections, + or sections discarded by a linker script, we just want the + section contents cleared. Avoid any special processing. */ + reloc_howto_type *howto; + howto = z80_rtype_to_howto (input_bfd, r_type); + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + } + + if (bfd_link_relocatable (info)) + continue; + + + z80_elf_final_link_relocate (r_type, input_bfd, output_bfd, + input_section, + contents, rel->r_offset, + relocation, rel->r_addend, + info, sec, h == NULL); + } + + return TRUE; +} + +/* The final processing done just before writing out a Z80 ELF object + file. This gets the Z80 architecture right based on the machine + number. */ + static bfd_boolean -z80_elf_set_mach_from_flags (bfd *abfd) +z80_elf_final_write_processing (bfd *abfd) { - int mach; - switch (elf_elfheader (abfd)->e_flags) + unsigned long val = bfd_get_mach (abfd); + + switch (val) { - case EF_Z80_MACH_GBZ80: - mach = bfd_mach_gbz80; + default: + _bfd_error_handler (_("%pB: unsupported bfd mach %#lx"), + abfd, val); + /* fall through */ + case bfd_mach_z80: + case bfd_mach_z80full: + case bfd_mach_z80strict: + val = EF_Z80_MACH_Z80; break; - case EF_Z80_MACH_Z80: - mach = bfd_mach_z80; + case bfd_mach_gbz80: + val = EF_Z80_MACH_GBZ80; break; - case EF_Z80_MACH_Z180: - mach = bfd_mach_z180; + case bfd_mach_z80n: + val = EF_Z80_MACH_Z80N; break; - case EF_Z80_MACH_EZ80_Z80: - mach = bfd_mach_ez80_z80; + case bfd_mach_z180: + val = EF_Z80_MACH_Z180; break; - case EF_Z80_MACH_EZ80_ADL: - mach = bfd_mach_ez80_adl; + case bfd_mach_ez80_z80: + val = EF_Z80_MACH_EZ80_Z80; break; - case EF_Z80_MACH_R800: - mach = bfd_mach_r800; + case bfd_mach_ez80_adl: + val = EF_Z80_MACH_EZ80_ADL; break; - default: - mach = bfd_mach_z80; + case bfd_mach_r800: + val = EF_Z80_MACH_R800; break; } + elf_elfheader (abfd)->e_machine = EM_Z80; + elf_elfheader (abfd)->e_flags &= ~EF_Z80_MACH_MSK; + elf_elfheader (abfd)->e_flags |= val; + return _bfd_elf_final_write_processing (abfd); +} - bfd_default_set_arch_mach (abfd, bfd_arch_z80, mach); - return TRUE; +/* Set the right machine number. */ +static bfd_boolean +z80_elf_object_p (bfd *abfd) +{ + unsigned int mach; + + if (elf_elfheader (abfd)->e_machine == EM_Z80) + { + int e_mach = elf_elfheader (abfd)->e_flags & EF_Z80_MACH_MSK; + switch (e_mach) + { + default: + _bfd_error_handler (_("%pB: unsupported mach %#x"), + abfd, e_mach); + /* fall through */ + case EF_Z80_MACH_Z80: + mach = bfd_mach_z80; + break; + case EF_Z80_MACH_GBZ80: + mach = bfd_mach_gbz80; + break; + case EF_Z80_MACH_Z180: + mach = bfd_mach_z180; + break; + case EF_Z80_MACH_EZ80_Z80: + mach = bfd_mach_ez80_z80; + break; + case EF_Z80_MACH_EZ80_ADL: + mach = bfd_mach_ez80_adl; + break; + case EF_Z80_MACH_R800: + mach = bfd_mach_r800; + break; + case EF_Z80_MACH_Z80N: + mach = bfd_mach_z80n; + break; + } + } + else + { + _bfd_error_handler (_("%pB: unsupported arch %#x"), + abfd, elf_elfheader (abfd)->e_machine); + mach = bfd_mach_z80; + } + return bfd_default_set_arch_mach (abfd, bfd_arch_z80, mach); } static int -z80_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, - const char * name) +z80_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, + const char * name) { return (name[0] == '.' && name[1] == 'L') || - _bfd_elf_is_local_label_name (abfd, name); + _bfd_elf_is_local_label_name (abfd, name); } +static bfd_reloc_status_type +z80_elf_16_be_reloc (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message) +{ + bfd_vma val; + long x; + bfd_size_type octets = (reloc_entry->address + * OCTETS_PER_BYTE (abfd, input_section)); + + /* If this is a relocatable link (output_bfd test tells us), just + call the generic function. Any adjustment will be done at final + link time. */ + if (output_bfd != NULL) + return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); + + /* Get symbol value. */ + val = 0; + if (!bfd_is_com_section (symbol->section)) + val = symbol->value; + val += symbol->section->output_offset + input_section->output_offset; + if (symbol->section->output_section) + val += symbol->section->output_section->vma; + + val += reloc_entry->addend; + if (reloc_entry->howto->partial_inplace) + { + x = bfd_get_8 (abfd, (bfd_byte *) data + octets + 0) * 0x100; + x += bfd_get_8 (abfd, (bfd_byte *) data + octets + 1); + x &= ~reloc_entry->howto->src_mask; + } + else + x = 0; + + x |= val & reloc_entry->howto->dst_mask; + if (x < -0x8000 || x >= 0x10000) + return bfd_reloc_outofrange; + + bfd_put_8 (abfd, x >> 8, (bfd_byte *) data + octets + 0); + bfd_put_8 (abfd, x >> 0, (bfd_byte *) data + octets + 1); + return bfd_reloc_ok; +} #define ELF_ARCH bfd_arch_z80 #define ELF_MACHINE_CODE EM_Z80 @@ -372,9 +613,20 @@ z80_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, #define TARGET_LITTLE_SYM z80_elf32_vec #define TARGET_LITTLE_NAME "elf32-z80" -#define elf_info_to_howto NULL -#define elf_info_to_howto_rel z80_info_to_howto_rel -#define elf_backend_object_p z80_elf_set_mach_from_flags +#define elf_backend_can_refcount 1 +#define elf_backend_can_gc_sections 1 +#define elf_backend_stack_align 1 +#define elf_backend_rela_normal 1 + +#define elf_info_to_howto z80_info_to_howto_rela +#define elf_info_to_howto_rel z80_info_to_howto_rela + +#define elf_backend_final_write_processing z80_elf_final_write_processing +#define elf_backend_object_p z80_elf_object_p +#define elf_backend_relocate_section z80_elf_relocate_section + +#define bfd_elf32_bfd_reloc_type_lookup z80_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup z80_reloc_name_lookup #define bfd_elf32_bfd_is_local_label_name z80_is_local_label_name #include "elf32-target.h" |