PR28163, Segment fault in function rl78_special_reloc

Relocation offset checks were completely missing in the rl78 backend,
allowing a relocation to write over memory anywhere.  This was true
for rl78_special_reloc, a function primarily used when applying debug
relocations, and in rl78_elf_relocate_section used by the linker.

This patch fixes those problems by correcting inaccuracies in the
relocation howtos, then uses those howtos to sanity check relocation
offsets before applying relocations.  In addition, the patch
implements overflow checking using the howto information rather than
the ad-hoc scheme implemented in relocate_section.  I implemented the
overflow checking in rl78_special_reloc too.

	* elf32-rl78.c (RL78REL, RL78_OP_REL): Add mask parameter.
	(rl78_elf_howto_table): Set destination masks.  Correct size and
	bitsize of DIR32_REV.  Correct complain_on_overflow for many relocs
	as per tests in relocate_section.  Add RH_SFR.  Correct bitsize
	for RH_SADDR.  Set size to 3 and bitsize to 0 for all OP relocs.
	(check_overflow): New function.
	(rl78_special_reloc): Check that reloc address is within section.
	Apply relocations using reloc howto.  Check for overflow.
	(RANGE): Delete.
	(rl78_elf_relocate_section): Sanity check r_offset.  Perform
	overflow checking using reloc howto.
This commit is contained in:
Alan Modra 2021-08-11 15:06:20 +09:30
parent c0e94211e1
commit 2ad55ffca1

View file

