summaryrefslogtreecommitdiff
path: root/bfd/elf32-z80.c
diff options
context:
space:
mode:
authorSergey Belyashov <sergey.belyashov@gmail.com>2020-02-07 14:53:46 +0000
committerNick Clifton <nickc@redhat.com>2020-02-07 14:53:46 +0000
commit9fc0b501af78bc4a92f53ec712e1aaa123e0224c (patch)
treef3ef7a39227828252a1878f1a526b3df19ec7c65 /bfd/elf32-z80.c
parentadb8754e48d53b219ddaa9e8368e4b1acb9db53a (diff)
Add support for the GBZ80 and Z80N variants of the Z80 architecture, and add DWARF debug info support to the Z80 assembler.
PR 25469 bfd * archures.c: Add GBZ80 and Z80N machine values. * reloc.c: Add BFD_RELOC_Z80_16_BE. * coff-z80.c: Add support for new reloc. * coffcode.h: Add support for new machine values. * cpu-z80.c: Add support for new machine names. * elf32-z80.c: Add support for new reloc. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. binutils* readelf.c (get_machine_flags): Add support for Z80N machine number. gas * config/tc-z80.c: Add -gbz80 command line option to generate code for the GameBoy Z80. Add support for generating DWARF. * config/tc-z80.h: Add support for DWARF debug information generation. * doc/c-z80.texi: Document new command line option. * testsuite/gas/z80/gbz80_all.d: New file. * testsuite/gas/z80/gbz80_all.s: New file. * testsuite/gas/z80/z80.exp: Run the new tests. * testsuite/gas/z80/z80n_all.d: New file. * testsuite/gas/z80/z80n_all.s: New file. * testsuite/gas/z80/z80n_reloc.d: New file. include * coff/internal.h (R_IMM16BE): Define. * elf/z80.h (EF_Z80_MACH_Z80N): Define. (R_Z80_16_BE): New reloc. ld * emulparams/elf32z80.sh: Use z80 emulation. * emultempl/z80.em: Make generic to both COFF and ELF Z80 emulations. * emultempl/z80elf.em: Delete. * testsuite/ld-elf/pr22450.d: Expect to fail for the Z80. * testsuite/ld-elf/sec64k.exp: Fix Z80 assembly. * testsuite/ld-unique/pr21529.s: Avoid register name conflict. * testsuite/ld-unique/unique.s: Likewise. * testsuite/ld-unique/unique_empty.s: Likewise. * testsuite/ld-unique/unique_shared.s: Likewise. * testsuite/ld-unique/unique.d: Updated expected output. * testsuite/ld-z80/arch_z80n.d: New file. * testsuite/ld-z80/comb_arch_z80_z80n.d: New file. * testsuite/ld-z80/labels.s: Add more labels. * testsuite/ld-z80/relocs.s: Add more reloc tests. * testsuite/ld-z80/relocs_f_z80n.d: New file opcodes * z80-dis.c: Add support for GBZ80 opcodes.
Diffstat (limited to 'bfd/elf32-z80.c')
-rw-r--r--bfd/elf32-z80.c350
1 files changed, 301 insertions, 49 deletions
diff --git a/bfd/elf32-z80.c b/bfd/elf32-z80.c
index 888606e7b5..89089f5eaa 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"