/* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994, 95, 96, 97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
 
 #endif
 
 static unsigned long   cpu_variant = CPU_DEFAULT | FPU_DEFAULT;
+static int target_oabi = 0;
 
 #if defined OBJ_COFF || defined OBJ_ELF
 /* Flags stored in private area of BFD structure */
      segT segment;
      valueT size;
 {
-/* start-sanitize-armelf */
 #ifdef OBJ_ELF
   /* Don't align the dwarf2 debug sections */
   if (!strncmp(segment->name,".debug",5))
     return size;
 #endif
-/* end-sanitize-armelf */
   /* Round all sects to multiple of 4 */
   return (size + 3) & ~3;
 }
       break;
 
     case BFD_RELOC_ARM_PCREL_BRANCH:
+#ifdef OBJ_ELF
+      if (target_oabi)
+        value = (value >> 2) & 0x00ffffff;
+      else
+        value = fixP->fx_offset;
+#else
       value = (value >> 2) & 0x00ffffff;
+#endif
       newval = md_chars_to_number (buf, INSN_SIZE);
+#ifdef OBJ_ELF 
+      if (!target_oabi)
+        newval = (newval & 0xff000000);
+#endif
+      newval = (newval & 0xff000000);
       value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
       newval = value | (newval & 0xff000000);
       md_number_to_chars (buf, newval, INSN_SIZE);
       {
         offsetT newval2;
         addressT diff;
-       
+
        newval  = md_chars_to_number (buf, THUMB_SIZE);
         newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
         diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
     case BFD_RELOC_8:
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 1);
+#ifdef OBJ_ELF
+      else if (!target_oabi)
+        {
+          value = fixP->fx_offset;
+          md_number_to_chars (buf, value, 1);
+        }
+#endif
       break;
 
     case BFD_RELOC_16:
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 2);
+#ifdef OBJ_ELF
+      else if (!target_oabi)
+        {
+          value = fixP->fx_offset;
+          md_number_to_chars (buf, value, 2);
+        }
+#endif
       break;
 
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
+#ifndef OBJ_ELF
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 4);
+#else
+      if (!target_oabi)
+        {
+          value = fixP->fx_offset;
+          md_number_to_chars (buf, value, 4);
+        }
+      else if (fixP->fx_done || fixP->fx_pcrel)
+        md_number_to_chars (buf, value, 4);
+#endif
       break;
 
     case BFD_RELOC_ARM_CP_OFF_IMM:
       md_number_to_chars (buf, newval , THUMB_SIZE);
       break;
 
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      return 1;
+
     case BFD_RELOC_NONE:
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
     case BFD_RELOC_THUMB_PCREL_BRANCH9:
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
+    case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_VTABLE_INHERIT:
       code = fixp->fx_r_type;
       break;
 
  *            -m[arm]1                Currently not supported.
  *            -m[arm]2, -m[arm]250    Arm 2 and Arm 250 processor
  *            -m[arm]3                Arm 3 processor
- *            -m[arm]6,               Arm 6 processors
- *            -m[arm]7[t][[d]m]       Arm 7 processors
+ *            -m[arm]6[xx],           Arm 6 processors
+ *            -m[arm]7[xx][t][[d]m]   Arm 7 processors
+ *            -mstrongarm[110]       Arm 8 processors
  *            -mall                   All (except the ARM1)
  *    FP variants:
  *            -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
   {"EB", no_argument, NULL, OPTION_EB},
 #define OPTION_EL (OPTION_MD_BASE + 1)
   {"EL", no_argument, NULL, OPTION_EL},
+#ifdef OBJ_ELF
+#define OPTION_OABI (OPTION_MD_BASE +2)
+  {"oabi", no_argument, NULL, OPTION_OABI},
+#endif
 #endif
   {NULL, no_argument, NULL, 0}
 };
            cpu_variant &= ~FPU_ALL;
          break;
 
+        case 'o':
+          if (!strcmp (str, "oabi"))
+            target_oabi = true;
+          break;
+
         case 't':
           /* Limit assembler to generating only Thumb instructions: */
           if (! strcmp (str, "thumb"))
                goto bad;
              break;
 
-           case '6':
-             if (! strcmp (str, "6"))
-               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
-             else
-               goto bad;
+             switch (strtol (str, NULL, 10))
+               {
+               case 6:
+               case 60:
+               case 600:
+               case 610:
+               case 620:
+                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
+                 break;
+               default:
+                 goto bad;
+               }
              break;
 
            case '7':
