bfd/ChangeLog
authorDenis Chertykov <chertykov@gmail.com>
Thu, 10 Apr 2014 15:50:33 +0000 (19:50 +0400)
committerDenis Chertykov <chertykov@gmail.com>
Thu, 10 Apr 2014 15:50:33 +0000 (19:50 +0400)
* elf32-avr.c: Add DIFF relocations for AVR.
(avr_final_link_relocate): Handle the DIFF relocs.
(bfd_elf_avr_diff_reloc): New.
(elf32_avr_is_diff_reloc): New.
(elf32_avr_adjust_diff_reloc_value): Reduce difference value.
(elf32_avr_relax_delete_bytes): Recompute difference after deleting
bytes.

* reloc.c: Add BFD_RELOC_AVR_DIFF8/16/32 relocations

gas/ChangeLog

* config/tc-avr.c: Add new flag mlink-relax.
(md_show_usage): Add flag and help text.
(md_parse_option): Record whether link relax is turned on.
(relaxable_section): New.
(avr_validate_fix_sub): New.
(avr_force_relocation): New.
(md_apply_fix): Generate DIFF reloc.
(avr_allow_local_subtract): New.

* config/tc-avr.h (TC_LINKRELAX_FIXUP): Define to 0.
(TC_FORCE_RELOCATION): Define.
(TC_FORCE_RELOCATION_SUB_SAME): Define.
(TC_VALIDATE_FIX_SUB): Define.
(avr_force_relocation): Declare.
(avr_validate_fix_sub): Declare.
(md_allow_local_subtract): Define.
(avr_allow_local_subtract): Declare.

gas/testsuite/ChangeLog

* gas/avr/diffreloc_withrelax.d: New testcase.
* gas/avr/noreloc_withoutrelax.d: Likewise.
* gas/avr/relax.s: Likewise.

include/ChangeLog

* elf/avr.h: Add new DIFF relocs.

ld/testsuite/ChangeLog

* ld-avr/norelax_diff.d: New testcase.
* ld-avr/relax_diff.d: Likewise.
* ld-avr/relax.s: Likewise.

17 files changed:
bfd/ChangeLog
bfd/elf32-avr.c
bfd/reloc.c
gas/ChangeLog
gas/config/tc-avr.c
gas/config/tc-avr.h
gas/testsuite/ChangeLog
gas/testsuite/gas/avr/diffreloc_withrelax.d [new file with mode: 0644]
gas/testsuite/gas/avr/noreloc_withoutrelax.d [new file with mode: 0644]
gas/testsuite/gas/avr/relax.s [new file with mode: 0644]
include/ChangeLog
include/elf/avr.h
ld/testsuite/ChangeLog
ld/testsuite/ld-avr/avr.exp [new file with mode: 0644]
ld/testsuite/ld-avr/norelax_diff.d [new file with mode: 0644]
ld/testsuite/ld-avr/relax.s [new file with mode: 0644]
ld/testsuite/ld-avr/relax_diff.d [new file with mode: 0644]

index e38c6a4..0fc016c 100644 (file)
@@ -1,3 +1,15 @@
+2014-04-10  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * elf32-avr.c: Add DIFF relocations for AVR.
+       (avr_final_link_relocate): Handle the DIFF relocs.
+       (bfd_elf_avr_diff_reloc): New.
+       (elf32_avr_is_diff_reloc): New.
+       (elf32_avr_adjust_diff_reloc_value): Reduce difference value.
+       (elf32_avr_relax_delete_bytes): Recompute difference after deleting
+       bytes.
+
+       * reloc.c: Add BFD_RELOC_AVR_DIFF8/16/32 relocations
+
 2014-04-09  Alan Modra  <amodra@gmail.com>
 
        * libcoff.h: Regenerate.
index 3fd43c9..425e2d1 100644 (file)
@@ -32,6 +32,15 @@ static bfd_boolean debug_relax = FALSE;
 /* Enable debugging printout at stdout with this variable.  */
 static bfd_boolean debug_stubs = FALSE;
 
+static bfd_reloc_status_type
+bfd_elf_avr_diff_reloc (bfd *abfd,
+              arelent *reloc_entry,
+              asymbol *symbol,
+              void *data,
+              asection *input_section,
+              bfd *output_bfd,
+              char **error_message);
+
 /* Hash table initialization and handling.  Code is taken from the hppa port
    and adapted to the needs of AVR.  */
 
