Adds support to the RL78 port for linker relaxation affecting .debug sections.

gas	* config/tc-rl78.h (TC_LINKRELAX_FIXUP): Define.
	(TC_FORCE_RELOCATION_SUB_SAME): Define.
	(DWARF2_USE_FIXED_ADVANCE_PC): Define.

	* gas/lns/lns.exp: Add RL78 to list of targets using
	DW_LNS_fixed_advance_pc.

bfd	* elf32-rl78.c (RL78_OP_REL): New macro.
	(rl78_elf_howto_table): Use it for complex relocs.
	(get_symbol_value): Handle the cases when the info or status
	arguments are NULL.
	(get_romstart): Cache the status returned by get_symbol_value.
	(get_ramstart): Likewise.
	(RL78_STACK_PUSH): Generate an error message if the stack
	overflows.
	(RL78_STACK_POP): Likewise for underflows.
	(rl78_compute_complex_reloc): New function.  Contains the basic
	processing code for all RL78 complex relocs.
	(rl78_special_reloc): New function.  Provides special reloc
	handling for complex relocs.
	(rl78_elf_relocate_section): Use rl78_compute_complex_reloc.
	(rl78_offset_for_reloc): Likewise.

binutils* readelf.c (target_specific_reloc_handling): Add code to handle
	RL78 complex relocs.
This commit is contained in:
Nick Clifton 2015-04-14 16:23:33 +01:00
parent 9e811bc379
commit 6ff71e7681
9 changed files with 582 additions and 427 deletions

View file

@ -1,3 +1,21 @@
2015-04-14 Nick Clifton <nickc@redhat.com>
* elf32-rl78.c (RL78_OP_REL): New macro.
(rl78_elf_howto_table): Use it for complex relocs.
(get_symbol_value): Handle the cases when the info or status
arguments are NULL.
(get_romstart): Cache the status returned by get_symbol_value.
(get_ramstart): Likewise.
(RL78_STACK_PUSH): Generate an error message if the stack
overflows.
(RL78_STACK_POP): Likewise for underflows.
(rl78_compute_complex_reloc): New function. Contains the basic
processing code for all RL78 complex relocs.
(rl78_special_reloc): New function. Provides special reloc
handling for complex relocs.
(rl78_elf_relocate_section): Use rl78_compute_complex_reloc.
(rl78_offset_for_reloc): Likewise.
2015-04-14 H.J. Lu <hongjiu.lu@intel.com> 2015-04-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/pr17709 PR ld/pr17709

View file