-              str++; /* eat the '7' */
+             switch (strtol (str, & str, 10))  /* Eat the processor name */
+               {
+               case 7:
+               case 70:
+               case 700:
+               case 710:
+               case 7100:
+               case 7500:
+                 break;
+               default:
+                 goto bad;
+               }
               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
               for (; *str; str++)
                 {
 void
 arm_adjust_symtab ()
 {
-  symbolS * sym;
 #ifdef OBJ_COFF
+  symbolS * sym;
 
   for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
     {
       if (ARM_IS_INTERWORK (sym))
        coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF;
     }
-#endif /* OBJ_COFF */
+#endif
 }
 #ifdef OBJ_ELF
 void
 armelf_adjust_symtab ()
 {
   symbolS * sym;
+  elf_symbol_type *elf_sym;
+  char bind;
 
   for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
     {
-      if (ARM_IS_THUMB (sym) && (THUMB_IS_FUNC (sym)))
-       {
-         elf_symbol_type * elf_sym;
-         unsigned char bind;
+      if (ARM_IS_THUMB (sym))
+        {
+         if (THUMB_IS_FUNC (sym))
+           {
+            elf_sym = elf_symbol(sym->bsym);
+            bind = ELF_ST_BIND(elf_sym);
+            elf_sym->internal_elf_sym.st_info = ELF_ST_INFO(bind, STT_ARM_TFUNC);
+            }
 
-         elf_sym = elf_symbol (sym->bsym);
-         bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
-         
-         elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
-       }
-    }
+         }
+     }
 }
 
+#endif
+
+#ifdef OBJ_ELF
 void
 armelf_frob_symbol (symp, puntp)
-     symbolS * symp;
-     int * puntp;
+    symbolS *symp;
+    int *puntp;
+
 {
    elf_frob_symbol (symp, puntp);
-}
-
-#endif /* OBJ_ELF */
 
+} 
+#endif
 int
 arm_data_in_code ()
 {
 
   return name;
 }
-/* start-sanitize-armelf */
 #ifdef OBJ_ELF
 /* Relocations against Thumb function names must be left unadjusted,
    so that the linker can use this information to correctly set the
 arm_fix_adjustable (fixP)
    fixS *fixP;
 {
+
   if (fixP->fx_addsy == NULL)
     return 1;
   
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERN (fixP->fx_addsy))
+    return 0;
+  if (S_IS_WEAK (fixP->fx_addsy))
+    return 0;
+
   if (THUMB_IS_FUNC (fixP->fx_addsy)
       && fixP->fx_subsy == NULL)
     return 0;
   
+  /* We need the symbol name for the VTABLE entries */
+  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 0;
+
   return 1;
 }
 #endif /* OBJ_ELF */
-/* end-sanitize-armelf */
+
+#ifdef OBJ_ELF
+int
+elf32_arm_force_relocation (fixp)
+      struct fix *fixp;
+{
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 1;
+
+  if (fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+    return 1;
+
+  return 0;
+}
+#endif
 
 boolean
 arm_validate_fix (fixP)
   return false;
 }
 
+const char *
+elf32_arm_target_format ()
+{
+  if (target_big_endian)
+    if (target_oabi)
+      return "elf32-bigarm-oabi";
+    else
+      return "elf32-bigarm";
+  else
+    if (target_oabi)
+      return "elf32-littlearm-oabi";
+    else
+      return "elf32-littlearm";
+}
 
 /* This file is tc-arm.h
-   Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
 
 # endif
 #endif
 
-/* start-sanitize-armelf */
+#ifdef OBJ_ELF
+#define TC_FORCE_RELOCATION(fixp) elf32_arm_force_relocation(fixp)
+extern int elf32_arm_force_relocation PARAMS ((struct fix *));
+#endif
+
 #ifdef OBJ_ELF
 extern boolean arm_validate_fix ();
 #define TC_VALIDATE_FIX(fixP,segType,Label) if (arm_validate_fix (fixP)) add_symbolP = fixP->fx_addsy
 #define ARM_BI_ENDIAN
-#define TARGET_FORMAT (target_big_endian ? "elf32-bigarm" : "elf32-littlearm")
+#define TARGET_FORMAT elf32_arm_target_format()
+extern const char *elf32_arm_target_format PARAMS ((void));
 #endif
-/* end-sanitize-armelf */
 
 #define md_convert_frag(b,s,f)         {as_fatal (_("arm convert_frag\n"));}
 
    deliberately not been updated to mark assembler created stabs
    symbols as Thumb.  */
 
-/* start-sanitize-armelf */
 #ifdef OBJ_ELF
 #define obj_fix_adjustable(fixP) arm_fix_adjustable(fixP)
 #else
-/* end-sanitize-armelf */
 #define obj_fix_adjustable(fixP) 0
-/* start-sanitize-armelf */
 #endif
-/* end-sanitize-armelf */
 
 /* We need to keep some local information on symbols.  */
 
 
 /* Finish processing the entire symbol table:  */
 #ifdef OBJ_ELF
-#define obj_adjust_symtab armelf_adjust_symtab 
+#define obj_adjust_symtab() armelf_adjust_symtab ()
 extern void armelf_adjust_symtab PARAMS ((void));
 #else
-#define obj_adjust_symtab arm_adjust_symtab 
+#define obj_adjust_symtab() arm_adjust_symtab ()
 extern void arm_adjust_symtab PARAMS ((void));
 #endif