@@ -557,6 +566,45 @@ static reloc_howto_type elf_avr_howto_table[] =
         0xffffff,              /* src_mask */
         0xffffff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
+  HOWTO (R_AVR_DIFF8,      /* type */
+     0,             /* rightshift */
+     0,                        /* size (0 = byte, 1 = short, 2 = long) */
+     8,                        /* bitsize */
+     FALSE,         /* pc_relative */
+     0,             /* bitpos */
+     complain_overflow_bitfield, /* complain_on_overflow */
+     bfd_elf_avr_diff_reloc, /* special_function */
+     "R_AVR_DIFF8",     /* name */
+     FALSE,         /* partial_inplace */
+     0,             /* src_mask */
+     0xff,          /* dst_mask */
+     FALSE),        /* pcrel_offset */
+  HOWTO (R_AVR_DIFF16,     /* type */
+     0,             /* rightshift */
+     1,                        /* size (0 = byte, 1 = short, 2 = long) */
+     16,                       /* bitsize */
+     FALSE,         /* pc_relative */
+     0,             /* bitpos */
+     complain_overflow_bitfield, /* complain_on_overflow */
+     bfd_elf_avr_diff_reloc, /* special_function */
+     "R_AVR_DIFF16",     /* name */
+     FALSE,         /* partial_inplace */
+     0,             /* src_mask */
+     0xffff,        /* dst_mask */
+     FALSE),        /* pcrel_offset */
+  HOWTO (R_AVR_DIFF32,    /* type */
+     0,             /* rightshift */
+     2,         /* size (0 = byte, 1 = short, 2 = long) */
+     32,        /* bitsize */
+     FALSE,         /* pc_relative */
+     0,             /* bitpos */
+     complain_overflow_bitfield, /* complain_on_overflow */
+     bfd_elf_avr_diff_reloc, /* special_function */
+     "R_AVR_DIFF32",     /* name */
+     FALSE,         /* partial_inplace */
+     0,             /* src_mask */
+     0xffffffff,    /* dst_mask */ 
+     FALSE)         /* pcrel_offset */
 };
 
 /* Map BFD reloc types to AVR ELF reloc types.  */
@@ -598,7 +646,10 @@ static const struct avr_reloc_map avr_reloc_map[] =
   { BFD_RELOC_8,                    R_AVR_8 },
   { BFD_RELOC_AVR_8_LO,             R_AVR_8_LO8 },
   { BFD_RELOC_AVR_8_HI,             R_AVR_8_HI8 },
-  { BFD_RELOC_AVR_8_HLO,            R_AVR_8_HLO8 }
+  { BFD_RELOC_AVR_8_HLO,            R_AVR_8_HLO8 },
+  { BFD_RELOC_AVR_DIFF8,            R_AVR_DIFF8 },
+  { BFD_RELOC_AVR_DIFF16,           R_AVR_DIFF16 },
+  { BFD_RELOC_AVR_DIFF32,           R_AVR_DIFF32 }
 };
 
 /* Meant to be filled one day with the wrap around address for the
@@ -797,6 +848,22 @@ avr_get_stub_addr (bfd_vma srel,
   return 0x020000;
 }
 
+/* Perform a diff relocation. Nothing to do, as the difference value is already
+   written into the section's contents. */
+
+static bfd_reloc_status_type
+bfd_elf_avr_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+                     arelent *reloc_entry ATTRIBUTE_UNUSED,
+              asymbol *symbol ATTRIBUTE_UNUSED,
+              void *data ATTRIBUTE_UNUSED,
+              asection *input_section ATTRIBUTE_UNUSED,
+              bfd *output_bfd ATTRIBUTE_UNUSED,
+              char **error_message ATTRIBUTE_UNUSED)
+{
+  return bfd_reloc_ok;
+}
+
+
 /* Perform a single relocation.  By default we use the standard BFD
    routines, but a few relocs, we have to do them ourselves.  */
 
@@ -1149,6 +1216,13 @@ avr_final_link_relocate (reloc_howto_type *                 howto,
       bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents);
       break;
 
