diff --git a/bfd/elf32-rl78.c b/bfd/elf32-rl78.c index 70b49aa..ff3af7b 100644 --- a/bfd/elf32-rl78.c +++ b/bfd/elf32-rl78.c @@ -31,6 +31,14 @@ HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ 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; feel free to move them as needed to avoid conflicts with published relocation numbers. */ @@ -106,23 +114,23 @@ static reloc_howto_type rl78_elf_howto_table [] = EMPTY_HOWTO (0x3f), EMPTY_HOWTO (0x40), - RL78REL (ABS32, 2, 32, 0, dont, FALSE), - RL78REL (ABS24S, 2, 24, 0, signed, FALSE), - RL78REL (ABS16, 1, 16, 0, dont, FALSE), - RL78REL (ABS16U, 1, 16, 0, unsigned, FALSE), - RL78REL (ABS16S, 1, 16, 0, signed, FALSE), - RL78REL (ABS8, 0, 8, 0, dont, FALSE), - RL78REL (ABS8U, 0, 8, 0, unsigned, FALSE), - RL78REL (ABS8S, 0, 8, 0, signed, FALSE), - RL78REL (ABS24S_PCREL, 2, 24, 0, signed, TRUE), - RL78REL (ABS16S_PCREL, 1, 16, 0, signed, TRUE), - RL78REL (ABS8S_PCREL, 0, 8, 0, signed, TRUE), - RL78REL (ABS16UL, 1, 16, 0, unsigned, FALSE), - RL78REL (ABS16UW, 1, 16, 0, unsigned, FALSE), - RL78REL (ABS8UL, 0, 8, 0, unsigned, FALSE), - RL78REL (ABS8UW, 0, 8, 0, unsigned, FALSE), - RL78REL (ABS32_REV, 2, 32, 0, dont, FALSE), - RL78REL (ABS16_REV, 1, 16, 0, dont, FALSE), + RL78_OP_REL (ABS32, 2, 32, 0, dont, FALSE), + RL78_OP_REL (ABS24S, 2, 24, 0, signed, FALSE), + RL78_OP_REL (ABS16, 1, 16, 0, dont, FALSE), + RL78_OP_REL (ABS16U, 1, 16, 0, unsigned, FALSE), + RL78_OP_REL (ABS16S, 1, 16, 0, signed, FALSE), + RL78_OP_REL (ABS8, 0, 8, 0, dont, FALSE), + RL78_OP_REL (ABS8U, 0, 8, 0, unsigned, FALSE), + RL78_OP_REL (ABS8S, 0, 8, 0, signed, FALSE), + RL78_OP_REL (ABS24S_PCREL, 2, 24, 0, signed, TRUE), + RL78_OP_REL (ABS16S_PCREL, 1, 16, 0, signed, TRUE), + RL78_OP_REL (ABS8S_PCREL, 0, 8, 0, signed, TRUE), + RL78_OP_REL (ABS16UL, 1, 16, 0, unsigned, FALSE), + RL78_OP_REL (ABS16UW, 1, 16, 0, unsigned, FALSE), + RL78_OP_REL (ABS8UL, 0, 8, 0, unsigned, FALSE), + RL78_OP_REL (ABS8UW, 0, 8, 0, unsigned, FALSE), + RL78_OP_REL (ABS32_REV, 2, 32, 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) @@ -174,29 +182,29 @@ static reloc_howto_type rl78_elf_howto_table [] = EMPTY_HOWTO (0x7e), EMPTY_HOWTO (0x7f), - RL78REL (SYM, 2, 32, 0, dont, FALSE), - RL78REL (OPneg, 2, 32, 0, dont, FALSE), - RL78REL (OPadd, 2, 32, 0, dont, FALSE), - RL78REL (OPsub, 2, 32, 0, dont, FALSE), - RL78REL (OPmul, 2, 32, 0, dont, FALSE), - RL78REL (OPdiv, 2, 32, 0, dont, FALSE), - RL78REL (OPshla, 2, 32, 0, dont, FALSE), - RL78REL (OPshra, 2, 32, 0, dont, FALSE), - RL78REL (OPsctsize, 2, 32, 0, dont, FALSE), + RL78_OP_REL (SYM, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPneg, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPadd, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPsub, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPmul, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPdiv, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPshla, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPshra, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPsctsize, 2, 32, 0, dont, FALSE), EMPTY_HOWTO (0x89), EMPTY_HOWTO (0x8a), EMPTY_HOWTO (0x8b), EMPTY_HOWTO (0x8c), - RL78REL (OPscttop, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPscttop, 2, 32, 0, dont, FALSE), EMPTY_HOWTO (0x8e), EMPTY_HOWTO (0x8f), - RL78REL (OPand, 2, 32, 0, dont, FALSE), - RL78REL (OPor, 2, 32, 0, dont, FALSE), - RL78REL (OPxor, 2, 32, 0, dont, FALSE), - RL78REL (OPnot, 2, 32, 0, dont, FALSE), - RL78REL (OPmod, 2, 32, 0, dont, FALSE), - RL78REL (OPromtop, 2, 32, 0, dont, FALSE), - RL78REL (OPramtop, 2, 32, 0, dont, FALSE) + RL78_OP_REL (OPand, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPor, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPxor, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPnot, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPmod, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPromtop, 2, 32, 0, dont, FALSE), + RL78_OP_REL (OPramtop, 2, 32, 0, dont, FALSE) }; /* Map BFD reloc types to RL78 ELF reloc types. */ @@ -292,22 +300,29 @@ get_symbol_value (const char * name, asection * input_section, int offset) { - bfd_vma value = 0; struct bfd_link_hash_entry * h; + if (info == NULL) + return 0; + h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); if (h == NULL || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)) - * status = info->callbacks->undefined_symbol - (info, name, input_bfd, input_section, offset, TRUE); - else - value = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); + { + bfd_reloc_status_type res; + + res = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, offset, TRUE); + if (status) + * status = res; + return 0; + } - return value; + return (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); } static bfd_vma @@ -319,12 +334,15 @@ get_romstart (bfd_reloc_status_type * status, { static bfd_boolean cached = FALSE; static bfd_vma cached_value = 0; + static bfd_reloc_status_type cached_status; 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; } + if (status) + * status = cached_status; return cached_value; } @@ -337,12 +355,15 @@ get_ramstart (bfd_reloc_status_type * status, { static bfd_boolean cached = FALSE; static bfd_vma cached_value = 0; + static bfd_reloc_status_type cached_status; 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; } + if (status) + * status = cached_status; return cached_value; } @@ -356,7 +377,7 @@ static unsigned int rl78_stack_top; if (rl78_stack_top < NUM_STACK_ENTRIES) \ rl78_stack [rl78_stack_top ++] = (val); \ else \ - r = bfd_reloc_dangerous; \ + _bfd_error_handler (_("Internal Error: RL78 reloc stack overflow")); \ } \ while (0) @@ -364,12 +385,269 @@ static unsigned int rl78_stack_top; do \ { \ if (rl78_stack_top > 0) \ - (dest) = rl78_stack [-- rl78_stack_top]; \ + (dest) = rl78_stack [-- rl78_stack_top];\ else \ - (dest) = 0, r = bfd_reloc_dangerous; \ + { \ + _bfd_error_handler (_("Internal Error: RL78 reloc stack underflow")); \ + (dest) = 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. 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], @@ -559,8 +837,6 @@ rl78_elf_relocate_section r = bfd_reloc_ok; #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. */ switch (r_type) @@ -663,279 +939,141 @@ rl78_elf_relocate_section break; /* Complex reloc handling: */ - case R_RL78_ABS32: - RL78_STACK_POP (relocation); - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; - break; - case R_RL78_ABS32_REV: - RL78_STACK_POP (relocation); - 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: - RL78_STACK_POP (relocation); - RANGE (-0x800000, 0x7fffff); - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - break; - case R_RL78_ABS16: - RL78_STACK_POP (relocation); - RANGE (-32768, 65535); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - case R_RL78_ABS16_REV: - RL78_STACK_POP (relocation); - RANGE (-32768, 65535); - OP (1) = relocation; - OP (0) = relocation >> 8; - break; - case R_RL78_ABS16S_PCREL: case R_RL78_ABS16S: - RL78_STACK_POP (relocation); - RANGE (-32768, 32767); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - case R_RL78_ABS16U: - RL78_STACK_POP (relocation); - RANGE (0, 65536); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - 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: - RL78_STACK_POP (relocation); - relocation >>= 1; - RANGE (0, 65536); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - case R_RL78_ABS8: - RL78_STACK_POP (relocation); - RANGE (-128, 255); - OP (0) = relocation; - break; - case R_RL78_ABS8U: - RL78_STACK_POP (relocation); - RANGE (0, 255); - OP (0) = relocation; - break; - case R_RL78_ABS8UL: - RL78_STACK_POP (relocation); - relocation >>= 2; - RANGE (0, 255); - OP (0) = relocation; - break; - case R_RL78_ABS8UW: - RL78_STACK_POP (relocation); - relocation >>= 1; - RANGE (0, 255); - OP (0) = relocation; - break; - case R_RL78_ABS8S_PCREL: case R_RL78_ABS8S: - RL78_STACK_POP (relocation); - RANGE (-128, 127); - OP (0) = relocation; - break; - - case R_RL78_SYM: - if (r_symndx < symtab_hdr->sh_info) - RL78_STACK_PUSH (sec->output_section->vma - + sec->output_offset - + sym->st_value - + rel->r_addend); - else - { - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - RL78_STACK_PUSH (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset - + rel->r_addend); - else if (h->root.type == bfd_link_hash_undefweak) - RL78_STACK_PUSH (0); - else - _bfd_error_handler (_("Warning: RL78_SYM reloc with an unknown symbol")); - } - break; - 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; + 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); - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 &= tmp2; - RL78_STACK_PUSH (tmp1); - } - break; + 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_OPor: - { - int32_t tmp1, tmp2; + case R_RL78_ABS32_REV: + OP (3) = relocation; + OP (2) = relocation >> 8; + OP (1) = relocation >> 16; + OP (0) = relocation >> 24; + break; - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 |= tmp2; - RL78_STACK_PUSH (tmp1); - } - break; + case R_RL78_ABS24S_PCREL: + case R_RL78_ABS24S: + RANGE (-0x800000, 0x7fffff); + OP (0) = relocation; + OP (1) = relocation >> 8; + OP (2) = relocation >> 16; + break; - case R_RL78_OPxor: - { - int32_t tmp1, tmp2; + case R_RL78_ABS16: + RANGE (-32768, 65535); + OP (0) = relocation; + OP (1) = relocation >> 8; + break; - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 ^= tmp2; - RL78_STACK_PUSH (tmp1); - } - break; + case R_RL78_ABS16_REV: + RANGE (-32768, 65535); + OP (1) = relocation; + OP (0) = relocation >> 8; + break; - case R_RL78_OPnot: - { - int32_t tmp; + case R_RL78_ABS16S_PCREL: + case R_RL78_ABS16S: + RANGE (-32768, 32767); + OP (0) = relocation; + OP (1) = relocation >> 8; + break; - RL78_STACK_POP (tmp); - tmp = ~ tmp; - RL78_STACK_PUSH (tmp); - } - break; + case R_RL78_ABS16U: + case R_RL78_ABS16UL: + case R_RL78_ABS16UW: + RANGE (0, 65536); + OP (0) = relocation; + OP (1) = relocation >> 8; + break; - case R_RL78_OPmod: - { - int32_t tmp1, tmp2; + case R_RL78_ABS8: + RANGE (-128, 255); + OP (0) = relocation; + break; - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 %= tmp2; - RL78_STACK_PUSH (tmp1); - } + case R_RL78_ABS8U: + case R_RL78_ABS8UL: + case R_RL78_ABS8UW: + RANGE (0, 255); + OP (0) = relocation; + break; + + case R_RL78_ABS8S_PCREL: + case R_RL78_ABS8S: + RANGE (-128, 127); + OP (0) = relocation; + break; + + default: + break; + } + break; + + case R_RL78_SYM: + if (r_symndx < symtab_hdr->sh_info) + relocation = sec->output_section->vma + sec->output_offset + + sym->st_value + rel->r_addend; + 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); break; 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; 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; default: @@ -1688,22 +1826,21 @@ reloc_bubblesort (Elf_Internal_Rela * r, int count) #define OFFSET_FOR_RELOC(rel, lrel, scale) \ rl78_offset_for_reloc (abfd, rel + 1, symtab_hdr, shndx_buf, intsyms, \ - lrel, abfd, sec, link_info, scale) + lrel, abfd, sec, link_info, scale) static bfd_vma rl78_offset_for_reloc (bfd * abfd, - Elf_Internal_Rela * rel, - Elf_Internal_Shdr * symtab_hdr, - Elf_External_Sym_Shndx * shndx_buf ATTRIBUTE_UNUSED, - Elf_Internal_Sym * intsyms, - Elf_Internal_Rela ** lrel, - bfd * input_bfd, - asection * input_section, - struct bfd_link_info * info, - int * scale) + Elf_Internal_Rela * rel, + Elf_Internal_Shdr * symtab_hdr, + Elf_External_Sym_Shndx * shndx_buf ATTRIBUTE_UNUSED, + Elf_Internal_Sym * intsyms, + Elf_Internal_Rela ** lrel, + bfd * input_bfd, + asection * input_section, + struct bfd_link_info * info, + int * scale) { bfd_vma symval; - bfd_reloc_status_type r; *scale = 1; @@ -1712,7 +1849,7 @@ rl78_offset_for_reloc (bfd * abfd, gets a pointer to the last relocation used. */ while (1) { - int32_t tmp1, tmp2; + unsigned long r_type; /* Get the value of the symbol referred to by the reloc. */ 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; } - switch (ELF32_R_TYPE (rel->r_info)) + r_type = ELF32_R_TYPE (rel->r_info); + switch (r_type) { 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); + case R_RL78_OPromtop: + symval = get_romstart (NULL, info, input_bfd, input_section, rel->r_offset); + (void) rl78_compute_complex_reloc (r_type, symval, input_section); break; - case R_RL78_OPadd: - RL78_STACK_POP (tmp1); - RL78_STACK_POP (tmp2); - tmp1 += tmp2; - RL78_STACK_PUSH (tmp1); + case R_RL78_OPramtop: + 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: - 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; - - case R_RL78_OPromtop: - RL78_STACK_PUSH (get_romstart (&r, info, input_bfd, input_section, rel->r_offset)); - break; - - case R_RL78_OPramtop: - RL78_STACK_PUSH (get_ramstart (&r, info, input_bfd, input_section, rel->r_offset)); + (void) rl78_compute_complex_reloc (r_type, 0, input_section); break; case R_RL78_DIR16UL: case R_RL78_DIR8UL: case R_RL78_ABS16UL: case R_RL78_ABS8UL: - if (rl78_stack_top) - RL78_STACK_POP (symval); - if (lrel) - *lrel = rel; *scale = 4; - return symval; + goto reloc_computes_value; case R_RL78_DIR16UW: case R_RL78_DIR8UW: case R_RL78_ABS16UW: case R_RL78_ABS8UW: - if (rl78_stack_top) - RL78_STACK_POP (symval); - if (lrel) - *lrel = rel; *scale = 2; - return symval; - + goto reloc_computes_value; + default: - if (rl78_stack_top) - RL78_STACK_POP (symval); + reloc_computes_value: + symval = rl78_compute_complex_reloc (r_type, 0, input_section); if (lrel) *lrel = rel; return symval; diff --git a/binutils/readelf.c b/binutils/readelf.c index ca25136..1533806 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -11161,6 +11161,42 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, } 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; diff --git a/gas/config/tc-rl78.c b/gas/config/tc-rl78.c index 337b819..b5f0563 100644 --- a/gas/config/tc-rl78.c +++ b/gas/config/tc-rl78.c @@ -340,15 +340,16 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED) } void -md_show_usage (FILE * stream ATTRIBUTE_UNUSED) +md_show_usage (FILE * stream) { 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, _(" --mg13 Selects the G13 core.\n")); fprintf (stream, _(" --mg14 Selects the G14 core [default]\n")); fprintf (stream, _(" --mrl78 Alias for --mg14\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 @@ -662,13 +663,23 @@ rl78_cons_fix_new (fragS * frag, case BFD_RELOC_RL78_LO16: case BFD_RELOC_RL78_HI16: if (size != 2) - as_bad (_("%%hi16/%%lo16 only applies to .short or .hword")); - type = exp->X_md; + { + /* 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")); + } + else + type = exp->X_md; break; case BFD_RELOC_RL78_HI8: if (size != 1) - as_bad (_("%%hi8 only applies to .byte")); - type = exp->X_md; + { + /* Fixups to assembler generated expressions do not use %hi or %lo. */ + if (frag->fr_file) + as_bad (_("%%hi8 only applies to .byte")); + } + else + type = exp->X_md; break; default: break; @@ -823,7 +834,7 @@ rl78_frag_fix_value (fragS * fragP, /* Estimate how big the opcode is after this relax pass. The return 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, - sowe only need to subtract fx_fix and return it. */ + so we only need to subtract fx_fix and return it. */ int md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED) @@ -960,8 +971,8 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) fragP->fr_subtype = newsize; tprintf (" -> new %d old %d delta %d\n", newsize, oldsize, newsize-oldsize); return newsize - oldsize; - } - +} + /* This lets us test for the opcode type and the desired size in a switch statement. */ #define OPCODE(type,size) ((type) * 16 + (size)) diff --git a/gas/config/tc-rl78.h b/gas/config/tc-rl78.h index e2b9699..b9ede61 100644 --- a/gas/config/tc-rl78.h +++ b/gas/config/tc-rl78.h @@ -85,3 +85,17 @@ extern void rl78_elf_final_processing (void); #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ ((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 diff --git a/gas/testsuite/gas/lns/lns.exp b/gas/testsuite/gas/lns/lns.exp index b72c536..96aaffd 100644 --- a/gas/testsuite/gas/lns/lns.exp +++ b/gas/testsuite/gas/lns/lns.exp @@ -32,13 +32,14 @@ if { && ![istarget s390*-*-*] } { # Use alternate file for targets using DW_LNS_fixed_advance_pc opcodes. - if { [istarget xtensa*-*-*] - || [istarget am3*-*-*] + if { [istarget am3*-*-*] || [istarget cr16-*-*] || [istarget crx-*-*] + || [istarget mn10*-*-*] || [istarget msp430-*-*] || [istarget nds32*-*-*] - || [istarget mn10*-*-*] } { + || [istarget rl78-*-*] + || [istarget xtensa*-*-*] } { run_dump_test "lns-common-1-alt" run_dump_test "lns-big-delta" } elseif { [istarget ia64*-*-*] } {