@ -31,6 +31,14 @@
HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \
bfd_elf_generic_reloc, "R_RL78_" #n, FALSE, 0, ~0, FALSE) bfd_elf_generic_reloc, "R_RL78_" #n, FALSE, 0, ~0, FALSE)
static bfd_reloc_status_type rl78_special_reloc (bfd *, arelent *, asymbol *, void *,
asection *, bfd *, char **);
/* FIXME: We could omit the SHIFT parameter, it is always zero. */
#define RL78_OP_REL(n,sz,bit,shift,complain,pcrel) \
HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \
rl78_special_reloc, "R_RL78_" #n, FALSE, 0, ~0, FALSE)
/* Note that the relocations around 0x7f are internal to this file; /* Note that the relocations around 0x7f are internal to this file;
feel free to move them as needed to avoid conflicts with published feel free to move them as needed to avoid conflicts with published
relocation numbers. */ relocation numbers. */
@ -106,23 +114,23 @@ static reloc_howto_type rl78_elf_howto_table [] =
EMPTY_HOWTO (0x3f), EMPTY_HOWTO (0x3f),
EMPTY_HOWTO (0x40), EMPTY_HOWTO (0x40),
RL78REL (ABS32, 2, 32, 0, dont, FALSE), RL78_OP_REL (ABS32, 2, 32, 0, dont, FALSE),
RL78REL (ABS24S, 2, 24, 0, signed, FALSE), RL78_OP_REL (ABS24S, 2, 24, 0, signed, FALSE),
RL78REL (ABS16, 1, 16, 0, dont, FALSE), RL78_OP_REL (ABS16, 1, 16, 0, dont, FALSE),
RL78REL (ABS16U, 1, 16, 0, unsigned, FALSE), RL78_OP_REL (ABS16U, 1, 16, 0, unsigned, FALSE),
RL78REL (ABS16S, 1, 16, 0, signed, FALSE), RL78_OP_REL (ABS16S, 1, 16, 0, signed, FALSE),
RL78REL (ABS8, 0, 8, 0, dont, FALSE), RL78_OP_REL (ABS8, 0, 8, 0, dont, FALSE),
RL78REL (ABS8U, 0, 8, 0, unsigned, FALSE), RL78_OP_REL (ABS8U, 0, 8, 0, unsigned, FALSE),
RL78REL (ABS8S, 0, 8, 0, signed, FALSE), RL78_OP_REL (ABS8S, 0, 8, 0, signed, FALSE),
RL78REL (ABS24S_PCREL, 2, 24, 0, signed, TRUE), RL78_OP_REL (ABS24S_PCREL, 2, 24, 0, signed, TRUE),
RL78REL (ABS16S_PCREL, 1, 16, 0, signed, TRUE), RL78_OP_REL (ABS16S_PCREL, 1, 16, 0, signed, TRUE),
RL78REL (ABS8S_PCREL, 0, 8, 0, signed, TRUE), RL78_OP_REL (ABS8S_PCREL, 0, 8, 0, signed, TRUE),
RL78REL (ABS16UL, 1, 16, 0, unsigned, FALSE), RL78_OP_REL (ABS16UL, 1, 16, 0, unsigned, FALSE),
RL78REL (ABS16UW, 1, 16, 0, unsigned, FALSE), RL78_OP_REL (ABS16UW, 1, 16, 0, unsigned, FALSE),
RL78REL (ABS8UL, 0, 8, 0, unsigned, FALSE), RL78_OP_REL (ABS8UL, 0, 8, 0, unsigned, FALSE),
RL78REL (ABS8UW, 0, 8, 0, unsigned, FALSE), RL78_OP_REL (ABS8UW, 0, 8, 0, unsigned, FALSE),
RL78REL (ABS32_REV, 2, 32, 0, dont, FALSE), RL78_OP_REL (ABS32_REV, 2, 32, 0, dont, FALSE),
RL78REL (ABS16_REV, 1, 16, 0, dont, FALSE), RL78_OP_REL (ABS16_REV, 1, 16, 0, dont, FALSE),
#define STACK_REL_P(x) ((x) <= R_RL78_ABS16_REV && (x) >= R_RL78_ABS32) #define STACK_REL_P(x) ((x) <= R_RL78_ABS16_REV && (x) >= R_RL78_ABS32)
@ -174,29 +182,29 @@ static reloc_howto_type rl78_elf_howto_table [] =
EMPTY_HOWTO (0x7e), EMPTY_HOWTO (0x7e),
EMPTY_HOWTO (0x7f), EMPTY_HOWTO (0x7f),
RL78REL (SYM, 2, 32, 0, dont, FALSE), RL78_OP_REL (SYM, 2, 32, 0, dont, FALSE),
RL78REL (OPneg, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPneg, 2, 32, 0, dont, FALSE),
RL78REL (OPadd, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPadd, 2, 32, 0, dont, FALSE),
RL78REL (OPsub, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPsub, 2, 32, 0, dont, FALSE),
RL78REL (OPmul, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPmul, 2, 32, 0, dont, FALSE),
RL78REL (OPdiv, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPdiv, 2, 32, 0, dont, FALSE),
RL78REL (OPshla, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPshla, 2, 32, 0, dont, FALSE),
RL78REL (OPshra, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPshra, 2, 32, 0, dont, FALSE),
RL78REL (OPsctsize, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPsctsize, 2, 32, 0, dont, FALSE),
EMPTY_HOWTO (0x89), EMPTY_HOWTO (0x89),
EMPTY_HOWTO (0x8a), EMPTY_HOWTO (0x8a),
EMPTY_HOWTO (0x8b), EMPTY_HOWTO (0x8b),
EMPTY_HOWTO (0x8c), EMPTY_HOWTO (0x8c),
RL78REL (OPscttop, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPscttop, 2, 32, 0, dont, FALSE),
EMPTY_HOWTO (0x8e), EMPTY_HOWTO (0x8e),
EMPTY_HOWTO (0x8f), EMPTY_HOWTO (0x8f),
RL78REL (OPand, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPand, 2, 32, 0, dont, FALSE),
RL78REL (OPor, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPor, 2, 32, 0, dont, FALSE),
RL78REL (OPxor, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPxor, 2, 32, 0, dont, FALSE),
RL78REL (OPnot, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPnot, 2, 32, 0, dont, FALSE),
RL78REL (OPmod, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPmod, 2, 32, 0, dont, FALSE),
RL78REL (OPromtop, 2, 32, 0, dont, FALSE), RL78_OP_REL (OPromtop, 2, 32, 0, dont, FALSE),
RL78REL (OPramtop, 2, 32, 0, dont, FALSE) RL78_OP_REL (OPramtop, 2, 32, 0, dont, FALSE)
}; };
/* Map BFD reloc types to RL78 ELF reloc types. */ /* Map BFD reloc types to RL78 ELF reloc types. */
@ -292,22 +300,29 @@ get_symbol_value (const char * name,
asection * input_section, asection * input_section,
int offset) int offset)
{ {
bfd_vma value = 0;
struct bfd_link_hash_entry * h; struct bfd_link_hash_entry * h;
if (info == NULL)
return 0;
h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
if (h == NULL if (h == NULL
|| (h->type != bfd_link_hash_defined || (h->type != bfd_link_hash_defined
&& h->type != bfd_link_hash_defweak)) && h->type != bfd_link_hash_defweak))
* status = info->callbacks->undefined_symbol {
bfd_reloc_status_type res;
res = info->callbacks->undefined_symbol
(info, name, input_bfd, input_section, offset, TRUE); (info, name, input_bfd, input_section, offset, TRUE);
else if (status)
value = (h->u.def.value * status = res;
return 0;
}
return (h->u.def.value
+ h->u.def.section->output_section->vma + h->u.def.section->output_section->vma
+ h->u.def.section->output_offset); + h->u.def.section->output_offset);
return value;
} }
static bfd_vma static bfd_vma
@ -319,12 +334,15 @@ get_romstart (bfd_reloc_status_type * status,
{ {
static bfd_boolean cached = FALSE; static bfd_boolean cached = FALSE;
static bfd_vma cached_value = 0; static bfd_vma cached_value = 0;
static bfd_reloc_status_type cached_status;
if (!cached) if (!cached)
{ {
cached_value = get_symbol_value ("_start", status, info, abfd, sec, offset); cached_value = get_symbol_value ("_start", & cached_status, info, abfd, sec, offset);
cached = TRUE; cached = TRUE;
} }
if (status)
* status = cached_status;
return cached_value; return cached_value;
} }
@ -337,12 +355,15 @@ get_ramstart (bfd_reloc_status_type * status,
{ {
static bfd_boolean cached = FALSE; static bfd_boolean cached = FALSE;
static bfd_vma cached_value = 0; static bfd_vma cached_value = 0;
static bfd_reloc_status_type cached_status;
if (!cached) if (!cached)
{ {
cached_value = get_symbol_value ("__datastart", status, info, abfd, sec, offset); cached_value = get_symbol_value ("__datastart", & cached_status, info, abfd, sec, offset);
cached = TRUE; cached = TRUE;
} }
if (status)
* status = cached_status;
return cached_value; return cached_value;
} }
@ -356,7 +377,7 @@ static unsigned int rl78_stack_top;
if (rl78_stack_top < NUM_STACK_ENTRIES) \ if (rl78_stack_top < NUM_STACK_ENTRIES) \
rl78_stack [rl78_stack_top ++] = (val); \ rl78_stack [rl78_stack_top ++] = (val); \
else \ else \
r = bfd_reloc_dangerous; \ _bfd_error_handler (_("Internal Error: RL78 reloc stack overflow")); \
} \ } \
while (0) while (0)
@ -364,12 +385,269 @@ static unsigned int rl78_stack_top;
do \ do \
{ \ { \
if (rl78_stack_top > 0) \ if (rl78_stack_top > 0) \
(dest) = rl78_stack [-- rl78_stack_top]; \ (dest) = rl78_stack [-- rl78_stack_top];\
else \ else \
(dest) = 0, r = bfd_reloc_dangerous; \ { \
_bfd_error_handler (_("Internal Error: RL78 reloc stack underflow")); \
(dest) = 0; \
} \
} \ } \
while (0) while (0)
/* Special handling for RL78 complex relocs. Returns the
value of the reloc, or 0 for relocs which do not generate
a result. SYMVAL is the value of the symbol for relocs
which use a symbolic argument. */
static bfd_vma
rl78_compute_complex_reloc (unsigned long r_type,
bfd_vma symval,
asection * input_section)
{
int32_t tmp1, tmp2;
bfd_vma relocation;
switch (r_type)
{
default:
return 0;
case R_RL78_ABS24S_PCREL:
case R_RL78_ABS16S_PCREL:
case R_RL78_ABS8S_PCREL:
RL78_STACK_POP (relocation);
relocation -= input_section->output_section->vma + input_section->output_offset;
return relocation;
case R_RL78_ABS32:
case R_RL78_ABS32_REV:
case R_RL78_ABS16:
case R_RL78_ABS16_REV:
case R_RL78_ABS16S:
case R_RL78_ABS16U:
case R_RL78_ABS8:
case R_RL78_ABS8U:
case R_RL78_ABS8S:
RL78_STACK_POP (relocation);
return relocation;
case R_RL78_ABS16UL:
case R_RL78_ABS8UL:
RL78_STACK_POP (relocation);
return relocation >> 2;
case R_RL78_ABS16UW:
case R_RL78_ABS8UW:
RL78_STACK_POP (relocation);
return relocation >> 1;
/* The rest of the relocs compute values and then push them onto the stack. */
case R_RL78_OPramtop:
case R_RL78_OPromtop:
case R_RL78_SYM:
RL78_STACK_PUSH (symval);
return 0;
case R_RL78_OPneg:
RL78_STACK_POP (tmp1);
tmp1 = - tmp1;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPadd:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 += tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPsub:
/* For the expression "A - B", the assembler pushes A,
then B, then OPSUB. So the first op we pop is B, not A. */
RL78_STACK_POP (tmp2); /* B */
RL78_STACK_POP (tmp1); /* A */
tmp1 -= tmp2; /* A - B */
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPmul:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 *= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPdiv:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 /= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPshla:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 <<= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPshra:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 >>= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPsctsize:
RL78_STACK_PUSH (input_section->size);
return 0;
case R_RL78_OPscttop:
RL78_STACK_PUSH (input_section->output_section->vma);
return 0;
case R_RL78_OPand:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 &= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPor:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 |= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPxor:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 ^= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPnot:
RL78_STACK_POP (tmp1);
tmp1 = ~ tmp1;
RL78_STACK_PUSH (tmp1);
return 0;
case R_RL78_OPmod:
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 %= tmp2;
RL78_STACK_PUSH (tmp1);
return 0;
}
}
#undef RL78_STACK_PUSH
#undef RL78_STACK_POP
#define OP(i) (contents[reloc->address + (i)])
static bfd_reloc_status_type
rl78_special_reloc (bfd * input_bfd,
arelent * reloc,
asymbol * symbol,
void * data,
asection * input_section,
bfd * output_bfd ATTRIBUTE_UNUSED,
char ** error_message ATTRIBUTE_UNUSED)
{
bfd_reloc_status_type r = bfd_reloc_ok;
bfd_vma relocation = 0;
unsigned long r_type = reloc->howto->type;
bfd_byte * contents = data;
/* If necessary, compute the symbolic value of the relocation. */
switch (r_type)
{
case R_RL78_SYM:
relocation = (symbol->value
+ symbol->section->output_section->vma
+ symbol->section->output_offset
+ reloc->addend);
break;
case R_RL78_OPromtop:
relocation = get_romstart (&r, NULL, input_bfd, input_section,
reloc->address);
break;
case R_RL78_OPramtop:
relocation = get_ramstart (&r, NULL, input_bfd, input_section,
reloc->address);
break;
}
/* Get the value of the relocation. */
relocation = rl78_compute_complex_reloc (r_type, relocation, input_section);
/* If the relocation alters the contents of the section then apply it now.
Note - since this function is called from
bfd_generic_get_relocated_section_contents via bfd_perform_relocation,
and not from the linker, we do not perform any range checking. The
clients who are calling us are only interested in some relocated section
contents, and not any linkage problems that might occur later. */
switch (r_type)
{
case R_RL78_ABS32:
OP (0) = relocation;
OP (1) = relocation >> 8;
OP (2) = relocation >> 16;
OP (3) = relocation >> 24;
break;
case R_RL78_ABS32_REV:
OP (3) = relocation;
OP (2) = relocation >> 8;
OP (1) = relocation >> 16;
OP (0) = relocation >> 24;
break;
case R_RL78_ABS24S_PCREL:
case R_RL78_ABS24S:
OP (0) = relocation;
OP (1) = relocation >> 8;
OP (2) = relocation >> 16;
break;
case R_RL78_ABS16_REV:
OP (1) = relocation;
OP (0) = relocation >> 8;
break;
case R_RL78_ABS16S_PCREL:
case R_RL78_ABS16:
case R_RL78_ABS16S:
case R_RL78_ABS16U:
case R_RL78_ABS16UL:
case R_RL78_ABS16UW:
OP (0) = relocation;
OP (1) = relocation >> 8;
break;
case R_RL78_ABS8S_PCREL:
case R_RL78_ABS8:
case R_RL78_ABS8U:
case R_RL78_ABS8UL:
case R_RL78_ABS8UW:
case R_RL78_ABS8S:
OP (0) = relocation;
break;
default:
break;
}
return r;
}
#undef OP
#define OP(i) (contents[rel->r_offset + (i)])
/* Relocate an RL78 ELF section. /* Relocate an RL78 ELF section.
There is some attempt to make this function usable for many architectures, There is some attempt to make this function usable for many architectures,
both USE_REL and USE_RELA ['twould be nice if such a critter existed], both USE_REL and USE_RELA ['twould be nice if such a critter existed],
@ -475,7 +753,7 @@ rl78_elf_relocate_section
name = h->root.root.string; name = h->root.root.string;
} }
if (sec != NULL && discarded_section (sec)) if (sec != NULL && discarded_section (sec)
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
rel, 1, relend, howto, 0, contents); rel, 1, relend, howto, 0, contents);
@ -559,8 +837,6 @@ rl78_elf_relocate_section
r = bfd_reloc_ok; r = bfd_reloc_ok;
#define RANGE(a,b) if (a > (long) relocation || (long) relocation > b) r = bfd_reloc_overflow #define RANGE(a,b) if (a > (long) relocation || (long) relocation > b) r = bfd_reloc_overflow
#define ALIGN(m) if (relocation & m) r = bfd_reloc_other;
#define OP(i) (contents[rel->r_offset + (i)])
/* Opcode relocs are always big endian. Data relocs are bi-endian. */ /* Opcode relocs are always big endian. Data relocs are bi-endian. */
switch (r_type) switch (r_type)
@ -663,9 +939,42 @@ rl78_elf_relocate_section
break; break;
/* Complex reloc handling: */ /* Complex reloc handling: */
case R_RL78_ABS32: case R_RL78_ABS32:
RL78_STACK_POP (relocation); case R_RL78_ABS32_REV:
case R_RL78_ABS24S_PCREL:
case R_RL78_ABS24S:
case R_RL78_ABS16:
case R_RL78_ABS16_REV:
case R_RL78_ABS16S_PCREL:
case R_RL78_ABS16S:
case R_RL78_ABS16U:
case R_RL78_ABS16UL:
case R_RL78_ABS16UW:
case R_RL78_ABS8:
case R_RL78_ABS8U:
case R_RL78_ABS8UL:
case R_RL78_ABS8UW:
case R_RL78_ABS8S_PCREL:
case R_RL78_ABS8S:
case R_RL78_OPneg:
case R_RL78_OPadd:
case R_RL78_OPsub:
case R_RL78_OPmul:
case R_RL78_OPdiv:
case R_RL78_OPshla:
case R_RL78_OPshra:
case R_RL78_OPsctsize:
case R_RL78_OPscttop:
case R_RL78_OPand:
case R_RL78_OPor:
case R_RL78_OPxor:
case R_RL78_OPnot:
case R_RL78_OPmod:
relocation = rl78_compute_complex_reloc (r_type, 0, input_section);
switch (r_type)
{
case R_RL78_ABS32:
OP (0) = relocation; OP (0) = relocation;
OP (1) = relocation >> 8; OP (1) = relocation >> 8;
OP (2) = relocation >> 16; OP (2) = relocation >> 16;
@ -673,7 +982,6 @@ rl78_elf_relocate_section
break; break;
case R_RL78_ABS32_REV: case R_RL78_ABS32_REV:
RL78_STACK_POP (relocation);
OP (3) = relocation; OP (3) = relocation;
OP (2) = relocation >> 8; OP (2) = relocation >> 8;
OP (1) = relocation >> 16; OP (1) = relocation >> 16;
@ -682,7 +990,6 @@ rl78_elf_relocate_section
case R_RL78_ABS24S_PCREL: case R_RL78_ABS24S_PCREL:
case R_RL78_ABS24S: case R_RL78_ABS24S:
RL78_STACK_POP (relocation);
RANGE (-0x800000, 0x7fffff); RANGE (-0x800000, 0x7fffff);
OP (0) = relocation; OP (0) = relocation;
OP (1) = relocation >> 8; OP (1) = relocation >> 8;
@ -690,14 +997,12 @@ rl78_elf_relocate_section
break; break;
case R_RL78_ABS16: case R_RL78_ABS16:
RL78_STACK_POP (relocation);
RANGE (-32768, 65535); RANGE (-32768, 65535);
OP (0) = relocation; OP (0) = relocation;
OP (1) = relocation >> 8; OP (1) = relocation >> 8;
break; break;
case R_RL78_ABS16_REV: case R_RL78_ABS16_REV:
RL78_STACK_POP (relocation);
RANGE (-32768, 65535); RANGE (-32768, 65535);
OP (1) = relocation; OP (1) = relocation;
OP (0) = relocation >> 8; OP (0) = relocation >> 8;
@ -705,237 +1010,70 @@ rl78_elf_relocate_section
case R_RL78_ABS16S_PCREL: case R_RL78_ABS16S_PCREL:
case R_RL78_ABS16S: case R_RL78_ABS16S:
RL78_STACK_POP (relocation);
RANGE (-32768, 32767); RANGE (-32768, 32767);
OP (0) = relocation; OP (0) = relocation;
OP (1) = relocation >> 8; OP (1) = relocation >> 8;
break; break;
case R_RL78_ABS16U: case R_RL78_ABS16U:
RL78_STACK_POP (relocation);
RANGE (0, 65536);
OP (0) = relocation;
OP (1) = relocation >> 8;
break;
case R_RL78_ABS16UL: case R_RL78_ABS16UL:
RL78_STACK_POP (relocation);
relocation >>= 2;
RANGE (0, 65536);
OP (0) = relocation;
OP (1) = relocation >> 8;
break;
case R_RL78_ABS16UW: case R_RL78_ABS16UW:
RL78_STACK_POP (relocation);
relocation >>= 1;
RANGE (0, 65536); RANGE (0, 65536);
OP (0) = relocation; OP (0) = relocation;
OP (1) = relocation >> 8; OP (1) = relocation >> 8;
break; break;
case R_RL78_ABS8: case R_RL78_ABS8:
RL78_STACK_POP (relocation);
RANGE (-128, 255); RANGE (-128, 255);
OP (0) = relocation; OP (0) = relocation;
break; break;
case R_RL78_ABS8U: case R_RL78_ABS8U:
RL78_STACK_POP (relocation);
RANGE (0, 255);
OP (0) = relocation;
break;
case R_RL78_ABS8UL: case R_RL78_ABS8UL:
RL78_STACK_POP (relocation);
relocation >>= 2;
RANGE (0, 255);
OP (0) = relocation;
break;
case R_RL78_ABS8UW: case R_RL78_ABS8UW:
RL78_STACK_POP (relocation);
relocation >>= 1;
RANGE (0, 255); RANGE (0, 255);
OP (0) = relocation; OP (0) = relocation;
break; break;
case R_RL78_ABS8S_PCREL: case R_RL78_ABS8S_PCREL:
case R_RL78_ABS8S: case R_RL78_ABS8S:
RL78_STACK_POP (relocation);
RANGE (-128, 127); RANGE (-128, 127);
OP (0) = relocation; OP (0) = relocation;
break; break;
default:
break;
}
break;
case R_RL78_SYM: case R_RL78_SYM:
if (r_symndx < symtab_hdr->sh_info) if (r_symndx < symtab_hdr->sh_info)
RL78_STACK_PUSH (sec->output_section->vma relocation = sec->output_section->vma + sec->output_offset
+ sec->output_offset + sym->st_value + rel->r_addend;
+ sym->st_value else if (h != NULL
+ rel->r_addend);
else
{
if (h != NULL
&& (h->root.type == bfd_link_hash_defined && (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)) || h->root.type == bfd_link_hash_defweak))
RL78_STACK_PUSH (h->root.u.def.value relocation = h->root.u.def.value
+ sec->output_section->vma + sec->output_section->vma
+ sec->output_offset + sec->output_offset
+ rel->r_addend); + rel->r_addend;
else if (h->root.type == bfd_link_hash_undefweak)
RL78_STACK_PUSH (0);
else else
{
relocation = 0;
if (h->root.type != bfd_link_hash_undefweak)
_bfd_error_handler (_("Warning: RL78_SYM reloc with an unknown symbol")); _bfd_error_handler (_("Warning: RL78_SYM reloc with an unknown symbol"));
} }
break; (void) rl78_compute_complex_reloc (r_type, relocation, input_section);
case R_RL78_OPneg:
{
int32_t tmp;
RL78_STACK_POP (tmp);
tmp = - tmp;
RL78_STACK_PUSH (tmp);
}
break;
case R_RL78_OPadd:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 += tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPsub:
{
int32_t tmp1, tmp2;
/* For the expression "A - B", the assembler pushes A,
then B, then OPSUB. So the first op we pop is B, not
A. */
RL78_STACK_POP (tmp2); /* B */
RL78_STACK_POP (tmp1); /* A */
tmp1 -= tmp2; /* A - B */
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPmul:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 *= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPdiv:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 /= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPshla:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 <<= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPshra:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 >>= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPsctsize:
RL78_STACK_PUSH (input_section->size);
break;
case R_RL78_OPscttop:
RL78_STACK_PUSH (input_section->output_section->vma);
break;
case R_RL78_OPand:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 &= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPor:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 |= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPxor:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 ^= tmp2;
RL78_STACK_PUSH (tmp1);
}
break;
case R_RL78_OPnot:
{
int32_t tmp;
RL78_STACK_POP (tmp);
tmp = ~ tmp;
RL78_STACK_PUSH (tmp);
}
break;
case R_RL78_OPmod:
{
int32_t tmp1, tmp2;
RL78_STACK_POP (tmp2);
RL78_STACK_POP (tmp1);
tmp1 %= tmp2;
RL78_STACK_PUSH (tmp1);
}
break; break;
case R_RL78_OPromtop: case R_RL78_OPromtop:
RL78_STACK_PUSH (get_romstart (&r, info, input_bfd, input_section, rel->r_offset)); relocation = get_romstart (&r, info, input_bfd, input_section, rel->r_offset);
(void) rl78_compute_complex_reloc (r_type, relocation, input_section);
break; break;
case R_RL78_OPramtop: case R_RL78_OPramtop:
RL78_STACK_PUSH (get_ramstart (&r, info, input_bfd, input_section, rel->r_offset)); relocation = get_ramstart (&r, info, input_bfd, input_section, rel->r_offset);
(void) rl78_compute_complex_reloc (r_type, relocation, input_section);
break; break;
default: default:
@ -1703,7 +1841,6 @@ rl78_offset_for_reloc (bfd * abfd,
int * scale) int * scale)
{ {
bfd_vma symval; bfd_vma symval;
bfd_reloc_status_type r;
*scale = 1; *scale = 1;
@ -1712,7 +1849,7 @@ rl78_offset_for_reloc (bfd * abfd,
gets a pointer to the last relocation used. */ gets a pointer to the last relocation used. */
while (1) while (1)
{ {
int32_t tmp1, tmp2; unsigned long r_type;
/* Get the value of the symbol referred to by the reloc. */ /* Get the value of the symbol referred to by the reloc. */
if (ELF32_R_SYM (rel->r_info) < symtab_hdr->sh_info) if (ELF32_R_SYM (rel->r_info) < symtab_hdr->sh_info)
@ -1786,135 +1923,57 @@ rl78_offset_for_reloc (bfd * abfd,
symval += rel->r_addend; symval += rel->r_addend;
} }
switch (ELF32_R_TYPE (rel->r_info)) r_type = ELF32_R_TYPE (rel->r_info);
switch (r_type)
{ {
case R_RL78_SYM: case R_RL78_SYM:
RL78_STACK_PUSH (symval); (void) rl78_compute_complex_reloc (r_type, symval, input_section);
break;
case R_RL78_OPneg:
RL78_STACK_POP (tmp1);
tmp1 = - tmp1;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPadd:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 += tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPsub:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp2 -= tmp1;
RL78_STACK_PUSH (tmp2);
break;
case R_RL78_OPmul:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 *= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPdiv:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 /= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPshla:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 <<= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPshra:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 >>= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPsctsize:
RL78_STACK_PUSH (input_section->size);
break;
case R_RL78_OPscttop:
RL78_STACK_PUSH (input_section->output_section->vma);
break;
case R_RL78_OPand:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 &= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPor:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 |= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPxor:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 ^= tmp2;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPnot:
RL78_STACK_POP (tmp1);
tmp1 = ~ tmp1;
RL78_STACK_PUSH (tmp1);
break;
case R_RL78_OPmod:
RL78_STACK_POP (tmp1);
RL78_STACK_POP (tmp2);
tmp1 %= tmp2;
RL78_STACK_PUSH (tmp1);
break; break;
case R_RL78_OPromtop: case R_RL78_OPromtop:
RL78_STACK_PUSH (get_romstart (&r, info, input_bfd, input_section, rel->r_offset)); symval = get_romstart (NULL, info, input_bfd, input_section, rel->r_offset);
(void) rl78_compute_complex_reloc (r_type, symval, input_section);
break; break;
case R_RL78_OPramtop: case R_RL78_OPramtop:
RL78_STACK_PUSH (get_ramstart (&r, info, input_bfd, input_section, rel->r_offset)); symval = get_ramstart (NULL, info, input_bfd, input_section, rel->r_offset);
(void) rl78_compute_complex_reloc (r_type, symval, input_section);
break;
case R_RL78_OPneg:
case R_RL78_OPadd:
case R_RL78_OPsub:
case R_RL78_OPmul:
case R_RL78_OPdiv:
case R_RL78_OPshla:
case R_RL78_OPshra:
case R_RL78_OPsctsize:
case R_RL78_OPscttop:
case R_RL78_OPand:
case R_RL78_OPor:
case R_RL78_OPxor:
case R_RL78_OPnot:
case R_RL78_OPmod:
(void) rl78_compute_complex_reloc (r_type, 0, input_section);
break; break;
case R_RL78_DIR16UL: case R_RL78_DIR16UL:
case R_RL78_DIR8UL: case R_RL78_DIR8UL:
case R_RL78_ABS16UL: case R_RL78_ABS16UL:
case R_RL78_ABS8UL: case R_RL78_ABS8UL:
if (rl78_stack_top)
RL78_STACK_POP (symval);
if (lrel)
*lrel = rel;
*scale = 4; *scale = 4;
return symval; goto reloc_computes_value;
case R_RL78_DIR16UW: case R_RL78_DIR16UW:
case R_RL78_DIR8UW: case R_RL78_DIR8UW:
case R_RL78_ABS16UW: case R_RL78_ABS16UW:
case R_RL78_ABS8UW: case R_RL78_ABS8UW:
if (rl78_stack_top)
RL78_STACK_POP (symval);
if (lrel)
*lrel = rel;
*scale = 2; *scale = 2;
return symval; goto reloc_computes_value;
default: default:
if (rl78_stack_top) reloc_computes_value:
RL78_STACK_POP (symval); symval = rl78_compute_complex_reloc (r_type, 0, input_section);
if (lrel) if (lrel)
*lrel = rel; *lrel = rel;
return symval; return symval;

View file

@ -1,3 +1,8 @@
2015-04-14 Nick Clifton <nickc@redhat.com>
* readelf.c (target_specific_reloc_handling): Add code to handle
RL78 complex relocs.
2015-04-13 Doug Evans <dje@google.com> 2015-04-13 Doug Evans <dje@google.com>
PR binutils/18218 PR binutils/18218

View file

@ -11161,6 +11161,42 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
} }
break; break;
} }
case EM_RL78:
{
static bfd_vma saved_sym1 = 0;
static bfd_vma saved_sym2 = 0;
static bfd_vma value;
switch (reloc_type)
{
case 0x80: /* R_RL78_SYM. */
saved_sym1 = saved_sym2;
saved_sym2 = symtab[get_reloc_symindex (reloc->r_info)].st_value;
saved_sym2 += reloc->r_addend;
return TRUE;
case 0x83: /* R_RL78_OPsub. */
value = saved_sym1 - saved_sym2;
saved_sym2 = saved_sym1 = 0;
return TRUE;
break;
case 0x41: /* R_RL78_ABS32. */
byte_put (start + reloc->r_offset, value, 4);
value = 0;
return TRUE;
case 0x43: /* R_RL78_ABS16. */
byte_put (start + reloc->r_offset, value, 2);
value = 0;
return TRUE;
default:
break;
}
break;
}
} }
return FALSE; return FALSE;

