#include "bfd.h"
#include "bfdlink.h"
#include "sysdep.h"
#include "libbfd.h"
#ifdef _CONST
#undef _CONST
#endif
#include "coff/tic80.h"
#include "coff/internal.h"
#include "libcoff.h"
#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
#define COFF_ALIGN_IN_SECTION_HEADER 1
#define COFF_ALIGN_IN_SFLAGS 1
#define GET_SCNHDR_FLAGS H_GET_16
#define PUT_SCNHDR_FLAGS H_PUT_16
static void rtype2howto
PARAMS ((arelent *cache_ptr, struct internal_reloc *dst));
static bfd_reloc_status_type ppbase_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type glob15_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type glob16_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type local16_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_boolean coff_tic80_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
struct internal_reloc *, struct internal_syment *, asection **));
static reloc_howto_type * coff_tic80_rtype_to_howto
PARAMS ((bfd *, asection *, struct internal_reloc *,
struct coff_link_hash_entry *, struct internal_syment *,
bfd_vma *));
static reloc_howto_type tic80_howto_table[] =
{
HOWTO (R_RELLONG,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
NULL,
"RELLONG",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MPPCR,
2,
2,
32,
TRUE,
0,
complain_overflow_signed,
NULL,
"MPPCR",
TRUE,
0xffffffff,
0xffffffff,
TRUE),
HOWTO (R_ABS,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
NULL,
"ABS",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_PPBASE,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
ppbase_reloc,
"PPBASE",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_PPLBASE,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
ppbase_reloc,
"PPLBASE",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_PP15,
0,
2,
15,
FALSE,
6,
complain_overflow_dont,
glob15_reloc,
"PP15",
TRUE,
0x1ffc0,
0x1ffc0,
FALSE),
HOWTO (R_PP15W,
2,
2,
15,
FALSE,
6,
complain_overflow_dont,
glob15_reloc,
"PP15W",
TRUE,
0x1ffc0,
0x1ffc0,
FALSE),
HOWTO (R_PP15H,
1,
2,
15,
FALSE,
6,
complain_overflow_dont,
glob15_reloc,
"PP15H",
TRUE,
0x1ffc0,
0x1ffc0,
FALSE),
HOWTO (R_PP16B,
0,
2,
16,
FALSE,
6,
complain_overflow_dont,
glob16_reloc,
"PP16B",
TRUE,
0x3ffc0,
0x3ffc0,
FALSE),
HOWTO (R_PPL15,
0,
2,
15,
FALSE,
0,
complain_overflow_dont,
NULL,
"PPL15",
TRUE,
0x7fff,
0x7fff,
FALSE),
HOWTO (R_PPL15W,
2,
2,
15,
FALSE,
0,
complain_overflow_dont,
NULL,
"PPL15W",
TRUE,
0x7fff,
0x7fff,
FALSE),
HOWTO (R_PPL15H,
1,
2,
15,
FALSE,
0,
complain_overflow_dont,
NULL,
"PPL15H",
TRUE,
0x7fff,
0x7fff,
FALSE),
HOWTO (R_PPL16B,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
local16_reloc,
"PPL16B",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (R_PPN15,
0,
-2,
15,
FALSE,
6,
complain_overflow_dont,
glob15_reloc,
"PPN15",
TRUE,
0x1ffc0,
0x1ffc0,
FALSE),
HOWTO (R_PPN15W,
2,
-2,
15,
FALSE,
6,
complain_overflow_dont,
glob15_reloc,
"PPN15W",
TRUE,
0x1ffc0,
0x1ffc0,
FALSE),
HOWTO (R_PPN15H,
1,
-2,
15,
FALSE,
6,
complain_overflow_dont,
glob15_reloc,
"PPN15H",
TRUE,
0x1ffc0,
0x1ffc0,
FALSE),
HOWTO (R_PPN16B,
0,
-2,
16,
FALSE,
6,
complain_overflow_dont,
glob16_reloc,
"PPN16B",
TRUE,
0x3ffc0,
0x3ffc0,
FALSE),
HOWTO (R_PPLN15,
0,
-2,
15,
FALSE,
0,
complain_overflow_dont,
NULL,
"PPLN15",
TRUE,
0x7fff,
0x7fff,
FALSE),
HOWTO (R_PPLN15W,
2,
-2,
15,
FALSE,
0,
complain_overflow_dont,
NULL,
"PPLN15W",
TRUE,
0x7fff,
0x7fff,
FALSE),
HOWTO (R_PPLN15H,
1,
-2,
15,
FALSE,
0,
complain_overflow_dont,
NULL,
"PPLN15H",
TRUE,
0x7fff,
0x7fff,
FALSE),
HOWTO (R_PPLN16B,
0,
-2,
15,
FALSE,
0,
complain_overflow_dont,
local16_reloc,
"PPLN16B",
TRUE,
0xffff,
0xffff,
FALSE)
};
static bfd_reloc_status_type
ppbase_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol_in ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd ATTRIBUTE_UNUSED;
char **error_message ATTRIBUTE_UNUSED;
{
abort ();
}
static bfd_reloc_status_type
glob15_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol_in ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd ATTRIBUTE_UNUSED;
char **error_message ATTRIBUTE_UNUSED;
{
abort ();
}
static bfd_reloc_status_type
glob16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol_in ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd ATTRIBUTE_UNUSED;
char **error_message ATTRIBUTE_UNUSED;
{
abort ();
}
static bfd_reloc_status_type
local16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol_in ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd ATTRIBUTE_UNUSED;
char **error_message ATTRIBUTE_UNUSED;
{
abort ();
}
static void
rtype2howto (cache_ptr, dst)
arelent *cache_ptr;
struct internal_reloc *dst;
{
unsigned int i;
for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
{
if (tic80_howto_table[i].type == dst->r_type)
{
cache_ptr->howto = tic80_howto_table + i;
return;
}
}
(*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
(unsigned int) dst->r_type);
cache_ptr->howto = tic80_howto_table + 0;
}
#define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
#define coff_rtype_to_howto coff_tic80_rtype_to_howto
static reloc_howto_type *
coff_tic80_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
struct internal_reloc *rel;
struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
struct internal_syment *sym ATTRIBUTE_UNUSED;
bfd_vma *addendp;
{
arelent genrel;
if (rel -> r_symndx == -1 && addendp != NULL)
{
*addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma;
}
RTYPE2HOWTO (&genrel, rel);
return genrel.howto;
}
#ifndef BADMAG
#define BADMAG(x) TIC80BADMAG(x)
#endif
#define coff_relocate_section coff_tic80_relocate_section
static bfd_boolean
coff_tic80_relocate_section (output_bfd, info, input_bfd,
input_section, contents, relocs, syms,
sections)
bfd *output_bfd;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
struct internal_reloc *relocs;
struct internal_syment *syms;
asection **sections;
{
struct internal_reloc *rel;
struct internal_reloc *relend;
rel = relocs;
relend = rel + input_section->reloc_count;
for (; rel < relend; rel++)
{
long symndx;
struct coff_link_hash_entry *h;
struct internal_syment *sym;
bfd_vma addend;
bfd_vma val;
reloc_howto_type *howto;
bfd_reloc_status_type rstat;
bfd_vma addr;
symndx = rel->r_symndx;
if (symndx == -1)
{
h = NULL;
sym = NULL;
}
else
{
h = obj_coff_sym_hashes (input_bfd)[symndx];
sym = syms + symndx;
}
if (sym != NULL && sym->n_scnum != 0)
addend = - sym->n_value;
else
addend = 0;
howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
sym, &addend);
if (howto == NULL)
return FALSE;
val = 0;
if (h == NULL)
{
asection *sec;
if (symndx == -1)
{
sec = bfd_abs_section_ptr;
val = 0;
}
else
{
sec = sections[symndx];
val = (sec->output_section->vma
+ sec->output_offset
+ sym->n_value);
if (! obj_pe (output_bfd))
val -= sec->vma;
}
}
else
{
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
asection *sec;
sec = h->root.u.def.section;
val = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else if (! info->relocatable)
{
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd, input_section,
rel->r_vaddr - input_section->vma, TRUE)))
return FALSE;
}
}
addr = rel->r_vaddr - input_section->vma;
switch (howto->type)
{
default:
case R_ABS:
case R_RELLONGX:
case R_PPL15:
case R_PPL15W:
case R_PPL15H:
case R_PPLN15:
case R_PPLN15W:
case R_PPLN15H:
rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, addr, val, addend);
break;
case R_PP15:
case R_PP15W:
case R_PP15H:
case R_PPN15:
case R_PPN15W:
case R_PPN15H:
rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents + 2, addr, val, addend);
break;
case R_PP16B:
case R_PPN16B:
{
bfd_byte hold;
hold = contents[addr + 4];
contents[addr + 4] &=~ 0x20;
contents[addr + 4] |= (contents[addr] >> 1) & 0x20;
rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents + 2, addr,
val, addend);
contents[addr] &=~ 0x40;
contents[addr] |= (contents[addr + 4] << 1) & 0x40;
contents[addr + 4] &=~ 0x20;
contents[addr + 4] |= hold & 0x20;
break;
}
case R_PPL16B:
case R_PPLN16B:
{
bfd_byte hold;
hold = contents[addr + 1];
contents[addr + 1] &=~ 0x80;
contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80;
rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, addr,
val, addend);
contents[addr + 3] &= ~0x10;
contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10;
contents[addr + 1] &=~ 0x80;
contents[addr + 1] |= hold & 0x80;
break;
}
case R_PPBASE:
contents[addr] &=~ 0x3;
if (val >= 0x1000000 && val < 0x1000800)
contents[addr] |= 0x3;
else
contents[addr] |= 0x2;
rstat = bfd_reloc_ok;
break;
case R_PPLBASE:
contents[addr + 2] &= ~0xc0;
if (val >= 0x1000000 && val < 0x1000800)
contents[addr + 2] |= 0xc0;
else
contents[addr + 2] |= 0x80;
rstat = bfd_reloc_ok;
break;
}
switch (rstat)
{
default:
abort ();
case bfd_reloc_ok:
break;
case bfd_reloc_outofrange:
(*_bfd_error_handler)
(_("%B: bad reloc address 0x%lx in section `%A'"),
input_bfd, input_section, (unsigned long) rel->r_vaddr);
return FALSE;
case bfd_reloc_overflow:
{
const char *name;
char buf[SYMNMLEN + 1];
if (symndx == -1)
name = "*ABS*";
else if (h != NULL)
name = NULL;
else
{
name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
if (name == NULL)
return FALSE;
}
if (! ((*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), name, howto->name,
(bfd_vma) 0, input_bfd, input_section,
rel->r_vaddr - input_section->vma)))
return FALSE;
}
}
}
return TRUE;
}
#define SWAP_OUT_RELOC_EXTRA(abfd,src,dst) \
do \
{ \
dst->r_reserved[0] = 0; \
dst->r_reserved[1] = 0; \
} \
while (0)
#define TIC80COFF 1
#undef C_AUTOARG
#undef C_LASTENT
#include "coffcode.h"
CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)