@ -27,17 +27,16 @@
#define valid_16bit_address(v) ((v) <= 0x0ffff || (v) >= 0xf0000) #define valid_16bit_address(v) ((v) <= 0x0ffff || (v) >= 0xf0000)
#define RL78REL(n,sz,bit,shift,complain,pcrel) \ #define RL78REL(n,sz,bit,mask,shift,complain,pcrel) \
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, mask, false)
static bfd_reloc_status_type rl78_special_reloc (bfd *, arelent *, asymbol *, void *, static bfd_reloc_status_type rl78_special_reloc (bfd *, arelent *, asymbol *, void *,
asection *, bfd *, char **); asection *, bfd *, char **);
/* FIXME: We could omit the SHIFT parameter, it is always zero. */ #define RL78_OP_REL(n,sz,bit,mask,shift,complain,pcrel) \
#define RL78_OP_REL(n,sz,bit,shift,complain,pcrel) \
HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \
rl78_special_reloc, "R_RL78_" #n, false, 0, ~0, false) rl78_special_reloc, "R_RL78_" #n, false, 0, mask, 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
@ -45,25 +44,25 @@ static bfd_reloc_status_type rl78_special_reloc (bfd *, arelent *, asymbol *, vo
static reloc_howto_type rl78_elf_howto_table [] = static reloc_howto_type rl78_elf_howto_table [] =
{ {
RL78REL (NONE, 3, 0, 0, dont, false), RL78REL (NONE, 3, 0, 0, 0, dont, false),
RL78REL (DIR32, 2, 32, 0, signed, false), RL78REL (DIR32, 2, 32, 0xffffffff, 0, dont, false),
RL78REL (DIR24S, 2, 24, 0, signed, false), RL78REL (DIR24S, 2, 24, 0xffffff, 0, signed, false),
RL78REL (DIR16, 1, 16, 0, dont, false), RL78REL (DIR16, 1, 16, 0xffff, 0, bitfield, false),
RL78REL (DIR16U, 1, 16, 0, unsigned, false), RL78REL (DIR16U, 1, 16, 0xffff, 0, unsigned, false),
RL78REL (DIR16S, 1, 16, 0, signed, false), RL78REL (DIR16S, 1, 16, 0xffff, 0, bitfield, false),
RL78REL (DIR8, 0, 8, 0, dont, false), RL78REL (DIR8, 0, 8, 0xff, 0, dont, false),
RL78REL (DIR8U, 0, 8, 0, unsigned, false), RL78REL (DIR8U, 0, 8, 0xff, 0, unsigned, false),
RL78REL (DIR8S, 0, 8, 0, signed, false), RL78REL (DIR8S, 0, 8, 0xff, 0, bitfield, false),
RL78REL (DIR24S_PCREL, 2, 24, 0, signed, true), RL78REL (DIR24S_PCREL, 2, 24, 0xffffff, 0, signed, true),
RL78REL (DIR16S_PCREL, 1, 16, 0, signed, true), RL78REL (DIR16S_PCREL, 1, 16, 0xffff, 0, signed, true),
RL78REL (DIR8S_PCREL, 0, 8, 0, signed, true), RL78REL (DIR8S_PCREL, 0, 8, 0xff, 0, signed, true),
RL78REL (DIR16UL, 1, 16, 2, unsigned, false), RL78REL (DIR16UL, 1, 16, 0xffff, 2, unsigned, false),
RL78REL (DIR16UW, 1, 16, 1, unsigned, false), RL78REL (DIR16UW, 1, 16, 0xffff, 1, unsigned, false),
RL78REL (DIR8UL, 0, 8, 2, unsigned, false), RL78REL (DIR8UL, 0, 8, 0xff, 2, unsigned, false),
RL78REL (DIR8UW, 0, 8, 1, unsigned, false), RL78REL (DIR8UW, 0, 8, 0xff, 1, unsigned, false),
RL78REL (DIR32_REV, 1, 16, 0, dont, false), RL78REL (DIR32_REV, 2, 32, 0xffffffff, 0, dont, false),
RL78REL (DIR16_REV, 1, 16, 0, dont, false), RL78REL (DIR16_REV, 1, 16, 0xffff, 0, bitfield, false),
RL78REL (DIR3U_PCREL, 0, 3, 0, dont, true), RL78REL (DIR3U_PCREL, 0, 3, 0x7, 0, unsigned, true),
EMPTY_HOWTO (0x13), EMPTY_HOWTO (0x13),
EMPTY_HOWTO (0x14), EMPTY_HOWTO (0x14),
@ -92,10 +91,11 @@ static reloc_howto_type rl78_elf_howto_table [] =
EMPTY_HOWTO (0x2a), EMPTY_HOWTO (0x2a),
EMPTY_HOWTO (0x2b), EMPTY_HOWTO (0x2b),
EMPTY_HOWTO (0x2c), EMPTY_HOWTO (0x2c),
RL78REL (RH_RELAX, 0, 0, 0, dont, false),
EMPTY_HOWTO (0x2e), RL78REL (RH_RELAX, 3, 0, 0, 0, dont, false),
RL78REL (RH_SADDR, 0, 0, 0, dont, false), RL78REL (RH_SFR, 0, 8, 0xff, 0, unsigned, false),
RL78REL (RH_SADDR, 0, 8, 0xff, 0, unsigned, false),
EMPTY_HOWTO (0x30), EMPTY_HOWTO (0x30),
EMPTY_HOWTO (0x31), EMPTY_HOWTO (0x31),
EMPTY_HOWTO (0x32), EMPTY_HOWTO (0x32),
@ -114,23 +114,23 @@ static reloc_howto_type rl78_elf_howto_table [] =
EMPTY_HOWTO (0x3f), EMPTY_HOWTO (0x3f),
EMPTY_HOWTO (0x40), EMPTY_HOWTO (0x40),
RL78_OP_REL (ABS32, 2, 32, 0, dont, false), RL78_OP_REL (ABS32, 2, 32, 0xffffffff, 0, dont, false),
RL78_OP_REL (ABS24S, 2, 24, 0, signed, false), RL78_OP_REL (ABS24S, 2, 24, 0xffffff, 0, signed, false),
RL78_OP_REL (ABS16, 1, 16, 0, dont, false), RL78_OP_REL (ABS16, 1, 16, 0xffff, 0, bitfield, false),
RL78_OP_REL (ABS16U, 1, 16, 0, unsigned, false), RL78_OP_REL (ABS16U, 1, 16, 0xffff, 0, unsigned, false),
RL78_OP_REL (ABS16S, 1, 16, 0, signed, false), RL78_OP_REL (ABS16S, 1, 16, 0xffff, 0, signed, false),
RL78_OP_REL (ABS8, 0, 8, 0, dont, false), RL78_OP_REL (ABS8, 0, 8, 0xff, 0, bitfield, false),
RL78_OP_REL (ABS8U, 0, 8, 0, unsigned, false), RL78_OP_REL (ABS8U, 0, 8, 0xff, 0, unsigned, false),
RL78_OP_REL (ABS8S, 0, 8, 0, signed, false), RL78_OP_REL (ABS8S, 0, 8, 0xff, 0, signed, false),
RL78_OP_REL (ABS24S_PCREL, 2, 24, 0, signed, true), RL78_OP_REL (ABS24S_PCREL, 2, 24, 0xffffff, 0, signed, true),
RL78_OP_REL (ABS16S_PCREL, 1, 16, 0, signed, true), RL78_OP_REL (ABS16S_PCREL, 1, 16, 0xffff, 0, signed, true),
RL78_OP_REL (ABS8S_PCREL, 0, 8, 0, signed, true), RL78_OP_REL (ABS8S_PCREL, 0, 8, 0xff, 0, signed, true),
RL78_OP_REL (ABS16UL, 1, 16, 0, unsigned, false), RL78_OP_REL (ABS16UL, 1, 16, 0xffff, 0, unsigned, false),
RL78_OP_REL (ABS16UW, 1, 16, 0, unsigned, false), RL78_OP_REL (ABS16UW, 1, 16, 0xffff, 0, unsigned, false),
RL78_OP_REL (ABS8UL, 0, 8, 0, unsigned, false), RL78_OP_REL (ABS8UL, 0, 8, 0xff, 0, unsigned, false),
RL78_OP_REL (ABS8UW, 0, 8, 0, unsigned, false), RL78_OP_REL (ABS8UW, 0, 8, 0xff, 0, unsigned, false),
RL78_OP_REL (ABS32_REV, 2, 32, 0, dont, false), RL78_OP_REL (ABS32_REV, 2, 32, 0xffffffff, 0, dont, false),
RL78_OP_REL (ABS16_REV, 1, 16, 0, dont, false), RL78_OP_REL (ABS16_REV, 1, 16, 0xffff, 0, bitfield, 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)
@ -182,29 +182,29 @@ static reloc_howto_type rl78_elf_howto_table [] =
EMPTY_HOWTO (0x7e), EMPTY_HOWTO (0x7e),
EMPTY_HOWTO (0x7f), EMPTY_HOWTO (0x7f),
RL78_OP_REL (SYM, 2, 32, 0, dont, false), RL78_OP_REL (SYM, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPneg, 2, 32, 0, dont, false), RL78_OP_REL (OPneg, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPadd, 2, 32, 0, dont, false), RL78_OP_REL (OPadd, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPsub, 2, 32, 0, dont, false), RL78_OP_REL (OPsub, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPmul, 2, 32, 0, dont, false), RL78_OP_REL (OPmul, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPdiv, 2, 32, 0, dont, false), RL78_OP_REL (OPdiv, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPshla, 2, 32, 0, dont, false), RL78_OP_REL (OPshla, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPshra, 2, 32, 0, dont, false), RL78_OP_REL (OPshra, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPsctsize, 2, 32, 0, dont, false), RL78_OP_REL (OPsctsize, 3, 0, 0, 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),
RL78_OP_REL (OPscttop, 2, 32, 0, dont, false), RL78_OP_REL (OPscttop, 3, 0, 0, 0, dont, false),
EMPTY_HOWTO (0x8e), EMPTY_HOWTO (0x8e),
EMPTY_HOWTO (0x8f), EMPTY_HOWTO (0x8f),
RL78_OP_REL (OPand, 2, 32, 0, dont, false), RL78_OP_REL (OPand, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPor, 2, 32, 0, dont, false), RL78_OP_REL (OPor, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPxor, 2, 32, 0, dont, false), RL78_OP_REL (OPxor, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPnot, 2, 32, 0, dont, false), RL78_OP_REL (OPnot, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPmod, 2, 32, 0, dont, false), RL78_OP_REL (OPmod, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPromtop, 2, 32, 0, dont, false), RL78_OP_REL (OPromtop, 3, 0, 0, 0, dont, false),
RL78_OP_REL (OPramtop, 2, 32, 0, dont, false) RL78_OP_REL (OPramtop, 3, 0, 0, 0, dont, false)
}; };
/* Map BFD reloc types to RL78 ELF reloc types. */ /* Map BFD reloc types to RL78 ELF reloc types. */
@ -559,7 +559,36 @@ rl78_compute_complex_reloc (unsigned long r_type,
return relocation; return relocation;
} }
#define OP(i) (contents[reloc->address + (i)]) /* Check whether RELOCATION overflows a relocation field described by
HOWTO. */
static bfd_reloc_status_type
check_overflow (reloc_howto_type *howto, bfd_vma relocation)
{
switch (howto->complain_on_overflow)
{
case complain_overflow_dont:
break;
case complain_overflow_bitfield:
if ((bfd_signed_vma) relocation < -(1LL << (howto->bitsize - 1))
|| (bfd_signed_vma) relocation >= 1LL << howto->bitsize)
return bfd_reloc_overflow;
break;
case complain_overflow_signed:
if ((bfd_signed_vma) relocation < -(1LL << (howto->bitsize - 1))
|| (bfd_signed_vma) relocation >= 1LL << (howto->bitsize - 1))
return bfd_reloc_overflow;
break;
case complain_overflow_unsigned:
if (relocation >= 1ULL << howto->bitsize)
return bfd_reloc_overflow;
break;
}
return bfd_reloc_ok;
}
static bfd_reloc_status_type static bfd_reloc_status_type
rl78_special_reloc (bfd * input_bfd, rl78_special_reloc (bfd * input_bfd,
@ -600,67 +629,42 @@ rl78_special_reloc (bfd * input_bfd,
relocation = rl78_compute_complex_reloc (r_type, relocation, input_section, relocation = rl78_compute_complex_reloc (r_type, relocation, input_section,
&r, error_message); &r, error_message);
/* If the relocation alters the contents of the section then apply it now. if (STACK_REL_P (r_type))
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: bfd_size_type limit;
OP (0) = relocation; unsigned int nbytes;
OP (1) = relocation >> 8;
OP (2) = relocation >> 16;
OP (3) = relocation >> 24;
break;
case R_RL78_ABS32_REV: if (r == bfd_reloc_ok)
OP (3) = relocation; r = check_overflow (reloc->howto, relocation);
OP (2) = relocation >> 8;
OP (1) = relocation >> 16;
OP (0) = relocation >> 24;
break;
case R_RL78_ABS24S_PCREL: if (r_type == R_RL78_ABS16_REV)
case R_RL78_ABS24S: relocation = ((relocation & 0xff) << 8) | ((relocation >> 8) & 0xff);
OP (0) = relocation; else if (r_type == R_RL78_ABS32_REV)
OP (1) = relocation >> 8; relocation = (((relocation & 0xff) << 24)
OP (2) = relocation >> 16; | ((relocation & 0xff00) << 8)
break; | ((relocation >> 8) & 0xff00)
| ((relocation >> 24) & 0xff));
case R_RL78_ABS16_REV: limit = bfd_get_section_limit_octets (input_bfd, input_section);
OP (1) = relocation; nbytes = reloc->howto->bitsize / 8;
OP (0) = relocation >> 8; if (reloc->address < limit
break; && nbytes <= limit - reloc->address)
{
unsigned int i;
case R_RL78_ABS16S_PCREL: for (i = 0; i < nbytes; i++)
case R_RL78_ABS16: {
case R_RL78_ABS16S: contents[reloc->address + i] = relocation;
case R_RL78_ABS16U: relocation >>= 8;
case R_RL78_ABS16UL: }
case R_RL78_ABS16UW: }
OP (0) = relocation; else
OP (1) = relocation >> 8; r = bfd_reloc_outofrange;
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; return r;
} }
#undef OP
#define OP(i) (contents[rel->r_offset + (i)]) #define OP(i) (contents[rel->r_offset + (i)])
/* Relocate an RL78 ELF section. /* Relocate an RL78 ELF section.
@ -848,256 +852,247 @@ rl78_elf_relocate_section
} }
r = bfd_reloc_ok; r = bfd_reloc_ok;
if (howto->bitsize != 0
&& (rel->r_offset >= input_section->size
|| ((howto->bitsize + 7u) / 8
> input_section->size - rel->r_offset)))
r = bfd_reloc_outofrange;
else
switch (r_type)
{
case R_RL78_NONE:
break;
#define RANGE(a,b) if (a > (long) relocation || (long) relocation > b) r = bfd_reloc_overflow case R_RL78_RH_RELAX:
break;
/* Opcode relocs are always big endian. Data relocs are bi-endian. */ case R_RL78_DIR8S_PCREL:
switch (r_type) OP (0) = relocation;
{ break;
case R_RL78_NONE:
break;
case R_RL78_RH_RELAX: case R_RL78_DIR8S:
break; OP (0) = relocation;
break;
case R_RL78_DIR8S_PCREL: case R_RL78_DIR8U:
RANGE (-128, 127); OP (0) = relocation;
OP (0) = relocation; break;
break;
case R_RL78_DIR8S: case R_RL78_DIR16S_PCREL:
RANGE (-128, 255); OP (0) = relocation;
OP (0) = relocation; OP (1) = relocation >> 8;
break; break;
case R_RL78_DIR8U: case R_RL78_DIR16S:
RANGE (0, 255); if ((relocation & 0xf0000) == 0xf0000)
OP (0) = relocation; relocation &= 0xffff;
break; OP (0) = relocation;
OP (1) = relocation >> 8;
break;
case R_RL78_DIR16S_PCREL: case R_RL78_DIR16U:
RANGE (-32768, 32767); OP (0) = relocation;
OP (0) = relocation; OP (1) = relocation >> 8;
OP (1) = relocation >> 8; break;
break;
case R_RL78_DIR16S: case R_RL78_DIR16:
if ((relocation & 0xf0000) == 0xf0000) OP (0) = relocation;
relocation &= 0xffff; OP (1) = relocation >> 8;
RANGE (-32768, 65535); break;
OP (0) = relocation;
OP (1) = relocation >> 8;
break;
case R_RL78_DIR16U: case R_RL78_DIR16_REV:
RANGE (0, 65536); OP (1) = relocation;
OP (0) = relocation; OP (0) = relocation >> 8;
OP (1) = relocation >> 8; break;
break;
case R_RL78_DIR16: case R_RL78_DIR3U_PCREL:
RANGE (-32768, 65536); OP (0) &= 0xf8;
OP (0) = relocation; OP (0) |= relocation & 0x07;
OP (1) = relocation >> 8; /* Map [3, 10] to [0, 7]. The code below using howto
break; bitsize will check for unsigned overflow. */
relocation -= 3;
break;
case R_RL78_DIR16_REV: case R_RL78_DIR24S_PCREL:
RANGE (-32768, 65536); OP (0) = relocation;
OP (1) = relocation; OP (1) = relocation >> 8;
OP (0) = relocation >> 8; OP (2) = relocation >> 16;
break; break;
case R_RL78_DIR3U_PCREL: case R_RL78_DIR24S:
RANGE (3, 10); OP (0) = relocation;
OP (0) &= 0xf8; OP (1) = relocation >> 8;
OP (0) |= relocation & 0x07; OP (2) = relocation >> 16;
break; break;
case R_RL78_DIR24S_PCREL: case R_RL78_DIR32:
RANGE (-0x800000, 0x7fffff); OP (0) = relocation;
OP (0) = relocation; OP (1) = relocation >> 8;
OP (1) = relocation >> 8; OP (2) = relocation >> 16;
OP (2) = relocation >> 16; OP (3) = relocation >> 24;
break; break;
case R_RL78_DIR24S: case R_RL78_DIR32_REV:
RANGE (-0x800000, 0x7fffff); OP (3) = relocation;
OP (0) = relocation; OP (2) = relocation >> 8;
OP (1) = relocation >> 8; OP (1) = relocation >> 16;
OP (2) = relocation >> 16; OP (0) = relocation >> 24;
break; break;
case R_RL78_DIR32: case R_RL78_RH_SFR:
OP (0) = relocation; relocation -= 0xfff00;
OP (1) = relocation >> 8; OP (0) = relocation;
OP (2) = relocation >> 16; break;
OP (3) = relocation >> 24;
break;
case R_RL78_DIR32_REV: case R_RL78_RH_SADDR:
OP (3) = relocation; relocation -= 0xffe20;
OP (2) = relocation >> 8; OP (0) = relocation;
OP (1) = relocation >> 16; break;
OP (0) = relocation >> 24;
break;
case R_RL78_RH_SFR: /* Complex reloc handling: */
RANGE (0xfff00, 0xfffff); case R_RL78_ABS32:
OP (0) = relocation & 0xff; case R_RL78_ABS32_REV:
break; 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,
&r, &error_message);
case R_RL78_RH_SADDR: switch (r_type)
RANGE (0xffe20, 0xfff1f); {
OP (0) = (relocation - 0x20) & 0xff; case R_RL78_ABS32:
break; OP (0) = relocation;
OP (1) = relocation >> 8;
OP (2) = relocation >> 16;
OP (3) = relocation >> 24;
break;
/* Complex reloc handling: */ case R_RL78_ABS32_REV:
case R_RL78_ABS32: OP (3) = relocation;
case R_RL78_ABS32_REV: OP (2) = relocation >> 8;
case R_RL78_ABS24S_PCREL: OP (1) = relocation >> 16;
case R_RL78_ABS24S: OP (0) = relocation >> 24;
case R_RL78_ABS16: break;
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,
&r, &error_message);
switch (r_type) case R_RL78_ABS24S_PCREL:
{ case R_RL78_ABS24S:
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; break;
OP (3) = relocation >> 24;
break;
case R_RL78_ABS32_REV: case R_RL78_ABS16:
OP (3) = relocation; OP (0) = relocation;
OP (2) = relocation >> 8; OP (1) = relocation >> 8;
OP (1) = relocation >> 16; break;
OP (0) = relocation >> 24;
break;
case R_RL78_ABS24S_PCREL: case R_RL78_ABS16_REV:
case R_RL78_ABS24S: OP (1) = relocation;
RANGE (-0x800000, 0x7fffff); OP (0) = relocation >> 8;
OP (0) = relocation; break;
OP (1) = relocation >> 8;
OP (2) = relocation >> 16;
break;
case R_RL78_ABS16: case R_RL78_ABS16S_PCREL:
RANGE (-32768, 65535); case R_RL78_ABS16S:
OP (0) = relocation; OP (0) = relocation;
OP (1) = relocation >> 8; OP (1) = relocation >> 8;
break; break;
case R_RL78_ABS16_REV: case R_RL78_ABS16U:
RANGE (-32768, 65535); case R_RL78_ABS16UL:
OP (1) = relocation; case R_RL78_ABS16UW:
OP (0) = relocation >> 8; OP (0) = relocation;
break; OP (1) = relocation >> 8;
break;
case R_RL78_ABS16S_PCREL: case R_RL78_ABS8:
case R_RL78_ABS16S: OP (0) = relocation;
RANGE (-32768, 32767); break;
OP (0) = relocation;
OP (1) = relocation >> 8;
break;
case R_RL78_ABS16U: case R_RL78_ABS8U:
case R_RL78_ABS16UL: case R_RL78_ABS8UL:
case R_RL78_ABS16UW: case R_RL78_ABS8UW:
RANGE (0, 65536); OP (0) = relocation;
OP (0) = relocation; break;
OP (1) = relocation >> 8;
break;
case R_RL78_ABS8: case R_RL78_ABS8S_PCREL:
RANGE (-128, 255); case R_RL78_ABS8S:
OP (0) = relocation; OP (0) = relocation;
break; break;
case R_RL78_ABS8U: default:
case R_RL78_ABS8UL: break;
case R_RL78_ABS8UW: }
RANGE (0, 255); break;
OP (0) = relocation;
break;
case R_RL78_ABS8S_PCREL: case R_RL78_SYM:
case R_RL78_ABS8S: if (r_symndx < symtab_hdr->sh_info)
RANGE (-128, 127); relocation = sec->output_section->vma + sec->output_offset
OP (0) = relocation; + sym->st_value + rel->r_addend;
break; else if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
relocation = h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset
+ rel->r_addend;
else
{
relocation = 0;
if (h->root.type != bfd_link_hash_undefweak)
_bfd_error_handler
(_("warning: RL78_SYM reloc with an unknown symbol"));
}
(void) rl78_compute_complex_reloc (r_type, relocation, input_section,
&r, &error_message);
break;
default: case R_RL78_OPromtop:
break; relocation = get_romstart (info, input_bfd, input_section,
} rel->r_offset);
break; (void) rl78_compute_complex_reloc (r_type, relocation, input_section,
&r, &error_message);
break;
case R_RL78_SYM: case R_RL78_OPramtop:
if (r_symndx < symtab_hdr->sh_info) relocation = get_ramstart (info, input_bfd, input_section,
relocation = sec->output_section->vma + sec->output_offset rel->r_offset);
+ sym->st_value + rel->r_addend; (void) rl78_compute_complex_reloc (r_type, relocation, input_section,
else if (h != NULL &r, &error_message);
&& (h->root.type == bfd_link_hash_defined break;
|| h->root.type == bfd_link_hash_defweak))
relocation = h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset
+ rel->r_addend;
else
{
relocation = 0;
if (h->root.type != bfd_link_hash_undefweak)
_bfd_error_handler
(_("warning: RL78_SYM reloc with an unknown symbol"));
}
(void) rl78_compute_complex_reloc (r_type, relocation, input_section,
&r, &error_message);
break;
case R_RL78_OPromtop: default:
relocation = get_romstart (info, input_bfd, input_section, rel->r_offset); r = bfd_reloc_notsupported;
(void) rl78_compute_complex_reloc (r_type, relocation, input_section, break;
&r, &error_message); }
break;
case R_RL78_OPramtop: if (r == bfd_reloc_ok)
relocation = get_ramstart (info, input_bfd, input_section, rel->r_offset); r = check_overflow (howto, relocation);
(void) rl78_compute_complex_reloc (r_type, relocation, input_section,
&r, &error_message);
break;
default:
r = bfd_reloc_notsupported;
break;
}
if (r != bfd_reloc_ok) if (r != bfd_reloc_ok)
{ {