View file

@ -1,3 +1,9 @@
2015-04-14 Nick Clifton <nickc@redhat.com>
* config/tc-rl78.h (TC_LINKRELAX_FIXUP): Define.
(TC_FORCE_RELOCATION_SUB_SAME): Define.
(DWARF2_USE_FIXED_ADVANCE_PC): Define.
2015-04-10 Nick Clifton <nickc@redhat.com> 2015-04-10 Nick Clifton <nickc@redhat.com>
PR binutils/18198 PR binutils/18198

View file

@ -340,15 +340,16 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
} }
void void
md_show_usage (FILE * stream ATTRIBUTE_UNUSED) md_show_usage (FILE * stream)
{ {
fprintf (stream, _(" RL78 specific command line options:\n")); fprintf (stream, _(" RL78 specific command line options:\n"));
fprintf (stream, _(" --mrelax Enable link time relaxation\n"));
fprintf (stream, _(" --mg10 Enable support for G10 variant\n")); fprintf (stream, _(" --mg10 Enable support for G10 variant\n"));
fprintf (stream, _(" --mg13 Selects the G13 core.\n")); fprintf (stream, _(" --mg13 Selects the G13 core.\n"));
fprintf (stream, _(" --mg14 Selects the G14 core [default]\n")); fprintf (stream, _(" --mg14 Selects the G14 core [default]\n"));
fprintf (stream, _(" --mrl78 Alias for --mg14\n")); fprintf (stream, _(" --mrl78 Alias for --mg14\n"));
fprintf (stream, _(" --m32bit-doubles [default]\n")); fprintf (stream, _(" --m32bit-doubles [default]\n"));
fprintf (stream, _(" --m64bit-doubles\n")); fprintf (stream, _(" --m64bit-doubles Source code uses 64-bit doubles\n"));
} }
static void static void
@ -662,12 +663,22 @@ rl78_cons_fix_new (fragS * frag,
case BFD_RELOC_RL78_LO16: case BFD_RELOC_RL78_LO16:
case BFD_RELOC_RL78_HI16: case BFD_RELOC_RL78_HI16:
if (size != 2) if (size != 2)
{
/* Fixups to assembler generated expressions do not use %hi or %lo. */
if (frag->fr_file)
as_bad (_("%%hi16/%%lo16 only applies to .short or .hword")); as_bad (_("%%hi16/%%lo16 only applies to .short or .hword"));
}
else
type = exp->X_md; type = exp->X_md;
break; break;
case BFD_RELOC_RL78_HI8: case BFD_RELOC_RL78_HI8:
if (size != 1) if (size != 1)
{
/* Fixups to assembler generated expressions do not use %hi or %lo. */
if (frag->fr_file)
as_bad (_("%%hi8 only applies to .byte")); as_bad (_("%%hi8 only applies to .byte"));
}
else
type = exp->X_md; type = exp->X_md;
break; break;
default: default:
@ -823,7 +834,7 @@ rl78_frag_fix_value (fragS * fragP,
/* Estimate how big the opcode is after this relax pass. The return /* Estimate how big the opcode is after this relax pass. The return
value is the difference between fr_fix and the actual size. We value is the difference between fr_fix and the actual size. We
compute the total size in rl78_relax_frag and store it in fr_subtype, compute the total size in rl78_relax_frag and store it in fr_subtype,
sowe only need to subtract fx_fix and return it. */ so we only need to subtract fx_fix and return it. */
int int
md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED) md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED)
@ -960,7 +971,7 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
fragP->fr_subtype = newsize; fragP->fr_subtype = newsize;
tprintf (" -> new %d old %d delta %d\n", newsize, oldsize, newsize-oldsize); tprintf (" -> new %d old %d delta %d\n", newsize, oldsize, newsize-oldsize);
return newsize - oldsize; return newsize - oldsize;
} }
/* This lets us test for the opcode type and the desired size in a /* This lets us test for the opcode type and the desired size in a
switch statement. */ switch statement. */