+    case R_AVR_DIFF8:
+    case R_AVR_DIFF16:
+    case R_AVR_DIFF32:
+      /* Nothing to do here, as contents already contains the diff value. */
+      r = bfd_reloc_ok;
+      break;
+
     default:
       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                    contents, rel->r_offset,
@@ -1457,6 +1531,104 @@ elf32_avr_object_p (bfd *abfd)
                                    e_set);
 }
 
+/* Returns whether the relocation type passed is a diff reloc. */
+
+static bfd_boolean
+elf32_avr_is_diff_reloc (Elf_Internal_Rela *irel)
+{
+  return (ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF8
+          ||ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF16
+          || ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF32);
+}
+
+/* Reduce the diff value written in the section by count if the shrinked 
+   insn address happens to fall between the two symbols for which this 
+   diff reloc was emitted. */
+
+static void
+elf32_avr_adjust_diff_reloc_value (bfd *abfd,
+                                   struct bfd_section *isec,
+                                   Elf_Internal_Rela *irel,
+                                   bfd_vma symval,
+                                   bfd_vma shrinked_insn_address,
+                                   int count)
+{
+  unsigned char *reloc_contents = NULL;
+  unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
+  if (isec_contents == NULL)
+  {
+    if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
+      return;
+
+    elf_section_data (isec)->this_hdr.contents = isec_contents;
+  }
+
+  reloc_contents = isec_contents + irel->r_offset;
+
+  /* Read value written in object file. */
+ bfd_vma x = 0;
+  switch (ELF32_R_TYPE (irel->r_info))
+  {
+  case R_AVR_DIFF8:
+    {
+      x = *reloc_contents;
+      break;
+    }
+  case R_AVR_DIFF16:
+    {
+      x = bfd_get_16 (abfd, reloc_contents);
+      break;
+    }
+  case R_AVR_DIFF32:
+    {
+      x = bfd_get_32 (abfd, reloc_contents);
+      break;
+    }
+  default:
+    {
+      BFD_FAIL();
+    }
+  }
+
+  /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
+     into the object file at the reloc offset. sym2's logical value is
+     symval (<start_of_section>) + reloc addend. Compute the start and end
+     addresses and check if the shrinked insn falls between sym1 and sym2. */
+
+  bfd_vma end_address = symval + irel->r_addend;
+  bfd_vma start_address = end_address - x;
+
+  /* Reduce the diff value by count bytes and write it back into section 
+    contents. */
+
+  if (shrinked_insn_address >= start_address && 
+      shrinked_insn_address <= end_address)
+  {
+    switch (ELF32_R_TYPE (irel->r_info))
+    {
+    case R_AVR_DIFF8:
+      {
+        *reloc_contents = (x - count);
+        break;
+      }
+    case R_AVR_DIFF16:
+      {
+        bfd_put_16 (abfd, (x - count) & 0xFFFF, reloc_contents);
+        break;
+      }
+    case R_AVR_DIFF32:
+      {
+        bfd_put_32 (abfd, (x - count) & 0xFFFFFFFF, reloc_contents);
+        break;
+      }
+    default:
+      {
+        BFD_FAIL();
+      }
+    }
+
+  }
+}
 
 /* Delete some bytes from a section while changing the size of an instruction.
    The parameter "addr" denotes the section-relative offset pointing just
@@ -1595,6 +1767,14 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                    if (symval <= shrinked_insn_address
                        && (symval + irel->r_addend) > shrinked_insn_address)
                      {
+                       if (elf32_avr_is_diff_reloc (irel))
+                         {
+                           elf32_avr_adjust_diff_reloc_value (abfd, isec, irel,
+                                                         symval,
+                                                         shrinked_insn_address,
+                                                        count);
+                         }
+
                        irel->r_addend -= count;
 
                        if (debug_relax)
index 5a7d0e9..7ca3cfd 100644 (file)
@@ -4780,7 +4780,19 @@ ENUM
 ENUMDOC
   This is a 8 bit reloc for the AVR that stores bits 16..23 of a symbol
   in .byte hlo8(symbol)
-
+ENUM
+  BFD_RELOC_AVR_DIFF8
+ENUMX
+  BFD_RELOC_AVR_DIFF16
+ENUMX
+  BFD_RELOC_AVR_DIFF32
+ENUMDOC
+  AVR relocations to mark the difference of two local symbols.
+  These are only needed to support linker relaxation and can be ignored
+  when not relaxing.  The field is set to the value of the difference
+  assuming no relaxation.  The relocation encodes the position of the
+  second symbol so the linker can determine whether to adjust the field
+  value.
 ENUM
   BFD_RELOC_RL78_NEG8
 ENUMX
index 326b47c..d7e5b4a 100644 (file)
@@ -1,3 +1,23 @@
+2014-04-10  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * config/tc-avr.c: Add new flag mlink-relax.
+       (md_show_usage): Add flag and help text.
+       (md_parse_option): Record whether link relax is turned on.
+       (relaxable_section): New.
+       (avr_validate_fix_sub): New.
+       (avr_force_relocation): New.
+       (md_apply_fix): Generate DIFF reloc.
+       (avr_allow_local_subtract): New.
+
+       * config/tc-avr.h (TC_LINKRELAX_FIXUP): Define to 0.
+       (TC_FORCE_RELOCATION): Define.
+       (TC_FORCE_RELOCATION_SUB_SAME): Define.
+       (TC_VALIDATE_FIX_SUB): Define.
+       (avr_force_relocation): Declare.
+       (avr_validate_fix_sub): Declare.
+       (md_allow_local_subtract): Define.
+       (avr_allow_local_subtract): Declare.
+
 2014-04-10  Andrew Bennett  <andrew.bennett@imgtec.com>
 
        * config/tc-mips.c (mips_cpu_info_table): Add P5600
index ce9708e..e4bc59c 100644 (file)
@@ -338,9 +338,11 @@ struct avr_opt_s
   int all_opcodes;  /* -mall-opcodes: accept all known AVR opcodes.  */
   int no_skip_bug;  /* -mno-skip-bug: no warnings for skipping 2-word insns.  */
   int no_wrap;      /* -mno-wrap: reject rjmp/rcall with 8K wrap-around.  */
