Add support to GDB for the Renesas rl78 architecture.
[external/binutils.git] / bfd / elf32-rx.c
index f049f6e..0ceed85 100644 (file)
@@ -32,6 +32,7 @@
    endian-swap we would otherwise get.  We check for this in
    rx_elf_object_p().  */
 const bfd_target bfd_elf32_rx_be_ns_vec;
+const bfd_target bfd_elf32_rx_be_vec;
 
 #ifdef DEBUG
 char * rx_get_reloc (long);
@@ -462,6 +463,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 +496,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 +564,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 +606,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 +627,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 +638,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 +650,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 +665,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 +677,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 +689,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 +707,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 +724,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 +739,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 +756,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 +771,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 +788,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 +968,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 +984,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 +1001,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 +1019,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 +1032,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 +1061,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 +1074,7 @@ rx_elf_relocate_section
          break;
 
        case R_RX_ABS16UL:
+         UNSAFE_FOR_PID;
          RX_STACK_POP (relocation);
          relocation >>= 2;
          RANGE (0, 65536);
@@ -1033,6 +1088,7 @@ rx_elf_relocate_section
          break;
 
        case R_RX_ABS16UW:
+         UNSAFE_FOR_PID;
          RX_STACK_POP (relocation);
          relocation >>= 1;
          RANGE (0, 65536);
@@ -1046,18 +1102,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 +1124,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 +1143,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 +1152,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 +1184,7 @@ rx_elf_relocate_section
          {
            int32_t tmp1, tmp2;
 
+           saw_subtract = TRUE;
            RX_STACK_POP (tmp1);
            RX_STACK_POP (tmp2);
            tmp2 -= tmp1;
@@ -1143,6 +1207,7 @@ rx_elf_relocate_section
          {
            int32_t tmp1, tmp2;
 
+           saw_subtract = TRUE;
            RX_STACK_POP (tmp1);
            RX_STACK_POP (tmp2);
            tmp1 /= tmp2;
@@ -2893,7 +2958,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)
        {
@@ -2964,6 +3029,7 @@ rx_elf_object_p (bfd * abfd)
   Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
   int nphdrs = elf_elfheader (abfd)->e_phnum;
   sec_ptr bsec;
+  static int saw_be = FALSE;
 
   /* We never want to automatically choose the non-swapping big-endian
      target.  The user can only get that explicitly, such as with -I
@@ -2972,6 +3038,15 @@ rx_elf_object_p (bfd * abfd)
       && abfd->target_defaulted)
     return FALSE;
 
+  /* BFD->target_defaulted is not set to TRUE when a target is chosen
+     as a fallback, so we check for "scanning" to know when to stop
+     using the non-swapping target.  */
+  if (abfd->xvec == &bfd_elf32_rx_be_ns_vec
+      && saw_be)
+    return FALSE;
+  if (abfd->xvec == &bfd_elf32_rx_be_vec)
+    saw_be = TRUE;
+
   bfd_default_set_arch_mach (abfd, bfd_arch_rx,
                             elf32_rx_machine (abfd));
 
@@ -3009,7 +3084,7 @@ rx_elf_object_p (bfd * abfd)
       bsec = abfd->sections;
       while (bsec)
        {
-         if (phdr[i].p_vaddr <= bsec->lma
+         if (phdr[i].p_vaddr <= bsec->vma
              && bsec->vma <= phdr[i].p_vaddr + (phdr[i].p_filesz - 1))
            {
              bsec->lma = phdr[i].p_paddr + (bsec->vma - phdr[i].p_vaddr);