[ARC] ARC_PC32 dynamic reloc incorrectly generated.
[deliverable/binutils-gdb.git] / bfd / elf32-arc.c
index 5f1505e7e987de60eb10b3c17e3c26b701ff178b..b1a1697f4c19359a249f5d88dbb99a7650fe42ab 100644 (file)
 #include "opcode/arc.h"
 #include "arc-plt.h"
 
+#define FEATURE_LIST_NAME bfd_feature_list
+#define CONFLICT_LIST bfd_conflict_list
+#include "opcode/arc-attrs.h"
+
 /* #define ARC_ENABLE_DEBUG 1  */
 #ifdef ARC_ENABLE_DEBUG
 static const char *
@@ -51,17 +55,20 @@ name_for_global_symbol (struct elf_link_hash_entry *h)
     Elf_Internal_Rela _rel;                                            \
     bfd_byte * _loc;                                                   \
                                                                        \
-    BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \
-    _loc = _htab->srel##SECTION->contents                              \
-      + ((_htab->srel##SECTION->reloc_count)                           \
-        * sizeof (Elf32_External_Rela));                               \
-    _htab->srel##SECTION->reloc_count++;                               \
-    _rel.r_addend = ADDEND;                                            \
-    _rel.r_offset = (_htab->s##SECTION)->output_section->vma           \
-      + (_htab->s##SECTION)->output_offset + OFFSET;                   \
-    BFD_ASSERT ((long) SYM_IDX != -1);                                 \
-    _rel.r_info = ELF32_R_INFO (SYM_IDX, TYPE);                                \
-    bfd_elf32_swap_reloca_out (BFD, &_rel, _loc);                      \
+    if (_htab->dynamic_sections_created == TRUE)                               \
+      {                                                                        \
+       BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \
+       _loc = _htab->srel##SECTION->contents                           \
+         + ((_htab->srel##SECTION->reloc_count)                        \
+            * sizeof (Elf32_External_Rela));                           \
+       _htab->srel##SECTION->reloc_count++;                            \
+       _rel.r_addend = ADDEND;                                         \
+       _rel.r_offset = (_htab->s##SECTION)->output_section->vma        \
+         + (_htab->s##SECTION)->output_offset + OFFSET;                \
+       BFD_ASSERT ((long) SYM_IDX != -1);                              \
+       _rel.r_info = ELF32_R_INFO (SYM_IDX, TYPE);                     \
+       bfd_elf32_swap_reloca_out (BFD, &_rel, _loc);                   \
+      }                                                                        \
   }
 
 
@@ -442,8 +449,9 @@ arc_elf_print_private_bfd_data (bfd *abfd, void * ptr)
     case E_ARC_OSABI_ORIG : fprintf (file, " (ABI:legacy)"); break;
     case E_ARC_OSABI_V2   : fprintf (file, " (ABI:v2)");     break;
     case E_ARC_OSABI_V3   : fprintf (file, " (ABI:v3)");     break;
+    case E_ARC_OSABI_V4   : fprintf (file, " (ABI:v4)");     break;
     default:
-      fprintf (file, "(ABI:unknown)");
+      fprintf (file, " (ABI:unknown)");
       break;
     }
 
@@ -500,6 +508,305 @@ arc_info_to_howto_rel (bfd * abfd ATTRIBUTE_UNUSED,
   cache_ptr->howto = arc_elf_howto (r_type);
 }
 
+/* Extract CPU features from an NTBS.  */
+
+static unsigned
+arc_extract_features (const char *p)
+{
+  unsigned i, r = 0;
+
+  if (!p)
+    return 0;
+
+  for (i = 0; i < ARRAY_SIZE (bfd_feature_list); i++)
+    {
+      char *t = strstr (p, bfd_feature_list[i].attr);
+      unsigned l = strlen (bfd_feature_list[i].attr);
+      if ((t != NULL)
+         && (t[l] == ','
+             || t[l] == '\0'))
+       r |= bfd_feature_list[i].feature;
+    }
+
+  return r;
+}
+
+/* Concatenate two strings.  s1 can be NULL but not
+   s2.  */
+
+static char *
+arc_stralloc (char * s1, const char * s2)
+{
+  char *p;
+
+  /* Only s1 can be null.  */
+  BFD_ASSERT (s2);
+
+  p = s1 ? concat (s1, ",", s2, NULL) : (char *)s2;
+
+  return p;
+}
+
+/* Merge ARC object attributes from IBFD into OBFD.  Raise an error if
+   there are conflicting attributes.  */
+
+static bfd_boolean
+arc_elf_merge_attributes (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd = info->output_bfd;
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  int i;
+  bfd_boolean result = TRUE;
+  const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section;
+  char *tagname = NULL;
+
+  /* Skip the linker stubs file.  This preserves previous behavior
+     of accepting unknown attributes in the first input file - but
+     is that a bug?  */
+  if (ibfd->flags & BFD_LINKER_CREATED)
+    return TRUE;
+
+  /* Skip any input that hasn't attribute section.
+     This enables to link object files without attribute section with
+     any others.  */
+  if (bfd_get_section_by_name (ibfd, sec_name) == NULL)
+    return TRUE;
+
+  if (!elf_known_obj_attributes_proc (obfd)[0].i)
+    {
+      /* This is the first object.  Copy the attributes.  */
+      _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+      out_attr = elf_known_obj_attributes_proc (obfd);
+
+      /* Use the Tag_null value to indicate the attributes have been
+        initialized.  */
+      out_attr[0].i = 1;
+
+      return TRUE;
+    }
+
+  in_attr = elf_known_obj_attributes_proc (ibfd);
+  out_attr = elf_known_obj_attributes_proc (obfd);
+
+  for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+    {
+      /* Merge this attribute with existing attributes.  */
+      switch (i)
+       {
+       case Tag_ARC_PCS_config:
+         if (out_attr[i].i == 0)
+           out_attr[i].i = in_attr[i].i;
+         else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i)
+           {
+             const char *tagval[] = { "Absent", "Bare-metal/mwdt",
+                                       "Bare-metal/newlib", "Linux/uclibc",
+                                       "Linux/glibc" };
+             BFD_ASSERT (in_attr[i].i < 5);
+             BFD_ASSERT (out_attr[i].i < 5);
+             /* It's sometimes ok to mix different configs, so this is only
+                a warning.  */
+             _bfd_error_handler
+               (_("Warning: %B: Conflicting platform configuration "
+                  "%s with %s.\n"), ibfd,
+                tagval[in_attr[i].i],
+                tagval[out_attr[i].i]);
+           }
+         break;
+
+       case Tag_ARC_CPU_base:
+         if (out_attr[i].i == 0)
+           out_attr[i].i = in_attr[i].i;
+         else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i
+                  && ((out_attr[i].i + in_attr[i].i) < 6))
+           {
+             const char *tagval[] = { "Absent", "ARC6xx", "ARC7xx",
+                                       "ARCEM", "ARCHS" };
+             BFD_ASSERT (in_attr[i].i < 5);
+             BFD_ASSERT (out_attr[i].i < 5);
+             /* We cannot mix code for different CPUs.  */
+             _bfd_error_handler
+               (_("error: %B: unable to merge CPU base attributes "
+                  "%s with %s.\n"),
+                obfd,
+                tagval[in_attr[i].i],
+                tagval[out_attr[i].i]);
+             result = FALSE;
+             break;
+           }
+         else
+           {
+             /* The CPUs may be different, check if we can still mix
+                the objects against the output choosen CPU.  */
+             unsigned in_feature = 0;
+             unsigned out_feature = 0;
+             char *p1 = in_attr[Tag_ARC_ISA_config].s;
+             char *p2 = out_attr[Tag_ARC_ISA_config].s;
+             unsigned j;
+             unsigned cpu_out;
+             unsigned opcode_map[] = {0, ARC_OPCODE_ARC600, ARC_OPCODE_ARC700,
+                                      ARC_OPCODE_ARCv2EM, ARC_OPCODE_ARCv2HS};
+
+             BFD_ASSERT (in_attr[i].i < (sizeof (opcode_map)
+                                         / sizeof (unsigned)));
+             BFD_ASSERT (out_attr[i].i < (sizeof (opcode_map)
+                                          / sizeof (unsigned)));
+             cpu_out = opcode_map[out_attr[i].i];
+
+             in_feature = arc_extract_features (p1);
+             out_feature = arc_extract_features (p2);
+
+             /* First, check if a feature is compatible with the
+                output object chosen CPU.  */
+             for (j = 0; j < ARRAY_SIZE (bfd_feature_list); j++)
+               if (((in_feature | out_feature) & bfd_feature_list[j].feature)
+                   && (!(cpu_out & bfd_feature_list[j].cpus)))
+                 {
+                   _bfd_error_handler
+                     (_("error: %B: unable to merge ISA extension attributes "
+                        "%s.\n"),
+                      obfd, bfd_feature_list[j].name);
+                   result = FALSE;
+                   break;
+                 }
+             /* Second, if we have compatible features with the
+                chosen CPU, check if they are compatible among
+                them.  */
+             for (j = 0; j < ARRAY_SIZE (bfd_conflict_list); j++)
+               if (((in_feature | out_feature) & bfd_conflict_list[j])
+                   == bfd_conflict_list[j])
+                 {
+                   unsigned k;
+                   for (k = 0; k < ARRAY_SIZE (bfd_feature_list); k++)
+                     {
+                       if (in_feature &  bfd_feature_list[k].feature
+                           & bfd_conflict_list[j])
+                         p1 = (char *) bfd_feature_list[k].name;
+                       if (out_feature &  bfd_feature_list[k].feature
+                           & bfd_conflict_list[j])
+                         p2 = (char *) bfd_feature_list[k].name;
+                     }
+                   _bfd_error_handler
+                     (_("error: %B: conflicting ISA extension attributes "
+                        "%s with %s.\n"),
+                      obfd, p1, p2);
+                   result = FALSE;
+                   break;
+                 }
+             /* Everithing is alright.  */
+             out_feature |= in_feature;
+             p1 = NULL;
+             for (j = 0; j < ARRAY_SIZE (bfd_feature_list); j++)
+               if (out_feature & bfd_feature_list[j].feature)
+                 p1 = arc_stralloc (p1, bfd_feature_list[j].attr);
+             if (p1)
+               out_attr[Tag_ARC_ISA_config].s =
+                 _bfd_elf_attr_strdup (obfd, p1);
+           }
+         /* Fall through.  */
+       case Tag_ARC_CPU_variation:
+       case Tag_ARC_ISA_mpy_option:
+       case Tag_ARC_ABI_osver:
+         /* Use the largest value specified.  */
+         if (in_attr[i].i > out_attr[i].i)
+           out_attr[i].i = in_attr[i].i;
+         break;
+
+       case Tag_ARC_CPU_name:
+         break;
+
+       case Tag_ARC_ABI_rf16:
+         if (out_attr[i].i == 0)
+           out_attr[i].i = in_attr[i].i;
+         else if (out_attr[i].i != in_attr[i].i)
+           {
+             /* We cannot mix code with rf16 and without.  */
+             _bfd_error_handler
+               (_("error: %B: cannot mix rf16 with full register set %B.\n"),
+                obfd, ibfd);
+             result = FALSE;
+           }
+         break;
+
+       case Tag_ARC_ABI_pic:
+         tagname = "PIC";
+         /* fall through */
+       case Tag_ARC_ABI_sda:
+         if (!tagname)
+           tagname = "SDA";
+         /* fall through */
+       case Tag_ARC_ABI_tls:
+         {
+           const char *tagval[] = { "Absent", "MWDT", "GNU" };
+
+           if (!tagname)
+             tagname = "TLS";
+
+           BFD_ASSERT (in_attr[i].i < 3);
+           BFD_ASSERT (out_attr[i].i < 3);
+           if (out_attr[i].i != 0 && in_attr[i].i != 0
+               && out_attr[i].i != in_attr[i].i)
+             {
+               _bfd_error_handler
+                 (_("error: %B: conflicting attributes %s: %s with %s.\n"),
+                  obfd, tagname,
+                  tagval[in_attr[i].i],
+                  tagval[out_attr[i].i]);
+               result = FALSE;
+             }
+           tagname = NULL;
+           break;
+         }
+
+       case Tag_ARC_ABI_double_size:
+         tagname = "Double size";
+         /* fall through */
+       case Tag_ARC_ABI_enumsize:
+         if (!tagname)
+           tagname = "Enum size";
+         /* fall through */
+       case Tag_ARC_ABI_exceptions:
+         if (!tagname)
+           tagname = "ABI exceptions";
+
+         if (out_attr[i].i != 0 && in_attr[i].i != 0
+             && out_attr[i].i != in_attr[i].i)
+           {
+             _bfd_error_handler
+               (_("error: %B: conflicting attributes %s.\n"),
+                obfd, tagname);
+             result = FALSE;
+           }
+         break;
+
+       case Tag_ARC_ISA_apex:
+         break; /* Do nothing for APEX attributes.  */
+
+       case Tag_ARC_ISA_config:
+         /* It is handled in Tag_ARC_CPU_base.  */
+         break;
+
+       default:
+         result
+           = result && _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i);
+       }
+
+      /* If out_attr was copied from in_attr then it won't have a type yet.  */
+      if (in_attr[i].type && !out_attr[i].type)
+       out_attr[i].type = in_attr[i].type;
+    }
+
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  if (!_bfd_elf_merge_object_attributes (ibfd, info))
+    return FALSE;
+
+  /* Check for any attributes not known on ARC.  */
+  result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd);
+
+  return result;
+}
+
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
@@ -517,6 +824,10 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
   if (! _bfd_generic_verify_endian_match (ibfd, info))
     return FALSE;
 
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
   /* Collect ELF flags.  */
   in_flags = elf_elfheader (ibfd)->e_flags & EF_ARC_MACH_MSK;
   out_flags = elf_elfheader (obfd)->e_flags & EF_ARC_MACH_MSK;
