From e4ef1b6c3fee295ab41138bf77a82dff16f1d7c3 Mon Sep 17 00:00:00 2001 From: Denis Chertykov Date: Thu, 10 Apr 2014 19:50:33 +0400 Subject: [PATCH] bfd/ChangeLog * 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. --- bfd/ChangeLog | 12 ++ bfd/elf32-avr.c | 182 ++++++++++++++++++++++++++- bfd/reloc.c | 14 ++- gas/ChangeLog | 20 +++ gas/config/tc-avr.c | 130 ++++++++++++++++++- gas/config/tc-avr.h | 23 ++++ gas/testsuite/ChangeLog | 6 + gas/testsuite/gas/avr/diffreloc_withrelax.d | 16 +++ gas/testsuite/gas/avr/noreloc_withoutrelax.d | 11 ++ gas/testsuite/gas/avr/relax.s | 12 ++ include/ChangeLog | 4 + include/elf/avr.h | 3 + ld/testsuite/ChangeLog | 6 + ld/testsuite/ld-avr/avr.exp | 31 +++++ ld/testsuite/ld-avr/norelax_diff.d | 13 ++ ld/testsuite/ld-avr/relax.s | 12 ++ ld/testsuite/ld-avr/relax_diff.d | 14 +++ 17 files changed, 504 insertions(+), 5 deletions(-) create mode 100644 gas/testsuite/gas/avr/diffreloc_withrelax.d create mode 100644 gas/testsuite/gas/avr/noreloc_withoutrelax.d create mode 100644 gas/testsuite/gas/avr/relax.s create mode 100644 ld/testsuite/ld-avr/avr.exp create mode 100644 ld/testsuite/ld-avr/norelax_diff.d create mode 100644 ld/testsuite/ld-avr/relax.s create mode 100644 ld/testsuite/ld-avr/relax_diff.d diff --git a/bfd/ChangeLog b/bfd/ChangeLog index e38c6a4..0fc016c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2014-04-10 Senthil Kumar Selvaraj + + * 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 * libcoff.h: Regenerate. diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c index 3fd43c9..425e2d1 100644 --- a/bfd/elf32-avr.c +++ b/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 () + 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 a/bfd/reloc.c b/bfd/reloc.c index 5a7d0e9..7ca3cfd 100644 --- a/bfd/reloc.c +++ b/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 a/gas/ChangeLog b/gas/ChangeLog index 326b47c..d7e5b4a 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,23 @@ +2014-04-10 Senthil Kumar Selvaraj + + * 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 * config/tc-mips.c (mips_cpu_info_table): Add P5600 diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c index ce9708e..e4bc59c 100644 --- a/gas/config/tc-avr.c +++ b/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; } @@ -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; +} diff --git a/gas/config/tc-avr.h b/gas/config/tc-avr.h index df75ac7..fb596ad 100644 --- a/gas/config/tc-avr.h +++ b/gas/config/tc-avr.h @@ -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); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 61b42dd..30d957d 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-04-10 Senthil Kumar Selvaraj + + * gas/avr/diffreloc_withrelax.d: New testcase. + * gas/avr/noreloc_withoutrelax.d: Likewise. + * gas/avr/relax.s: Likewise. + 2014-04-04 Ilya Tocar * 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 index 0000000..6d5bd2e --- /dev/null +++ b/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 a/gas/testsuite/gas/avr/noreloc_withoutrelax.d b/gas/testsuite/gas/avr/noreloc_withoutrelax.d new file mode 100644 index 0000000..daaaeb2 --- /dev/null +++ b/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 a/gas/testsuite/gas/avr/relax.s b/gas/testsuite/gas/avr/relax.s new file mode 100644 index 0000000..dc6b262 --- /dev/null +++ b/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 a/include/ChangeLog b/include/ChangeLog index a0fc40b..eb0543b 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2014-04-10 Senthil Kumar Selvaraj + + * elf/avr.h: Add new DIFF relocs. + 2014-03-05 Alan Modra Update copyright years. diff --git a/include/elf/avr.h b/include/elf/avr.h index 5480dd4..06a7f13 100644 --- a/include/elf/avr.h +++ b/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 a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index cbc12f6..e239ce8 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-04-10 Senthil Kumar Selvaraj + + * ld-avr/norelax_diff.d: New testcase. + * ld-avr/relax_diff.d: Likewise. + * ld-avr/relax.s: Likewise. + 2014-04-05 Andreas Schwab * 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 index 0000000..d196d96 --- /dev/null +++ b/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 a/ld/testsuite/ld-avr/norelax_diff.d b/ld/testsuite/ld-avr/norelax_diff.d new file mode 100644 index 0000000..1891d6e --- /dev/null +++ b/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 a/ld/testsuite/ld-avr/relax.s b/ld/testsuite/ld-avr/relax.s new file mode 100644 index 0000000..fbb7bae --- /dev/null +++ b/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 a/ld/testsuite/ld-avr/relax_diff.d b/ld/testsuite/ld-avr/relax_diff.d new file mode 100644 index 0000000..b84df81 --- /dev/null +++ b/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 .* + -- 2.7.4