+  int link_relax;   /* -mlink-relax: generate relocations for linker 
+                       relaxation. */
 };
 
-static struct avr_opt_s avr_opt = { 0, 0, 0 };
+static struct avr_opt_s avr_opt = { 0, 0, 0, 0 };
 
 const char EXP_CHARS[] = "eE";
 const char FLT_CHARS[] = "dD";
@@ -401,7 +403,8 @@ enum options
   OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
   OPTION_NO_SKIP_BUG,
   OPTION_NO_WRAP,
-  OPTION_ISA_RMW
+  OPTION_ISA_RMW,
+  OPTION_LINK_RELAX
 };
 
 struct option md_longopts[] =
@@ -411,6 +414,7 @@ struct option md_longopts[] =
   { "mno-skip-bug", no_argument, NULL, OPTION_NO_SKIP_BUG },
   { "mno-wrap",     no_argument, NULL, OPTION_NO_WRAP     },
   { "mrmw",         no_argument, NULL, OPTION_ISA_RMW     },
+  { "mlink-relax",  no_argument, NULL, OPTION_LINK_RELAX  },
   { NULL, no_argument, NULL, 0 }
 };
 
@@ -517,6 +521,7 @@ md_show_usage (FILE *stream)
        "  -mno-wrap        reject rjmp/rcall instructions with 8K wrap-around\n"
        "                   (default for avr3, avr5)\n"
        "  -mrmw            accept Read-Modify-Write instructions\n"
+    "  -mlink-relax     generate relocations for linker relaxation\n"
     ));
   show_mcu_list (stream);
 }
@@ -587,6 +592,9 @@ md_parse_option (int c, char *arg)
     case OPTION_ISA_RMW:
       specified_mcu.isa |= AVR_ISA_RMW;
       return 1;
+    case OPTION_LINK_RELAX:
+      avr_opt.link_relax = 1;
+      return 1;
     }
 
   return 0;