@@ -527,9 +838,8 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       out_flags = in_flags;
     }
 
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
+  if (!arc_elf_merge_attributes (ibfd, info))
+    return FALSE;
 
   /* Check to see if the input BFD actually contains any sections.  Do
      not short-circuit dynamic objects; their section list may be
@@ -569,7 +879,11 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
                              ibfd, obfd);
          return FALSE;
        }
-      else if (in_flags != out_flags)
+      else if ((in_flags != out_flags)
+              /* If we have object attributes, then we already
+                 checked the objects compatibility, skip it.  */
+              && !bfd_elf_get_obj_attr_int (ibfd, OBJ_ATTR_PROC,
+                                            Tag_ARC_CPU_base))
        {
          /* Warn if different flags.  */
          _bfd_error_handler
@@ -583,6 +897,11 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
             eflags set by gcc.  */
          in_flags = in_flags > out_flags ? in_flags : out_flags;
        }
+      else
+       {
+         /* Everything is correct; don't change the output flags.  */
+         in_flags = out_flags;
+       }
     }
 
   /* Update the flags.  */
@@ -596,6 +915,30 @@ arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Return a best guess for the machine number based on the attributes.  */
+
+static unsigned int
+bfd_arc_get_mach_from_attributes (bfd * abfd)
+{
+  int arch = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, Tag_ARC_CPU_base);
+  unsigned e_machine = elf_elfheader (abfd)->e_machine;
+
+  switch (arch)
+    {
+    case TAG_CPU_ARC6xx:
+      return bfd_mach_arc_arc600;
+    case TAG_CPU_ARC7xx:
+      return bfd_mach_arc_arc700;
+    case TAG_CPU_ARCEM:
+    case TAG_CPU_ARCHS:
+      return bfd_mach_arc_arcv2;
+    default:
+      break;
+    }
+  return (e_machine == EM_ARC_COMPACT)
+    ? bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
+}
+
 /* Set the right machine number for an ARC ELF file.  */
 static bfd_boolean
 arc_elf_object_p (bfd * abfd)
