]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Merge in patches from mainline
authorNick Clifton <nickc@redhat.com>
Wed, 13 Jun 2001 11:49:41 +0000 (11:49 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 13 Jun 2001 11:49:41 +0000 (11:49 +0000)
gas/ChangeLog
gas/config/tc-arm.c
gas/config/tc-arm.h

index 105e8875e4161db3950c03d2d6f2289f24bffde5..0386e0990bd8e4b61a5bff12fed93945f25424a6 100644 (file)
@@ -1,3 +1,32 @@
+2001-06-13  Nick Clifton  <nickc@cambridge.redhat.com>
+
+       Merge from mainline:
+       2001-05-11  Nick Clifton  <nickc@cambridge.redhat.com>
+       * config/tc-arm.c (arm_handle_align): When truncating an aligned
+       block, ensure that the low order bits of the alignment are
+       preserved.
+       2001-05-06  Nick Clifton  <nickc@cambridge.redhat.com>
+       * config/tc-arm.h (MAX_MEM_FOR_RS_ALIGN_CODE): Define.
+       * config/tc-arm.c (arm_handle_align): Do not insert more than
+       MAX_MEM_FOR_RS_ALIGN_CODE bytes.
+       (arm_frag_align_code): Use MAX_MEM_FOR_RS_ALIGN_CODE.
+       2001-04-26  Nick Clifton  <nickc@cambridge.redhat.com>
+       * config/tc-arm.c (arm_handle_align): New Function:  Generate
+       no-op filled alignment frags.
+       (arm_frag_align_code): New Function: Create a code alignment frag.
+       (arm_init_frag): New Function: Initialse the target dependent
+       parts of a frag.
+       * config/tc-arm.h (TC_FRAG_TYPE): Define.
+       (TC_FRAG_INIT): Define.
+       (HANDLE_ALIGN): Define.
+       (md_do_align): Define.
+       2001-03-12  Nick Clifton  <nickc@redhat.com>
+       * config/tc-arm.c (md_begin): Always set machine type based on
+       cpu_variant.
+       2001-03-06  Nick Clifton  <nickc@redhat.com>
+       * config/tc-arm.c (md_apply_fix3): Clear bit zero of offset in
+       BLX(1) instruction.
+
 2001-06-12  Nick Clifton  <nickc@cambridge.redhat.com>
 
        * doc/as.texinfo (Infix Ops): Document that comparison and
index f88d1ff6fb9cf33ae6ab642922fdb8815a1655be..fa5c85a4e96e080ec32e30ef383476e20cbbe9e3 100644 (file)
@@ -1279,12 +1279,23 @@ add_to_lit_pool ()
              == inst.reloc.exp.X_add_number)
          && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
        break;
+
+      if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
+          && inst.reloc.exp.X_op == O_symbol
+          && (literals[lit_count].exp.X_add_number
+             == inst.reloc.exp.X_add_number)
+          && (literals[lit_count].exp.X_add_symbol
+             == inst.reloc.exp.X_add_symbol)
+          && (literals[lit_count].exp.X_op_symbol
+             == inst.reloc.exp.X_op_symbol))
+        break;
+
       lit_count++;
     }
 
   if (lit_count == next_literal_pool_place) /* New entry.  */
     {
-      if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE)
+      if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE)
        {
          inst.error = _("Literal Pool Overflow");
          return FAIL;
@@ -6513,29 +6524,26 @@ md_begin ()
     }
 
   /* Catch special cases.  */
-  if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
+  if (cpu_variant & ARM_EXT_XSCALE)
+    mach = bfd_mach_arm_XScale;
+  else if (cpu_variant & ARM_EXT_V5E)
+    mach = bfd_mach_arm_5TE;
+  else if (cpu_variant & ARM_EXT_V5)
+    {
+      if (cpu_variant & ARM_EXT_THUMB)
+       mach = bfd_mach_arm_5T;
+      else
+       mach = bfd_mach_arm_5;
+    }
+  else if (cpu_variant & ARM_EXT_HALFWORD)
     {
-      if (cpu_variant & ARM_EXT_XSCALE)
-       mach = bfd_mach_arm_XScale;
-      else if (cpu_variant & ARM_EXT_V5E)
-       mach = bfd_mach_arm_5TE;
-      else if (cpu_variant & ARM_EXT_V5)
-       {
-         if (cpu_variant & ARM_EXT_THUMB)
-           mach = bfd_mach_arm_5T;
-         else
-           mach = bfd_mach_arm_5;
-       }
-      else if (cpu_variant & ARM_EXT_HALFWORD)
-       {
-         if (cpu_variant & ARM_EXT_THUMB)
-           mach = bfd_mach_arm_4T;
-         else
-           mach = bfd_mach_arm_4;
-       }
-      else if (cpu_variant & ARM_EXT_LONGMUL)
-       mach = bfd_mach_arm_3M;
+      if (cpu_variant & ARM_EXT_THUMB)
+       mach = bfd_mach_arm_4T;
+      else
+       mach = bfd_mach_arm_4;
     }
+  else if (cpu_variant & ARM_EXT_LONGMUL)
+    mach = bfd_mach_arm_3M;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
 }
@@ -7149,6 +7157,15 @@ md_apply_fix3 (fixP, val, seg)
 
        newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
        newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+         /* Remove bit zero of the adjusted offset.  Bit zero can only be
+            set if the upper insn is at a half-word boundary, since the
+            destination address, an ARM instruction, must always be on a
+            word boundary.  The semantics of the BLX (1) instruction, however,
+            are that bit zero in the offset must always be zero, and the
+            corresponding bit one in the target address will be set from bit
+            one of the source address.  */
+         newval2 &= ~1;
        md_number_to_chars (buf, newval, THUMB_SIZE);
        md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
       }