@@ -637,6 +645,7 @@ md_begin (void)
     }
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
+  linkrelax = avr_opt.link_relax;
 }
 
 /* Resolve STR as a constant expression and return the result.
@@ -1200,6 +1209,53 @@ md_pcrel_from_section (fixS *fixp, segT sec)
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
+static bfd_boolean
+relaxable_section (asection *sec)
+{
+  return (sec->flags & SEC_DEBUGGING) == 0;
+}
+
+/* Does whatever the xtensa port does. */
+int
+avr_validate_fix_sub (fixS *fix)
+{
+  segT add_symbol_segment, sub_symbol_segment;
+
+  /* The difference of two symbols should be resolved by the assembler when
+     linkrelax is not set.  If the linker may relax the section containing
+     the symbols, then an Xtensa DIFF relocation must be generated so that
+     the linker knows to adjust the difference value.  */
+  if (!linkrelax || fix->fx_addsy == NULL)
+    return 0;
+
+  /* Make sure both symbols are in the same segment, and that segment is
+     "normal" and relaxable.  If the segment is not "normal", then the
+     fix is not valid.  If the segment is not "relaxable", then the fix
+     should have been handled earlier.  */
+  add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
+  if (! SEG_NORMAL (add_symbol_segment) ||
+      ! relaxable_section (add_symbol_segment))
+    return 0;
+
+  sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
+  return (sub_symbol_segment == add_symbol_segment);
+}
+
+/* TC_FORCE_RELOCATION hook */
+
+/* If linkrelax is turned on, and the symbol to relocate
+   against is in a relaxable segment, don't compute the value -
+   generate a relocation instead. */
+int
+avr_force_relocation (fixS *fix)
+{
+  if (linkrelax && fix->fx_addsy
+      && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
+    return 1;
+
+  return generic_force_reloc (fix);
+}
+
 /* GAS will call this for each fixup.  It should store the correct
    value in the object file.  */
 
@@ -1223,11 +1279,47 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
          fixP->fx_done = 1;
        }
     }
-
+  else if (linkrelax && fixP->fx_subsy)
+    {
+      /* For a subtraction relocation expression, generate one
+         of the DIFF relocs, with the value being the difference.
+         Note that a sym1 - sym2 expression is adjusted into a
+         section_start_sym + sym4_offset_from_section_start - sym1
+         expression. fixP->fx_addsy holds the section start symbol,
+         fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
+         holds sym1. Calculate the current difference and write value,
+         but leave fx_offset as is - during relaxation, 
+         fx_offset - value gives sym1's value */
+
+       switch (fixP->fx_r_type)
+         {
+           case BFD_RELOC_8:
+             fixP->fx_r_type = BFD_RELOC_AVR_DIFF8;
+             break;
+           case BFD_RELOC_16:
+             fixP->fx_r_type = BFD_RELOC_AVR_DIFF16;
+             break;
+           case BFD_RELOC_32:
+             fixP->fx_r_type = BFD_RELOC_AVR_DIFF32;
+             break;
+           default:
+             as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+             break;
+         }
+
+      value = S_GET_VALUE (fixP->fx_addsy) +
+          fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy);
+
+      fixP->fx_subsy = NULL;
+  }
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
     as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
 
+  /* For the DIFF relocs, write the value into the object file while still
+     keeping fx_done FALSE, as both the difference (recorded in the object file)
+     and the sym offset (part of fixP) are needed at link relax time */
+  where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
   switch (fixP->fx_r_type)
     {
     default:
@@ -1237,6 +1329,16 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
     case BFD_RELOC_AVR_13_PCREL:
     case BFD_RELOC_32:
     case BFD_RELOC_16:
+      break;
+    case BFD_RELOC_AVR_DIFF8:
+      *where = value;
+         break;
+    case BFD_RELOC_AVR_DIFF16:
+      bfd_putl16 ((bfd_vma) value, where);
+      break;
+    case BFD_RELOC_AVR_DIFF32:
+      bfd_putl32 ((bfd_vma) value, where);
+      break;
     case BFD_RELOC_AVR_CALL:
       break;
     }
@@ -1654,3 +1756,25 @@ tc_cfi_frame_initial_instructions (void)
      do not line up the same way as for targers that use pre-decrement.  */
   cfi_add_CFA_offset (DWARF2_DEFAULT_RETURN_COLUMN, 1-return_size);
 }
