summaryrefslogtreecommitdiff
path: root/bfd/elf32-rx.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2011-10-05 14:13:24 +0000
committerNick Clifton <nickc@redhat.com>2011-10-05 14:13:24 +0000
commitb7bfdfcc729e11b745f1884926b616a4dd95f60c (patch)
tree2a18a32ae5a527ed0f64bb6d99fa0403d62b98d1 /bfd/elf32-rx.c
parent33977ea14d6571313dc312ea3eb7c3412a4564dc (diff)
downloadbinutils-redhat-b7bfdfcc729e11b745f1884926b616a4dd95f60c.tar.gz
* readelf.c (get_machine_dlags): Add support for RX's PID mode.
* ld-scripts/phdrs.exp: Expect to fail for the RX. * elf32-rx.c: Add support for PID mode. (rx_elf_relocate_section): Add checks for unsafe PID relocations. Include addend in R_RX_SYM relocations. * config/rx-defs.h (rx_pid_register): New. (rx_gp_register): New. * config/rx-parse.y (rx_lex): Add support for %gpreg and %pidreg. (displacement): Add PID support. * config/tc-rx.c (rx_pid_mode): New. (rx_num_int_regs): New. (rx_pid_register): New. (rx_gp_register): New. (options): Add -mpid and -mint-register= options. (md_longopts): Likewise. (md_parse_option): Likewise. (md_show_usage): Likewise. (rx_pid_symbol): New. (rx_pidreg_symbol): New. (rx_gpreg_symbol): New. (md_begin): Support PID. (rx_validate_fix_sub): Support PID. (tc_gen_reloc): Support PID. * doc/c-rx.texi: Document PID support. * rx.h (E_FLAG_RX_PID): New.
Diffstat (limited to 'bfd/elf32-rx.c')
-rw-r--r--bfd/elf32-rx.c72
1 files changed, 68 insertions, 4 deletions
diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c
index f049f6e339..99cffc0e00 100644
--- a/bfd/elf32-rx.c
+++ b/bfd/elf32-rx.c
@@ -462,6 +462,13 @@ rx_elf_relocate_section
struct elf_link_hash_entry ** sym_hashes;
Elf_Internal_Rela * rel;
Elf_Internal_Rela * relend;
+ bfd_boolean pid_mode;
+ bfd_boolean saw_subtract = FALSE;
+
+ if (elf_elfheader (output_bfd)->e_flags & E_FLAG_RX_PID)
+ pid_mode = TRUE;
+ else
+ pid_mode = FALSE;
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
@@ -488,6 +495,9 @@ rx_elf_relocate_section
sec = NULL;
relocation = 0;
+ if (rx_stack_top == 0)
+ saw_subtract = FALSE;
+
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
@@ -553,6 +563,28 @@ rx_elf_relocate_section
_bfd_error_handler (_("%B:%A: Warning: deprecated Red Hat reloc " type " detected against: %s."), \
input_bfd, input_section, name)
+ /* Check for unsafe relocs in PID mode. These are any relocs where
+ an absolute address is being computed. There are special cases
+ for relocs against symbols that are known to be referenced in
+ crt0.o before the PID base address register has been initialised. */
+#define UNSAFE_FOR_PID \
+ do \
+ { \
+ if (pid_mode \
+ && sec != NULL \
+ && sec->flags & SEC_READONLY \
+ && !(input_section->flags & SEC_DEBUGGING) \
+ && strcmp (name, "__pid_base") != 0 \
+ && strcmp (name, "__gp") != 0 \
+ && strcmp (name, "__romdatastart") != 0 \
+ && !saw_subtract) \
+ _bfd_error_handler (_("%B(%A): unsafe PID relocation %s at 0x%08lx (against %s in %s)"), \
+ input_bfd, input_section, howto->name, \
+ input_section->output_section->vma + input_section->output_offset + rel->r_offset, \
+ name, sec->name); \
+ } \
+ while (0)
+
/* Opcode relocs are always big endian. Data relocs are bi-endian. */
switch (r_type)
{
@@ -573,16 +605,19 @@ rx_elf_relocate_section
WARN_REDHAT ("RX_RH_8_NEG");
relocation = - relocation;
case R_RX_DIR8S_PCREL:
+ UNSAFE_FOR_PID;
RANGE (-128, 127);
OP (0) = relocation;
break;
case R_RX_DIR8S:
+ UNSAFE_FOR_PID;
RANGE (-128, 255);
OP (0) = relocation;
break;
case R_RX_DIR8U:
+ UNSAFE_FOR_PID;
RANGE (0, 255);
OP (0) = relocation;
break;
@@ -591,6 +626,7 @@ rx_elf_relocate_section
WARN_REDHAT ("RX_RH_16_NEG");
relocation = - relocation;
case R_RX_DIR16S_PCREL:
+ UNSAFE_FOR_PID;
RANGE (-32768, 32767);
#if RX_OPCODE_BIG_ENDIAN
#else
@@ -601,6 +637,7 @@ rx_elf_relocate_section
case R_RX_RH_16_OP:
WARN_REDHAT ("RX_RH_16_OP");
+ UNSAFE_FOR_PID;
RANGE (-32768, 32767);
#if RX_OPCODE_BIG_ENDIAN
OP (1) = relocation;
@@ -612,6 +649,7 @@ rx_elf_relocate_section
break;
case R_RX_DIR16S:
+ UNSAFE_FOR_PID;
RANGE (-32768, 65535);
if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE))
{
@@ -626,6 +664,7 @@ rx_elf_relocate_section
break;
case R_RX_DIR16U:
+ UNSAFE_FOR_PID;
RANGE (0, 65536);
#if RX_OPCODE_BIG_ENDIAN
OP (1) = relocation;
@@ -637,6 +676,7 @@ rx_elf_relocate_section
break;
case R_RX_DIR16:
+ UNSAFE_FOR_PID;
RANGE (-32768, 65536);
#if RX_OPCODE_BIG_ENDIAN
OP (1) = relocation;
@@ -648,6 +688,7 @@ rx_elf_relocate_section
break;
case R_RX_DIR16_REV:
+ UNSAFE_FOR_PID;
RANGE (-32768, 65536);
#if RX_OPCODE_BIG_ENDIAN
OP (0) = relocation;
@@ -665,6 +706,7 @@ rx_elf_relocate_section
break;
case R_RX_RH_24_NEG:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_24_NEG");
relocation = - relocation;
case R_RX_DIR24S_PCREL:
@@ -681,6 +723,7 @@ rx_elf_relocate_section
break;
case R_RX_RH_24_OP:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_24_OP");
RANGE (-0x800000, 0x7fffff);
#if RX_OPCODE_BIG_ENDIAN
@@ -695,6 +738,7 @@ rx_elf_relocate_section
break;
case R_RX_DIR24S:
+ UNSAFE_FOR_PID;
RANGE (-0x800000, 0x7fffff);
if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE))
{
@@ -711,6 +755,7 @@ rx_elf_relocate_section
break;
case R_RX_RH_24_UNS:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_24_UNS");
RANGE (0, 0xffffff);
#if RX_OPCODE_BIG_ENDIAN
@@ -725,6 +770,7 @@ rx_elf_relocate_section
break;
case R_RX_RH_32_NEG:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_32_NEG");
relocation = - relocation;
#if RX_OPCODE_BIG_ENDIAN
@@ -741,6 +787,7 @@ rx_elf_relocate_section
break;
case R_RX_RH_32_OP:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_32_OP");
#if RX_OPCODE_BIG_ENDIAN
OP (3) = relocation;
@@ -920,6 +967,7 @@ rx_elf_relocate_section
/* Complex reloc handling: */
case R_RX_ABS32:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
#if RX_OPCODE_BIG_ENDIAN
OP (3) = relocation;
@@ -935,6 +983,7 @@ rx_elf_relocate_section
break;
case R_RX_ABS32_REV:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
#if RX_OPCODE_BIG_ENDIAN
OP (0) = relocation;
@@ -951,6 +1000,7 @@ rx_elf_relocate_section
case R_RX_ABS24S_PCREL:
case R_RX_ABS24S:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-0x800000, 0x7fffff);
if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE))
@@ -968,6 +1018,7 @@ rx_elf_relocate_section
break;
case R_RX_ABS16:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-32768, 65535);
#if RX_OPCODE_BIG_ENDIAN
@@ -980,6 +1031,7 @@ rx_elf_relocate_section
break;
case R_RX_ABS16_REV:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-32768, 65535);
#if RX_OPCODE_BIG_ENDIAN
@@ -1008,6 +1060,7 @@ rx_elf_relocate_section
break;
case R_RX_ABS16U:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (0, 65536);
#if RX_OPCODE_BIG_ENDIAN
@@ -1020,6 +1073,7 @@ rx_elf_relocate_section
break;
case R_RX_ABS16UL:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 2;
RANGE (0, 65536);
@@ -1033,6 +1087,7 @@ rx_elf_relocate_section
break;
case R_RX_ABS16UW:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 1;
RANGE (0, 65536);
@@ -1046,18 +1101,21 @@ rx_elf_relocate_section
break;
case R_RX_ABS8:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-128, 255);
OP (0) = relocation;
break;
case R_RX_ABS8U:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (0, 255);
OP (0) = relocation;
break;
case R_RX_ABS8UL:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 2;
RANGE (0, 255);
@@ -1065,14 +1123,16 @@ rx_elf_relocate_section
break;
case R_RX_ABS8UW:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 1;
RANGE (0, 255);
OP (0) = relocation;
break;
- case R_RX_ABS8S_PCREL:
case R_RX_ABS8S:
+ UNSAFE_FOR_PID;
+ case R_RX_ABS8S_PCREL:
RX_STACK_POP (relocation);
RANGE (-128, 127);
OP (0) = relocation;
@@ -1082,7 +1142,8 @@ rx_elf_relocate_section
if (r_symndx < symtab_hdr->sh_info)
RX_STACK_PUSH (sec->output_section->vma
+ sec->output_offset
- + sym->st_value);
+ + sym->st_value
+ + rel->r_addend);
else
{
if (h != NULL
@@ -1090,7 +1151,8 @@ rx_elf_relocate_section
|| h->root.type == bfd_link_hash_defweak))
RX_STACK_PUSH (h->root.u.def.value
+ sec->output_section->vma
- + sec->output_offset);
+ + sec->output_offset
+ + rel->r_addend);
else
_bfd_error_handler (_("Warning: RX_SYM reloc with an unknown symbol"));
}
@@ -1121,6 +1183,7 @@ rx_elf_relocate_section
{
int32_t tmp1, tmp2;
+ saw_subtract = TRUE;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
tmp2 -= tmp1;
@@ -1143,6 +1206,7 @@ rx_elf_relocate_section
{
int32_t tmp1, tmp2;
+ saw_subtract = TRUE;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
tmp1 /= tmp2;
@@ -2893,7 +2957,7 @@ rx_elf_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
}
else if (old_flags != new_flags)
{
- flagword known_flags = E_FLAG_RX_64BIT_DOUBLES | E_FLAG_RX_DSP;
+ flagword known_flags = E_FLAG_RX_64BIT_DOUBLES | E_FLAG_RX_DSP | E_FLAG_RX_PID;
if ((old_flags ^ new_flags) & known_flags)
{