View file

@ -85,3 +85,17 @@ extern void rl78_elf_final_processing (void);
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
((EXP)->X_md = 0, expression (EXP), TC_PARSE_CONS_RETURN_NONE) ((EXP)->X_md = 0, expression (EXP), TC_PARSE_CONS_RETURN_NONE)
#define TC_LINKRELAX_FIXUP(seg) ((seg->flags & SEC_CODE) || (seg->flags & SEC_DEBUGGING))
/* Do not adjust relocations involving symbols in code sections,
because it breaks linker relaxations. This could be fixed in the
linker, but this fix is simpler, and it pretty much only affects
object size a little bit. */
#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEC) \
( ((SEC)->flags & SEC_CODE) != 0 \
|| ((SEC)->flags & SEC_DEBUGGING) != 0 \
|| ! SEG_NORMAL (SEC) \
|| TC_FORCE_RELOCATION (FIX))
#define DWARF2_USE_FIXED_ADVANCE_PC 1

View file

@ -1,3 +1,8 @@
2015-04-14 Nick Clifton <nickc@redhat.com>
* gas/lns/lns.exp: Add RL78 to list of targets using
DW_LNS_fixed_advance_pc.
2015-04-08 H.J. Lu <hongjiu.lu@intel.com> 2015-04-08 H.J. Lu <hongjiu.lu@intel.com>
* gas/i386/dw2-compressed-1.d: New file. * gas/i386/dw2-compressed-1.d: New file.

View file

@ -32,13 +32,14 @@ if {
&& ![istarget s390*-*-*] && ![istarget s390*-*-*]
} { } {
# Use alternate file for targets using DW_LNS_fixed_advance_pc opcodes. # Use alternate file for targets using DW_LNS_fixed_advance_pc opcodes.
if { [istarget xtensa*-*-*] if { [istarget am3*-*-*]
|| [istarget am3*-*-*]
|| [istarget cr16-*-*] || [istarget cr16-*-*]
|| [istarget crx-*-*] || [istarget crx-*-*]
|| [istarget mn10*-*-*]
|| [istarget msp430-*-*] || [istarget msp430-*-*]
|| [istarget nds32*-*-*] || [istarget nds32*-*-*]
|| [istarget mn10*-*-*] } { || [istarget rl78-*-*]
|| [istarget xtensa*-*-*] } {
run_dump_test "lns-common-1-alt" run_dump_test "lns-common-1-alt"
run_dump_test "lns-big-delta" run_dump_test "lns-big-delta"
} elseif { [istarget ia64*-*-*] } { } elseif { [istarget ia64*-*-*] } {