Retro68/binutils/bfd/coff-mcore.c

563 lines
17 KiB
C
Raw Normal View History

2012-03-26 19:18:29 +00:00
/* BFD back-end for Motorola MCore COFF/PE
2018-12-28 15:25:28 +00:00
Copyright (C) 1999-2018 Free Software Foundation, Inc.
2012-03-26 19:18:29 +00:00
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
#include "sysdep.h"
#include "bfd.h"
#include "libbfd.h"
#include "coff/mcore.h"
#include "coff/internal.h"
#include "coff/pe.h"
#include "libcoff.h"
#ifdef BADMAG
#undef BADMAG
#endif
#define BADMAG(x) MCOREBADMAG(x)
#ifndef NUM_ELEM
#define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0])
#endif
/* This file is compiled more than once, but we only compile the
final_link routine once. */
extern bfd_boolean mcore_bfd_coff_final_link
(bfd *, struct bfd_link_info *);
2012-03-26 19:18:29 +00:00
static bfd_reloc_status_type mcore_coff_unsupported_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
2012-03-26 19:18:29 +00:00
/* The NT loader points the toc register to &toc + 32768, in order to
use the complete range of a 16-bit displacement. We have to adjust
for this when we fix up loads displaced off the toc reg. */
#define TOC_LOAD_ADJUSTMENT (-32768)
#define TOC_SECTION_NAME ".private.toc"
/* The main body of code is in coffcode.h. */
#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
from smaller values. Start with zero, widen, *then* decrement. */
#define MINUS_ONE (((bfd_vma)0) - 1)
static reloc_howto_type mcore_coff_howto_table[] =
{
/* Unused: */
HOWTO (IMAGE_REL_MCORE_ABSOLUTE,/* type */
2018-12-28 15:25:28 +00:00
0, /* rightshift */
0, /* size (0 = byte, 1 = short, 2 = long) */
0, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
2012-03-26 19:18:29 +00:00
complain_overflow_dont, /* dont complain_on_overflow */
2018-12-28 15:25:28 +00:00
NULL, /* special_function */
"ABSOLUTE", /* name */
FALSE, /* partial_inplace */
0x00, /* src_mask */
0x00, /* dst_mask */
FALSE), /* pcrel_offset */
2012-03-26 19:18:29 +00:00
HOWTO (IMAGE_REL_MCORE_ADDR32,/* type */
2018-12-28 15:25:28 +00:00
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
2012-03-26 19:18:29 +00:00
complain_overflow_bitfield, /* complain_on_overflow */
2018-12-28 15:25:28 +00:00
NULL, /* special_function */
"ADDR32", /* name */
TRUE, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
2012-03-26 19:18:29 +00:00
/* 8 bits + 2 zero bits; jmpi/jsri/lrw instructions.
Should not appear in object files. */
HOWTO (IMAGE_REL_MCORE_PCREL_IMM8BY4, /* type */
2, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
8, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
mcore_coff_unsupported_reloc, /* special_function */
2018-12-28 15:25:28 +00:00
"IMM8BY4", /* name */
2012-03-26 19:18:29 +00:00
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
TRUE), /* pcrel_offset */
/* bsr/bt/bf/br instructions; 11 bits + 1 zero bit
Span 2k instructions == 4k bytes.
Only useful pieces at the relocated address are the opcode (5 bits) */
HOWTO (IMAGE_REL_MCORE_PCREL_IMM11BY2,/* type */
1, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
11, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
2018-12-28 15:25:28 +00:00
NULL, /* special_function */
"IMM11BY2", /* name */
2012-03-26 19:18:29 +00:00
FALSE, /* partial_inplace */
0x0, /* src_mask */
0x7ff, /* dst_mask */
TRUE), /* pcrel_offset */
/* 4 bits + 1 zero bit; 'loopt' instruction only; unsupported. */
HOWTO (IMAGE_REL_MCORE_PCREL_IMM4BY2, /* type */
1, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
4, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
mcore_coff_unsupported_reloc, /* special_function */
2018-12-28 15:25:28 +00:00
"IMM4BY2", /* name */
2012-03-26 19:18:29 +00:00
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
TRUE), /* pcrel_offset */
/* 32-bit pc-relative. Eventually this will help support PIC code. */
HOWTO (IMAGE_REL_MCORE_PCREL_32,/* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
2018-12-28 15:25:28 +00:00
NULL, /* special_function */
"PCREL_32", /* name */
2012-03-26 19:18:29 +00:00
FALSE, /* partial_inplace */
0x0, /* src_mask */
0xffffffff, /* dst_mask */
TRUE), /* pcrel_offset */
/* Like PCREL_IMM11BY2, this relocation indicates that there is a
'jsri' at the specified address. There is a separate relocation
entry for the literal pool entry that it references, but we
might be able to change the jsri to a bsr if the target turns out
to be close enough [even though we won't reclaim the literal pool
entry, we'll get some runtime efficiency back]. Note that this
is a relocation that we are allowed to safely ignore. */
HOWTO (IMAGE_REL_MCORE_PCREL_JSR_IMM11BY2,/* type */
1, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
11, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
2018-12-28 15:25:28 +00:00
NULL, /* special_function */
"JSR_IMM11BY2", /* name */
2012-03-26 19:18:29 +00:00
FALSE, /* partial_inplace */
0x0, /* src_mask */
0x7ff, /* dst_mask */
TRUE), /* pcrel_offset */
2018-12-28 15:25:28 +00:00
HOWTO (IMAGE_REL_MCORE_RVA, /* type */
2012-03-26 19:18:29 +00:00
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
2018-12-28 15:25:28 +00:00
NULL, /* special_function */
"MCORE_RVA", /* name */
2012-03-26 19:18:29 +00:00
TRUE, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
TRUE) /* pcrel_offset */
};
/* Extend the coff_link_hash_table structure with a few M*Core specific fields.
This allows us to store global data here without actually creating any
global variables, which is a no-no in the BFD world. */
typedef struct coff_mcore_link_hash_table
{
/* The original coff_link_hash_table structure. MUST be first field. */
struct coff_link_hash_table root;
2018-12-28 15:25:28 +00:00
bfd * bfd_of_toc_owner;
long int global_toc_size;
long int import_table_size;
long int first_thunk_address;
long int thunk_size;
2012-03-26 19:18:29 +00:00
}
mcore_hash_table;
/* Get the MCore coff linker hash table from a link_info structure. */
#define coff_mcore_hash_table(info) \
((mcore_hash_table *) ((info)->hash))
/* Add an entry to the base file. */
static bfd_boolean
mcore_emit_base_file_entry (struct bfd_link_info *info,
bfd *output_bfd,
asection *input_section,
bfd_vma reloc_offset)
{
bfd_vma addr = reloc_offset
2018-12-28 15:25:28 +00:00
- input_section->vma
+ input_section->output_offset
+ input_section->output_section->vma;
2012-03-26 19:18:29 +00:00
if (coff_data (output_bfd)->pe)
addr -= pe_data (output_bfd)->pe_opthdr.ImageBase;
if (fwrite (&addr, sizeof (addr), 1, (FILE *) info->base_file) == 1)
return TRUE;
bfd_set_error (bfd_error_system_call);
return FALSE;
}
static bfd_reloc_status_type
mcore_coff_unsupported_reloc (bfd * abfd,
arelent * reloc_entry,
asymbol * symbol ATTRIBUTE_UNUSED,
void * data ATTRIBUTE_UNUSED,
asection * input_section ATTRIBUTE_UNUSED,
bfd * output_bfd ATTRIBUTE_UNUSED,
char ** error_message ATTRIBUTE_UNUSED)
2012-03-26 19:18:29 +00:00
{
BFD_ASSERT (reloc_entry->howto != (reloc_howto_type *)0);
2017-04-10 11:32:00 +00:00
/* xgettext: c-format */
2018-12-28 15:25:28 +00:00
_bfd_error_handler (_("%pB: Relocation %s (%d) is not currently supported.\n"),
2012-03-26 19:18:29 +00:00
abfd,
reloc_entry->howto->name,
reloc_entry->howto->type);
return bfd_reloc_notsupported;
}
/* A cheesy little macro to make the code a little more readable. */
#define HOW2MAP(bfd_rtype, mcore_rtype) \
case bfd_rtype: return & mcore_coff_howto_table [mcore_rtype]
static reloc_howto_type *
mcore_coff_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
2012-03-26 19:18:29 +00:00
{
switch (code)
{
2018-12-28 15:25:28 +00:00
HOW2MAP (BFD_RELOC_32, IMAGE_REL_MCORE_ADDR32);
HOW2MAP (BFD_RELOC_MCORE_PCREL_IMM8BY4, IMAGE_REL_MCORE_PCREL_IMM8BY4);
HOW2MAP (BFD_RELOC_MCORE_PCREL_IMM11BY2, IMAGE_REL_MCORE_PCREL_IMM11BY2);
HOW2MAP (BFD_RELOC_MCORE_PCREL_IMM4BY2, IMAGE_REL_MCORE_PCREL_IMM4BY2);
HOW2MAP (BFD_RELOC_32_PCREL, IMAGE_REL_MCORE_PCREL_32);
2012-03-26 19:18:29 +00:00
HOW2MAP (BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, IMAGE_REL_MCORE_PCREL_JSR_IMM11BY2);
2018-12-28 15:25:28 +00:00
HOW2MAP (BFD_RELOC_RVA, IMAGE_REL_MCORE_RVA);
2012-03-26 19:18:29 +00:00
default:
return NULL;
}
/*NOTREACHED*/
}
#undef HOW2MAP
2015-08-28 15:32:19 +00:00
#define NUM_HOWTOS NUM_ELEM (mcore_coff_howto_table)
2012-03-26 19:18:29 +00:00
static reloc_howto_type *
mcore_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
const char *r_name)
{
unsigned int i;
2015-08-28 15:32:19 +00:00
for (i = 0; i < NUM_HOWTOS; i++)
2012-03-26 19:18:29 +00:00
if (mcore_coff_howto_table[i].name != NULL
&& strcasecmp (mcore_coff_howto_table[i].name, r_name) == 0)
return &mcore_coff_howto_table[i];
return NULL;
}
2015-08-28 15:32:19 +00:00
#define RTYPE2HOWTO(cache_ptr, dst) \
((cache_ptr)->howto = \
((dst)->r_type < NUM_HOWTOS \
? mcore_coff_howto_table + (dst)->r_type \
: NULL))
2012-03-26 19:18:29 +00:00
static reloc_howto_type *
coff_mcore_rtype_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
asection * sec,
struct internal_reloc * rel,
struct coff_link_hash_entry * h ATTRIBUTE_UNUSED,
struct internal_syment * sym,
bfd_vma * addendp)
2012-03-26 19:18:29 +00:00
{
reloc_howto_type * howto;
2015-08-28 15:32:19 +00:00
if (rel->r_type >= NUM_HOWTOS)
2012-03-26 19:18:29 +00:00
return NULL;
howto = mcore_coff_howto_table + rel->r_type;
if (rel->r_type == IMAGE_REL_MCORE_RVA)
* addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase;
else if (howto->pc_relative)
{
* addendp = sec->vma - 2; /* XXX guess - is this right ? */
/* If the symbol is defined, then the generic code is going to
2018-12-28 15:25:28 +00:00
add back the symbol value in order to cancel out an
adjustment it made to the addend. However, we set the addend
to 0 at the start of this function. We need to adjust here,
to avoid the adjustment the generic code will make. FIXME:
This is getting a bit hackish. */
2012-03-26 19:18:29 +00:00
if (sym != NULL && sym->n_scnum != 0)
* addendp -= sym->n_value;
}
else
* addendp = 0;
return howto;
}
/* Return TRUE if this relocation should appear in the output .reloc section.
This function is referenced in pe_mkobject in peicode.h. */
static bfd_boolean
in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, reloc_howto_type * howto)
2012-03-26 19:18:29 +00:00
{
return ! howto->pc_relative && howto->type != IMAGE_REL_MCORE_RVA;
}
/* The reloc processing routine for the optimized COFF linker. */
static bfd_boolean
coff_mcore_relocate_section (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)
2012-03-26 19:18:29 +00:00
{
struct internal_reloc * rel;
struct internal_reloc * relend;
/* If we are performing a relocatable link, we don't need to do a
thing. The caller will take care of adjusting the reloc
addresses and symbol indices. */
2017-04-10 11:32:00 +00:00
if (bfd_link_relocatable (info))
2012-03-26 19:18:29 +00:00
return TRUE;
/* Check if we have the same endianness */
2012-03-26 19:18:29 +00:00
if ( input_bfd->xvec->byteorder != output_bfd->xvec->byteorder
&& output_bfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
{
2017-04-10 11:32:00 +00:00
_bfd_error_handler
/* xgettext: c-format */
2018-12-28 15:25:28 +00:00
(_("%pB: compiled for a %s system and target is %s.\n"),
2012-03-26 19:18:29 +00:00
input_bfd,
2018-12-28 15:25:28 +00:00
bfd_big_endian (input_bfd) ? _("big endian") : _("little endian"),
bfd_big_endian (output_bfd) ? _("big endian") : _("little endian"));
2012-03-26 19:18:29 +00:00
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
rel = relocs;
relend = rel + input_section->reloc_count;
for (; rel < relend; rel++)
{
2018-12-28 15:25:28 +00:00
long symndx;
struct internal_syment * sym;
bfd_vma val;
bfd_vma addend;
bfd_reloc_status_type rstat;
bfd_byte * loc;
unsigned short r_type = rel->r_type;
reloc_howto_type * howto = NULL;
2012-03-26 19:18:29 +00:00
struct coff_link_hash_entry * h;
2018-12-28 15:25:28 +00:00
const char * my_name;
2012-03-26 19:18:29 +00:00
symndx = rel->r_symndx;
loc = contents + rel->r_vaddr - input_section->vma;
if (symndx == -1)
{
h = NULL;
sym = NULL;
}
else
{
h = obj_coff_sym_hashes (input_bfd)[symndx];
sym = syms + symndx;
}
addend = 0;
/* Get the howto and initialise the addend. */
howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
sym, & addend);
if (howto == NULL)
return FALSE;
val = 0;
if (h == NULL)
{
if (symndx == -1)
my_name = "*ABS*";
else
{
asection * sec = sections[symndx];
val = (sym->n_value
+ sec->output_section->vma
+ sec->output_offset);
if (sym == NULL)
my_name = "*unknown*";
else if ( sym->_n._n_n._n_zeroes == 0
&& sym->_n._n_n._n_offset != 0)
my_name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
else
{
static char buf [SYMNMLEN + 1];
strncpy (buf, sym->_n._n_name, SYMNMLEN);
buf[SYMNMLEN] = '\0';
my_name = buf;
}
}
}
else
{
if ( h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
asection * sec = h->root.u.def.section;
val = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else
2017-04-10 11:32:00 +00:00
(*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd, input_section,
rel->r_vaddr - input_section->vma, TRUE);
2012-03-26 19:18:29 +00:00
my_name = h->root.root.string;
}
rstat = bfd_reloc_ok;
/* Each case must do its own relocation, setting rstat appropriately. */
switch (r_type)
{
default:
2017-04-10 11:32:00 +00:00
/* xgettext: c-format */
2018-12-28 15:25:28 +00:00
_bfd_error_handler (_("%pB: unsupported relocation type %#x"),
2012-03-26 19:18:29 +00:00
input_bfd, r_type);
bfd_set_error (bfd_error_bad_value);
return FALSE;
case IMAGE_REL_MCORE_ABSOLUTE:
_bfd_error_handler
2017-04-10 11:32:00 +00:00
/* xgettext: c-format */
2018-12-28 15:25:28 +00:00
(_("warning: unsupported reloc %s <file %pB, section %pA>\n"
"sym %ld (%s), r_vaddr %" PRId64 " (%#" PRIx64 ")"),
howto->name, input_bfd, input_section,
2018-12-28 15:25:28 +00:00
rel->r_symndx, my_name, (int64_t) rel->r_vaddr,
(uint64_t) rel->r_vaddr);
2012-03-26 19:18:29 +00:00
break;
case IMAGE_REL_MCORE_PCREL_IMM8BY4:
case IMAGE_REL_MCORE_PCREL_IMM11BY2:
case IMAGE_REL_MCORE_PCREL_IMM4BY2:
case IMAGE_REL_MCORE_PCREL_32:
case IMAGE_REL_MCORE_PCREL_JSR_IMM11BY2:
case IMAGE_REL_MCORE_ADDR32:
/* XXX fixme - shouldn't this be like the code for the RVA reloc ? */
rstat = _bfd_relocate_contents (howto, input_bfd, val, loc);
break;
case IMAGE_REL_MCORE_RVA:
rstat = _bfd_final_link_relocate
(howto, input_bfd,
input_section, contents, rel->r_vaddr - input_section->vma,
val, addend);
break;
}
/* Emit a reloc if the backend thinks it needs it. */
if (info->base_file
&& sym
&& pe_data (output_bfd)->in_reloc_p (output_bfd, howto)
&& !mcore_emit_base_file_entry (info, output_bfd, input_section,
rel->r_vaddr))
return FALSE;
switch (rstat)
{
default:
abort ();
case bfd_reloc_ok:
break;
case bfd_reloc_overflow:
2017-04-10 11:32:00 +00:00
(*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), my_name, howto->name,
(bfd_vma) 0, input_bfd,
input_section, rel->r_vaddr - input_section->vma);
2012-03-26 19:18:29 +00:00
}
}
return TRUE;
}
/* Tailor coffcode.h -- macro heaven. */
/* We use the special COFF backend linker, with our own special touch. */
#define coff_bfd_reloc_type_lookup mcore_coff_reloc_type_lookup
#define coff_bfd_reloc_name_lookup mcore_coff_reloc_name_lookup
2018-12-28 15:25:28 +00:00
#define coff_relocate_section coff_mcore_relocate_section
#define coff_rtype_to_howto coff_mcore_rtype_to_howto
2012-03-26 19:18:29 +00:00
#define SELECT_RELOC(internal, howto) {internal.r_type = howto->type;}
/* Make sure that the 'r_offset' field is copied properly
so that identical binaries will compare the same. */
2018-12-28 15:25:28 +00:00
#define SWAP_IN_RELOC_OFFSET H_GET_32
#define SWAP_OUT_RELOC_OFFSET H_PUT_32
2012-03-26 19:18:29 +00:00
2018-12-28 15:25:28 +00:00
#define COFF_PAGE_SIZE 0x1000
2012-03-26 19:18:29 +00:00
#include "coffcode.h"
/* Forward declaration to initialise alternative_target field. */
extern const bfd_target TARGET_LITTLE_SYM;
/* The transfer vectors that lead the outside world to all of the above. */
CREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED,
(SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_READONLY | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
0, & TARGET_LITTLE_SYM, COFF_SWAP_TABLE)
CREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED,
(SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_READONLY | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
0, & TARGET_BIG_SYM, COFF_SWAP_TABLE)