@@ -603,7 +946,7 @@ arc_elf_object_p (bfd * abfd)
   /* Make sure this is initialised, or you'll have the potential of passing
      garbage---or misleading values---into the call to
      bfd_default_set_arch_mach ().  */
-  int            mach = bfd_mach_arc_arc700;
+  unsigned int   mach = bfd_mach_arc_arc700;
   unsigned long   arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH_MSK;
   unsigned       e_machine = elf_elfheader (abfd)->e_machine;
 
@@ -625,8 +968,7 @@ arc_elf_object_p (bfd * abfd)
            mach = bfd_mach_arc_arcv2;
            break;
          default:
-           mach = (e_machine == EM_ARC_COMPACT)
-             ? bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
+           mach = bfd_arc_get_mach_from_attributes (abfd);
            break;
        }
     }
@@ -657,6 +999,9 @@ arc_elf_final_write_processing (bfd * abfd,
                                bfd_boolean linker ATTRIBUTE_UNUSED)
 {
   unsigned long emf;
+  int osver = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC,
+                                       Tag_ARC_ABI_osver);
+  flagword e_flags = elf_elfheader (abfd)->e_flags & ~EF_ARC_OSABI_MSK;
 
   switch (bfd_get_mach (abfd))
     {
@@ -673,16 +1018,18 @@ arc_elf_final_write_processing (bfd * abfd,
       emf = EM_ARC_COMPACT2;
       break;
     default:
-      goto DO_NOTHING;
+      return;
     }
 
   elf_elfheader (abfd)->e_machine = emf;
 
   /* Record whatever is the current syscall ABI version.  */
-  elf_elfheader (abfd)->e_flags |= E_ARC_OSABI_CURRENT;
+  if (osver)
+    e_flags |= ((osver & 0x0f) << 8);
+  else
+    e_flags |= E_ARC_OSABI_V3;
 
-DO_NOTHING:
-  return;
+  elf_elfheader (abfd)->e_flags |=  e_flags;
 }
 
 #ifdef ARC_ENABLE_DEBUG
