This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, avr] Add DIFF relocations


This patch adds DIFF relocations to the AVR target. Until now, the
assembler computed symbol differences at assembly time, but this does
not work well with linker relaxation. For example, the changes Nick 
made to DWARF line number information 
(https://sourceware.org/ml/binutils/2012-06/msg00234.html) did not work
because the generated fixups were still being resolved at assembly time.

This patch is based a lot on how the xtensa target handles this problem. 
It adds three DIFF relocation types (for 8, 16 and 32 bit diffs) and 
makes the assembler and the linker aware of them. The difference at 
assembly time is written into the object file by the assembler, 
and the linker adjusts it after relaxation.

The generation of DIFF relocations is controlled by a new assembler flag
(mlink-relax) - without the flag, there will no change from the current
behavior. I have a patch for gcc that automatically passes mlink-relax
to the assembler if -mrelax is passed to the gcc driver.

I also have a couple of assembler and linker tests to verify relocation
generation by the assembler and resolution by the linker.

I have not attached generated files with the patch. If ok, could someone
apply please? I don't have commit access.

Regards
Senthil

bfd/ChangeLog

2014-04-09  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

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.


diff --git bfd/elf32-avr.c bfd/elf32-avr.c
index 3fd43c9..425e2d1 100644
--- bfd/elf32-avr.c
+++ bfd/elf32-avr.c
@@ -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)
diff --git bfd/reloc.c bfd/reloc.c
index 5a7d0e9..7ca3cfd 100644
--- bfd/reloc.c
+++ bfd/reloc.c
@@ -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
diff --git gas/config/tc-avr.c gas/config/tc-avr.c
index 5049d11..ef9eb0c 100644
--- gas/config/tc-avr.c
+++ gas/config/tc-avr.c
@@ -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;
     }
@@ -1674,3 +1776,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;
+}
diff --git gas/config/tc-avr.h gas/config/tc-avr.h
index caa058f..8fdfb9c 100644
--- gas/config/tc-avr.h
+++ gas/config/tc-avr.h
@@ -92,6 +92,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
 
@@ -149,6 +161,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
 
@@ -170,3 +188,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);
diff --git gas/testsuite/gas/avr/diffreloc_withrelax.d gas/testsuite/gas/avr/diffreloc_withrelax.d
new file mode 100644
index 0000000..6d5bd2e
--- /dev/null
+++ gas/testsuite/gas/avr/diffreloc_withrelax.d
@@ -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 gas/testsuite/gas/avr/noreloc_withoutrelax.d gas/testsuite/gas/avr/noreloc_withoutrelax.d
new file mode 100644
index 0000000..daaaeb2
--- /dev/null
+++ gas/testsuite/gas/avr/noreloc_withoutrelax.d
@@ -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 gas/testsuite/gas/avr/relax.s gas/testsuite/gas/avr/relax.s
new file mode 100644
index 0000000..dc6b262
--- /dev/null
+++ gas/testsuite/gas/avr/relax.s
@@ -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
diff --git include/elf/avr.h include/elf/avr.h
index 5480dd4..06a7f13 100644
--- include/elf/avr.h
+++ include/elf/avr.h
@@ -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 */
diff --git ld/testsuite/ld-avr/avr.exp ld/testsuite/ld-avr/avr.exp
new file mode 100644
index 0000000..d196d96
--- /dev/null
+++ ld/testsuite/ld-avr/avr.exp
@@ -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 ld/testsuite/ld-avr/norelax_diff.d ld/testsuite/ld-avr/norelax_diff.d
new file mode 100644
index 0000000..1891d6e
--- /dev/null
+++ ld/testsuite/ld-avr/norelax_diff.d
@@ -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 ld/testsuite/ld-avr/relax.s ld/testsuite/ld-avr/relax.s
new file mode 100644
index 0000000..fbb7bae
--- /dev/null
+++ ld/testsuite/ld-avr/relax.s
@@ -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 ld/testsuite/ld-avr/relax_diff.d ld/testsuite/ld-avr/relax_diff.d
new file mode 100644
index 0000000..b84df81
--- /dev/null
+++ ld/testsuite/ld-avr/relax_diff.d
@@ -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                               .*
+


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]