+
+bfd_boolean
+avr_allow_local_subtract (expressionS * left,
+                            expressionS * right,
+                            segT section)
+{
+  /* If we are not in relaxation mode, subtraction is OK. */
+  if (!linkrelax)
+    return TRUE;
+
+  /* If the symbols are not in a code section then they are OK.  */
+  if ((section->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  if (left->X_add_symbol == right->X_add_symbol)
+    return TRUE;
+
+  /* We have to assume that there may be instructions between the
+     two symbols and that relaxation may increase the distance between
+     them.  */
+  return FALSE;
+}
index df75ac7..fb596ad 100644 (file)
@@ -112,6 +112,18 @@ extern void avr_cons_fix_new (fragS *,int, int, expressionS *,
    visible symbols can be overridden.  */
 #define EXTERN_FORCE_RELOC 0
 
+/* If defined, this macro allows control over whether fixups for a
+   given section will be processed when the linkrelax variable is
+   set. Define it to zero and handle things in md_apply_fix instead.*/
+#define TC_LINKRELAX_FIXUP(SEG) 0
+
+/* If this macro returns non-zero, it guarantees that a relocation will be emitted
+   even when the value can be resolved locally. Do that if linkrelax is turned on */
+#define TC_FORCE_RELOCATION(fix)       avr_force_relocation (fix)
+#define TC_FORCE_RELOCATION_SUB_SAME(fix, seg) \
+  (! SEG_NORMAL (seg) || avr_force_relocation (fix))
+extern int avr_force_relocation (struct fix *);
+
 /* Values passed to md_apply_fix don't include the symbol value.  */
 #define MD_APPLY_SYM_VALUE(FIX) 0
 
@@ -169,6 +181,12 @@ extern long md_pcrel_from_section (struct fix *, segT);
       goto SKIP;                                            \
     }
 
+/* This macro is evaluated for any fixup with a fx_subsy that
+   fixup_segment cannot reduce to a number.  If the macro returns
+   false an error will be reported. */
+#define TC_VALIDATE_FIX_SUB(fix, seg)   avr_validate_fix_sub (fix)
+extern int avr_validate_fix_sub (struct fix *);
+
 /* This target is buggy, and sets fix size too large.  */
 #define TC_FX_SIZE_SLACK(FIX) 2
 
@@ -190,3 +208,8 @@ extern long md_pcrel_from_section (struct fix *, segT);
 /* Define a hook to setup initial CFI state.  */
 extern void tc_cfi_frame_initial_instructions (void);
 #define tc_cfi_frame_initial_instructions tc_cfi_frame_initial_instructions
+
+/* The difference between same-section symbols may be affected by linker
+   relaxation, so do not resolve such expressions in the assembler.  */
+#define md_allow_local_subtract(l,r,s) avr_allow_local_subtract (l, r, s)
+extern bfd_boolean avr_allow_local_subtract (expressionS *, expressionS *, segT);
index 61b42dd..30d957d 100644 (file)
@@ -1,3 +1,9 @@
+2014-04-10  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * gas/avr/diffreloc_withrelax.d: New testcase.
+       * gas/avr/noreloc_withoutrelax.d: Likewise.
+       * gas/avr/relax.s: Likewise.
+
 2014-04-04  Ilya Tocar  <ilya.tocar@intel.com>
 
        * gas/i386/i386.exp: Run SE1 tests.
diff --git a/gas/testsuite/gas/avr/diffreloc_withrelax.d b/gas/testsuite/gas/avr/diffreloc_withrelax.d
new file mode 100644 (file)
index 0000000..6d5bd2e
--- /dev/null
@@ -0,0 +1,16 @@
+#name: AVR DIFF relocs with link relax
+#as: -mmcu=avrxmega2 -mlink-relax
+#source: relax.s
+#objdump: -r
+#target: avr-*-*
+
+.*:     file format elf32-avr
+
+RELOCATION RECORDS FOR \[.text\]:
+OFFSET   TYPE              VALUE 
+00000000 R_AVR_CALL        .text
+
+
+RELOCATION RECORDS FOR \[.data\]:
+OFFSET   TYPE              VALUE 
+00000000 R_AVR_DIFF16      .text\+0x00000004
diff --git a/gas/testsuite/gas/avr/noreloc_withoutrelax.d b/gas/testsuite/gas/avr/noreloc_withoutrelax.d
new file mode 100644 (file)
index 0000000..daaaeb2
--- /dev/null
@@ -0,0 +1,11 @@
+#name: AVR no DIFF relocs without link relax
+#as: -mmcu=avrxmega2
+#objdump: -r
+#source: relax.s
+#target: avr-*-*
+
+.*:     file format elf32-avr
+
+RELOCATION RECORDS FOR \[.text\]:
+OFFSET   TYPE              VALUE 
+00000000 R_AVR_CALL        .text
diff --git a/gas/testsuite/gas/avr/relax.s b/gas/testsuite/gas/avr/relax.s
new file mode 100644 (file)
index 0000000..dc6b262
--- /dev/null
@@ -0,0 +1,12 @@
+    .file "diffreloc.s"
+.section       .text,"ax",@progbits
+main:
+L1:
+    jmp  L1
+L2:
+.global        x
+       .section .data
+       .type   x, @object
+       .size   x, 2
+x:
+       .word   L2 - L1
index a0fc40b..eb0543b 100644 (file)
@@ -1,3 +1,7 @@
+2014-04-10  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * elf/avr.h: Add new DIFF relocs.
+
 2014-03-05  Alan Modra  <amodra@gmail.com>
 
        Update copyright years.
index 5480dd4..06a7f13 100644 (file)
@@ -80,6 +80,9 @@ START_RELOC_NUMBERS (elf_avr_reloc_type)
      RELOC_NUMBER (R_AVR_8_LO8,                27)
      RELOC_NUMBER (R_AVR_8_HI8,                28)
      RELOC_NUMBER (R_AVR_8_HLO8,               29)
+     RELOC_NUMBER (R_AVR_DIFF8,                30)
+     RELOC_NUMBER (R_AVR_DIFF16,               31)
+     RELOC_NUMBER (R_AVR_DIFF32,               32)
 END_RELOC_NUMBERS (R_AVR_max)
 
 #endif /* _ELF_AVR_H */
index cbc12f6..e239ce8 100644 (file)
@@ -1,3 +1,9 @@
+2014-04-10  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       * ld-avr/norelax_diff.d: New testcase.
+       * ld-avr/relax_diff.d: Likewise.
+       * ld-avr/relax.s: Likewise.
+
 2014-04-05  Andreas Schwab  <schwab@linux-m68k.org>
 
        * ld-plugin/lto.exp: Make "-Wp," prefix optional when filtering
diff --git a/ld/testsuite/ld-avr/avr.exp b/ld/testsuite/ld-avr/avr.exp
new file mode 100644 (file)
index 0000000..d196d96
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2014
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  
+
+#
+# Some AVR tests
+#
+
+if {![istarget avr-*-*]} {
+    return
+}
+
+set avr_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+foreach avr_test $avr_test_list {
+    verbose [file rootname $avr_test]
+    run_dump_test [file rootname $avr_test]
+}
+
diff --git a/ld/testsuite/ld-avr/norelax_diff.d b/ld/testsuite/ld-avr/norelax_diff.d
new file mode 100644 (file)
index 0000000..1891d6e
--- /dev/null
@@ -0,0 +1,13 @@
+#name: AVR No change in behavior without relaxation
+#as: -mmcu=avrxmega2 
+#ld:  -mavrxmega2
+#source: relax.s
+#objdump: -s
+#target: avr-*-*
+
+.*:     file format elf32-avr
+
+Contents of section .text:
+ 0000 0c940000                             .*
+Contents of section .data:
+ 802000 0400                               .* 
diff --git a/ld/testsuite/ld-avr/relax.s b/ld/testsuite/ld-avr/relax.s
new file mode 100644 (file)
index 0000000..fbb7bae
--- /dev/null
@@ -0,0 +1,12 @@
+    .file "relax.s"
+.section       .text,"ax",@progbits
+main:
+L1:
+    jmp  L1
+L2:
+.global        x
+       .section .data
+       .type   x, @object
+       .size   x, 2
+x:
+       .word   L2 - L1
diff --git a/ld/testsuite/ld-avr/relax_diff.d b/ld/testsuite/ld-avr/relax_diff.d
new file mode 100644 (file)
index 0000000..b84df81
--- /dev/null
@@ -0,0 +1,14 @@
+#name: AVR Account for relaxation in label differences
+#as: -mmcu=avrxmega2 -mlink-relax
+#ld:  -mavrxmega2 --relax
+#source: relax.s
+#objdump: -s
+#target: avr-*-*
+
+.*:     file format elf32-avr
+
+Contents of section .text:
+ 0000 ffcf                                 .*
+Contents of section .data:
+ 802000 0200                               .*
+