@@ -919,7 +1266,7 @@ arc_do_relocation (bfd_byte * contents,
   struct elf_link_hash_table *htab ATTRIBUTE_UNUSED = elf_hash_table (info);
   bfd_reloc_status_type flag;
 
-  if (reloc_data.should_relocate == FALSE)
+  if (!reloc_data.should_relocate)
     return bfd_reloc_ok;
 
   switch (reloc_data.howto->size)
@@ -1124,9 +1471,9 @@ elf_arc_relocate_section (bfd *                     output_bfd,
       h2 = elf_link_hash_lookup (elf_hash_table (info), "__SDATA_BEGIN__",
                                 FALSE, FALSE, TRUE);
 
-      if (reloc_data.sdata_begin_symbol_vma_set == FALSE
-           && h2 != NULL && h2->root.type != bfd_link_hash_undefined
-           && h2->root.u.def.section->output_section != NULL)
+      if (!reloc_data.sdata_begin_symbol_vma_set
+         && h2 != NULL && h2->root.type != bfd_link_hash_undefined
+         && h2->root.u.def.section->output_section != NULL)
        /* TODO: Verify this condition.  */
        {
          reloc_data.sdata_begin_symbol_vma =
@@ -1241,7 +1588,12 @@ elf_arc_relocate_section (bfd *                    output_bfd,
 
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
+         {
+           struct elf_link_hash_entry *h_old = h;
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           if (h->got.glist == 0 && h_old->got.glist != h->got.glist)
+             h->got.glist = h_old->got.glist;
+         }
 
          /* TODO: Need to validate what was the intention.  */
          /* BFD_ASSERT ((h->dynindx == -1) || (h->forced_local != 0)); */
@@ -1361,16 +1713,22 @@ elf_arc_relocate_section (bfd *                   output_bfd,
            }
        }
 
+
+#define IS_ARC_PCREL_TYPE(TYPE) \
+  (   (TYPE == R_ARC_PC32)      \
+   || (TYPE == R_ARC_32_PCREL))
+
       switch (r_type)
        {
          case R_ARC_32:
          case R_ARC_32_ME:
          case R_ARC_PC32:
          case R_ARC_32_PCREL:
-           if ((bfd_link_pic (info))
-               && ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL)
+           if (bfd_link_pic (info)
+               && (!IS_ARC_PCREL_TYPE (r_type)
                    || (h != NULL
                        && h->dynindx != -1
+                       && !h->def_regular
                        && (!info->symbolic || !h->def_regular))))
              {
                Elf_Internal_Rela outrel;
@@ -1387,6 +1745,7 @@ elf_arc_relocate_section (bfd *                     output_bfd,
                                                           info,
                                                           input_section,
                                                           rel->r_offset);
+
                if (outrel.r_offset == (bfd_vma) -1)
                  skip = TRUE;
 
@@ -1394,10 +1753,6 @@ elf_arc_relocate_section (bfd *                    output_bfd,
                outrel.r_offset += (input_section->output_section->vma
                                    + input_section->output_offset);
 
-#define IS_ARC_PCREL_TYPE(TYPE) \
-  (   (TYPE == R_ARC_PC32)      \
-   || (TYPE == R_ARC_32_PCREL))
-
                if (skip)
                  {
                    memset (&outrel, 0, sizeof outrel);
@@ -1405,10 +1760,10 @@ elf_arc_relocate_section (bfd *                   output_bfd,
                  }
                else if (h != NULL
                         && h->dynindx != -1
-                        && ((IS_ARC_PCREL_TYPE (r_type))
-                        || !(bfd_link_executable (info)
-                             || SYMBOLIC_BIND (info, h))
-                        || ! h->def_regular))
+                        && (IS_ARC_PCREL_TYPE (r_type)
+                            || !(bfd_link_executable (info)
+                                 || SYMBOLIC_BIND (info, h))
+                            || ! h->def_regular))
                  {
                    BFD_ASSERT (h != NULL);
                    if ((input_section->flags & SEC_ALLOC) != 0)
@@ -1444,7 +1799,7 @@ elf_arc_relocate_section (bfd *                     output_bfd,
 
                bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 
-               if (relocate == FALSE)
+               if (!relocate)
                  continue;
              }
            break;
@@ -1453,7 +1808,7 @@ elf_arc_relocate_section (bfd *                     output_bfd,
        }
 
       if (is_reloc_SDA_relative (howto)
-         && (reloc_data.sdata_begin_symbol_vma_set == FALSE))
+         && !reloc_data.sdata_begin_symbol_vma_set)
        {
          _bfd_error_handler
            ("Error: Linker symbol __SDATA_BEGIN__ not found");
@@ -1567,8 +1922,8 @@ elf_arc_check_relocs (bfd *                        abfd,
       howto = arc_elf_howto (r_type);
 
       if (dynobj == NULL
-         && (is_reloc_for_GOT (howto) == TRUE
-             || is_reloc_for_TLS (howto) == TRUE))
+         && (is_reloc_for_GOT (howto)
+             || is_reloc_for_TLS (howto)))
        {
          dynobj = elf_hash_table (info)->dynobj = abfd;
          if (! _bfd_elf_create_got_section (abfd, info))
@@ -1591,7 +1946,8 @@ elf_arc_check_relocs (bfd *                        abfd,
               and the dynamic linker can not resolve these.  However
               the error should not occur for e.g. debugging or
               non-readonly sections.  */
-           if ((bfd_link_dll (info) && !bfd_link_pie (info))
+           if (h != NULL
+               && (bfd_link_dll (info) && !bfd_link_pie (info))
                && (sec->flags & SEC_ALLOC) != 0
                && (sec->flags & SEC_READONLY) != 0
                && ((sec->flags & SEC_CODE) != 0
@@ -1645,7 +2001,7 @@ elf_arc_check_relocs (bfd *                        abfd,
            break;
        }
 
-      if (is_reloc_for_PLT (howto) == TRUE)
+      if (is_reloc_for_PLT (howto))
        {
          if (h == NULL)
            continue;
@@ -1654,8 +2010,8 @@ elf_arc_check_relocs (bfd *                        abfd,
        }
 
       /* Add info to the symbol got_entry_list.  */
-      if (is_reloc_for_GOT (howto) == TRUE
-         || is_reloc_for_TLS (howto) == TRUE)
+      if (is_reloc_for_GOT (howto)
+         || is_reloc_for_TLS (howto))
        {
          arc_fill_got_info_for_reloc (
                  arc_got_entry_type_for_reloc (howto),
@@ -2465,6 +2821,69 @@ elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
                                          note->descpos + offset);
 }
 
+/* Determine whether an object attribute tag takes an integer, a
+   string or both.  */
+
+static int
+elf32_arc_obj_attrs_arg_type (int tag)
+{
+  if (tag == Tag_ARC_CPU_name
+          || tag == Tag_ARC_ISA_config
+          || tag == Tag_ARC_ISA_apex)
+    return ATTR_TYPE_FLAG_STR_VAL;
+  else if (tag < (Tag_ARC_ISA_mpy_option + 1))
+    return ATTR_TYPE_FLAG_INT_VAL;
+  else
+    return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
+}
+
+/* Attribute numbers >=14 can be safely ignored.  */
+
+static bfd_boolean
+elf32_arc_obj_attrs_handle_unknown (bfd *abfd, int tag)
+{
+  if ((tag & 127) < (Tag_ARC_ISA_mpy_option + 1))
+    {
+      _bfd_error_handler
+       (_("%B: Unknown mandatory ARC object attribute %d."),
+        abfd, tag);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+  else
+    {
+      _bfd_error_handler
+       (_("Warning: %B: Unknown ARC object attribute %d."),
+        abfd, tag);
+      return TRUE;
+    }
+}
+
+/* Handle an ARC specific section when reading an object file.  This is
+   called when bfd_section_from_shdr finds a section with an unknown
+   type.  */
+
+static bfd_boolean
+elf32_arc_section_from_shdr (bfd *abfd,
+                            Elf_Internal_Shdr * hdr,
+                            const char *name,
+                            int shindex)
+{
+  switch (hdr->sh_type)
+    {
+    case SHT_ARC_ATTRIBUTES:
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+    return FALSE;
+
+  return TRUE;
+}
+
 #define TARGET_LITTLE_SYM   arc_elf32_le_vec
 #define TARGET_LITTLE_NAME  "elf32-littlearc"
 #define TARGET_BIG_SYM     arc_elf32_be_vec
@@ -2516,4 +2935,16 @@ elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 
 #define elf_backend_default_execstack  0
 
+#undef  elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor           "ARC"
+#undef  elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section          ".ARC.attributes"
+#undef  elf_backend_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type         elf32_arc_obj_attrs_arg_type
+#undef  elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type     SHT_ARC_ATTRIBUTES
+#define elf_backend_obj_attrs_handle_unknown   elf32_arc_obj_attrs_handle_unknown
+
+#define elf_backend_section_from_shdr                  elf32_arc_section_from_shdr
+
 #include "elf32-target.h"
This page took 0.031331 seconds and 4 git commands to generate.