@@ -8418,7 +8435,38 @@ arm_frob_label (sym)
   ARM_SET_INTERWORK (sym, support_interwork);
 #endif
 
-  if (label_is_thumb_function_name)
+  /* Note - do not allow local symbols (.Lxxx) to be labeled
+     as Thumb functions.  This is because these labels, whilst
+     they exist inside Thumb code, are not the entry points for
+     possible ARM->Thumb calls.  Also, these labels can be used
+     as part of a computed goto or switch statement.  eg gcc
+     can generate code that looks like this:
+
+                ldr  r2, [pc, .Laaa]
+                lsl  r3, r3, #2
+                ldr  r2, [r3, r2]
+                mov  pc, r2
+               
+       .Lbbb:  .word .Lxxx
+       .Lccc:  .word .Lyyy
+       ..etc...
+       .Laaa:   .word Lbbb
+
+     The first instruction loads the address of the jump table.
+     The second instruction converts a table index into a byte offset.
+     The third instruction gets the jump address out of the table.
+     The fourth instruction performs the jump.
+     
+     If the address stored at .Laaa is that of a symbol which has the
+     Thumb_Func bit set, then the linker will arrange for this address
+     to have the bottom bit set, which in turn would mean that the
+     address computation performed by the third instruction would end
+     up with the bottom bit set.  Since the ARM is capable of unaligned
+     word loads, the instruction would then load the incorrect address
+     out of the jump table, and chaos would ensue.  */
+  if (label_is_thumb_function_name
+      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
+      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
     {
       /* When the address of a Thumb function is taken the bottom
         bit of that address should be set.  This will allow
@@ -8743,3 +8791,102 @@ s_arm_elf_cons (nbytes)
 }
 
 #endif /* OBJ_ELF */
+
+/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
+   of an rs_align_code fragment.  */
+
+void
+arm_handle_align (fragP)
+     fragS *fragP;
+{
+  static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
+  static char const thumb_noop[2] = { 0xc0, 0x46 };
+  static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
+  static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
+
+  int bytes, fix, noop_size;
+  char * p;
+  const char * noop;
+  
+  if (fragP->fr_type != rs_align_code)
+    return;
+
+  bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
+  p = fragP->fr_literal + fragP->fr_fix;
+  fix = 0;
+  
+  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
+    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
+  
+  if (fragP->tc_frag_data)
+    {
+      if (target_big_endian)
+       noop = thumb_bigend_noop;
+      else
+       noop = thumb_noop;
+      noop_size = sizeof (thumb_noop);
+    }
+  else
+    {
+      if (target_big_endian)
+       noop = arm_bigend_noop;
+      else
+       noop = arm_noop;
+      noop_size = sizeof (arm_noop);
+    }
+  
+  if (bytes & (noop_size - 1))
+    {
+      fix = bytes & (noop_size - 1);
+      memset (p, 0, fix);
+      p += fix;
+      bytes -= fix;
+    }
+
+  while (bytes >= noop_size)
+    {
+      memcpy (p, noop, noop_size);
+      p += noop_size;
+      bytes -= noop_size;
+      fix += noop_size;
+    }
+  
+  fragP->fr_fix += fix;
+  fragP->fr_var = noop_size;
+}
+
+/* Called from md_do_align.  Used to create an alignment
+   frag in a code section.  */
+
+void
+arm_frag_align_code (n, max)
+     int n;
+     int max;
+{
+  char * p;
+
+  /* We assume that there will never be a requirment
+     to support alignments greater than 32 bytes.  */
+  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
+    as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
+  
+  p = frag_var (rs_align_code,
+               MAX_MEM_FOR_RS_ALIGN_CODE,
+               1,
+               (relax_substateT) max,
+               (symbolS *) NULL,
+               (offsetT) n,
+               (char *) NULL);
+  *p = 0;
+
+}
+
+/* Perform target specific initialisation of a frag.  */
+
+void
+arm_init_frag (fragP)
+     fragS *fragP;
+{
+  /* Record whether this frag is in an ARM or a THUMB area.  */
+  fragP->tc_frag_data = thumb_mode;
+}
index 7060333a5b10ff473a5244cde9453bf93c729cea..8de5704efae8e8b866d4dc7fa0256aece4c3bfc2 100644 (file)
@@ -214,3 +214,23 @@ void armelf_frob_symbol PARAMS ((symbolS *, int *));
 #ifdef OBJ_ELF
 #define DWARF2_LINE_MIN_INSN_LENGTH 2
 #endif
+
+#define MAX_MEM_FOR_RS_ALIGN_CODE 31
+
+/* For frags in code sections we need to record whether they contain
+   ARM code or THUMB code.  This is that if they have to be aligned,
+   they can contain the correct type of no-op instruction.  */
+#define TC_FRAG_TYPE   int
+#define TC_FRAG_INIT(fragp)    arm_init_frag (fragp)
+extern void arm_init_frag PARAMS ((struct frag *));
+
+#define HANDLE_ALIGN(fragp) arm_handle_align (fragp)
+extern void arm_handle_align PARAMS ((struct frag *));
+
+#define md_do_align(N, FILL, LEN, MAX, LABEL)                                  \
+  if (FILL == NULL && (N) != 0 && ! need_pass_2 && subseg_text_p (now_seg))    \
+    {                                                                          \
+      arm_frag_align_code (N, MAX);                                            \
+      goto LABEL;                                                              \
+    }
+extern void arm_frag_align_code PARAMS ((int, int));