1 diff -Naurp bfd/elf32-avr.c bfd/elf32-avr.c
2 --- bfd/elf32-avr.c 2013-01-02 16:27:32.000000000 +0530
3 +++ bfd/elf32-avr.c 2013-01-02 16:28:50.000000000 +0530
4 @@ -34,6 +34,15 @@ static bfd_boolean debug_relax = FALSE;
5 /* Enable debugging printout at stdout with this variable. */
6 static bfd_boolean debug_stubs = FALSE;
8 +static bfd_reloc_status_type
9 +bfd_elf_avr_diff_reloc (bfd *abfd,
10 + arelent *reloc_entry,
13 + asection *input_section,
15 + char **error_message);
17 /* Hash table initialization and handling. Code is taken from the hppa port
18 and adapted to the needs of AVR. */
20 @@ -573,6 +582,45 @@ static reloc_howto_type elf_avr_howto_ta
21 0xffff, /* src_mask */
22 0xffff, /* dst_mask */
23 FALSE), /* pcrel_offset */
24 + HOWTO (R_AVR_DIFF8, /* type */
26 + 0, /* size (0 = byte, 1 = short, 2 = long) */
28 + FALSE, /* pc_relative */
30 + complain_overflow_bitfield, /* complain_on_overflow */
31 + bfd_elf_avr_diff_reloc, /* special_function */
32 + "R_AVR_DIFF8", /* name */
33 + FALSE, /* partial_inplace */
35 + 0xff, /* dst_mask */
36 + FALSE), /* pcrel_offset */
37 + HOWTO (R_AVR_DIFF16, /* type */
39 + 1, /* size (0 = byte, 1 = short, 2 = long) */
41 + FALSE, /* pc_relative */
43 + complain_overflow_bitfield, /* complain_on_overflow */
44 + bfd_elf_avr_diff_reloc, /* special_function */
45 + "R_AVR_DIFF16", /* name */
46 + FALSE, /* partial_inplace */
48 + 0xffff, /* dst_mask */
49 + FALSE), /* pcrel_offset */
50 + HOWTO (R_AVR_DIFF32, /* type */
52 + 2, /* size (0 = byte, 1 = short, 2 = long) */
54 + FALSE, /* pc_relative */
56 + complain_overflow_bitfield, /* complain_on_overflow */
57 + bfd_elf_avr_diff_reloc, /* special_function */
58 + "R_AVR_DIFF32", /* name */
59 + FALSE, /* partial_inplace */
61 + 0xffffffff, /* dst_mask */
62 + FALSE) /* pcrel_offset */
65 /* Map BFD reloc types to AVR ELF reloc types. */
66 @@ -615,7 +663,10 @@ static const struct avr_reloc_map avr_re
67 { BFD_RELOC_AVR_8_LO, R_AVR_8_LO8 },
68 { BFD_RELOC_AVR_8_HI, R_AVR_8_HI8 },
69 { BFD_RELOC_AVR_8_HLO, R_AVR_8_HLO8 },
70 - { BFD_RELOC_AVR_7_LDS16, R_AVR_7_LDS16 }
71 + { BFD_RELOC_AVR_7_LDS16, R_AVR_7_LDS16 },
72 + { BFD_RELOC_AVR_DIFF8, R_AVR_DIFF8 },
73 + { BFD_RELOC_AVR_DIFF16, R_AVR_DIFF16 },
74 + { BFD_RELOC_AVR_DIFF32, R_AVR_DIFF32 }
77 /* Meant to be filled one day with the wrap around address for the
78 @@ -823,6 +874,22 @@ avr_get_stub_addr (bfd_vma srel,
82 +/* Perform a diff relocation. Nothing to do, as the difference value is already
83 + written into the section's contents. */
85 +static bfd_reloc_status_type
86 +bfd_elf_avr_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED,
87 + arelent *reloc_entry ATTRIBUTE_UNUSED,
88 + asymbol *symbol ATTRIBUTE_UNUSED,
89 + void *data ATTRIBUTE_UNUSED,
90 + asection *input_section ATTRIBUTE_UNUSED,
91 + bfd *output_bfd ATTRIBUTE_UNUSED,
92 + char **error_message ATTRIBUTE_UNUSED)
94 + return bfd_reloc_ok;
98 /* Perform a single relocation. By default we use the standard BFD
99 routines, but a few relocs, we have to do them ourselves. */
101 @@ -1186,6 +1253,13 @@ avr_final_link_relocate (reloc_howto_typ
102 bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents);
108 + /* Nothing to do here, as contents already contains the diff value. */
113 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
114 contents, rel->r_offset,
115 @@ -1502,6 +1576,99 @@ elf32_avr_object_p (bfd *abfd)
119 +/* Returns whether the relocation type passed is a diff reloc. */
122 +elf32_avr_is_diff_reloc (Elf_Internal_Rela *irel)
124 + return (ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF8
125 + ||ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF16
126 + || ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF32);
129 +/* Reduce the value written in the section by count if the shrinked insn address
130 + happens to fall between the two symbols for which this diff reloc was
134 +elf32_avr_adjust_diff_reloc_value (bfd *abfd,
135 + struct bfd_section *isec,
136 + Elf_Internal_Rela *irel,
138 + bfd_vma shrinked_insn_address,
141 + unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
142 + if (isec_contents == NULL)
144 + if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
148 + isec_contents += irel->r_offset;
150 + /* Read value written in object file. */
152 + switch (ELF32_R_TYPE (irel->r_info))
156 + x = *isec_contents;
161 + x = bfd_get_16 (abfd, isec_contents);
166 + x = bfd_get_32 (abfd, isec_contents);
175 + /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
176 + into the object file. sym2's value is represented as
177 + <start_of_section> + addend. Check if the shrinked insn falls between
180 + bfd_vma end_address = symval + irel->r_addend;
181 + bfd_vma start_address = end_address - x;
183 + if (shrinked_insn_address >= start_address &&
184 + shrinked_insn_address <= end_address)
186 + switch (ELF32_R_TYPE (irel->r_info))
190 + *isec_contents = (x - count);
195 + bfd_put_16 (abfd, (x - count) & 0xFFFF, isec_contents);
200 + bfd_put_32 (abfd, (x - count) & 0xFFFFFFFF, isec_contents);
209 + elf_section_data (isec)->this_hdr.contents = isec_contents - irel->r_offset;
213 /* Delete some bytes from a section while changing the size of an instruction.
214 The parameter "addr" denotes the section-relative offset pointing just
215 @@ -1640,6 +1807,14 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
216 if (symval <= shrinked_insn_address
217 && (symval + irel->r_addend) > shrinked_insn_address)
219 + if (elf32_avr_is_diff_reloc (irel))
221 + elf32_avr_adjust_diff_reloc_value (abfd, isec, irel,
223 + shrinked_insn_address,
227 irel->r_addend -= count;
230 diff -Naurp bfd/reloc.c bfd/reloc.c
231 --- bfd/reloc.c 2013-01-02 16:27:32.000000000 +0530
232 +++ bfd/reloc.c 2013-01-02 16:28:50.000000000 +0530
233 @@ -4414,6 +4414,19 @@ ENUM
235 This is a 7 bit reloc for the AVR that stores offset for 16bit sts/lds
236 instructions supported only by Tiny core
238 + BFD_RELOC_AVR_DIFF8
240 + BFD_RELOC_AVR_DIFF16
242 + BFD_RELOC_AVR_DIFF32
244 + AVR relocations to mark the difference of two local symbols.
245 + These are only needed to support linker relaxation and can be ignored
246 + when not relaxing. The field is set to the value of the difference
247 + assuming no relaxation. The relocation encodes the position of the
248 + second symbol so the linker can determine whether to adjust the field
253 diff -Naurp gas/config/tc-avr.c gas/config/tc-avr.c
254 --- gas/config/tc-avr.c 2013-01-02 16:28:02.000000000 +0530
255 +++ gas/config/tc-avr.c 2013-01-02 16:28:50.000000000 +0530
256 @@ -342,9 +342,11 @@ struct avr_opt_s
257 int all_opcodes; /* -mall-opcodes: accept all known AVR opcodes. */
258 int no_skip_bug; /* -mno-skip-bug: no warnings for skipping 2-word insns. */
259 int no_wrap; /* -mno-wrap: reject rjmp/rcall with 8K wrap-around. */
260 + int link_relax; /* -mlink-relax: generate relocations for linker
264 -static struct avr_opt_s avr_opt = { 0, 0, 0 };
265 +static struct avr_opt_s avr_opt = { 0, 0, 0, 0 };
267 const char EXP_CHARS[] = "eE";
268 const char FLT_CHARS[] = "dD";
269 @@ -404,7 +406,8 @@ enum options
271 OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
278 struct option md_longopts[] =
279 @@ -413,6 +416,7 @@ struct option md_longopts[] =
280 { "mall-opcodes", no_argument, NULL, OPTION_ALL_OPCODES },
281 { "mno-skip-bug", no_argument, NULL, OPTION_NO_SKIP_BUG },
282 { "mno-wrap", no_argument, NULL, OPTION_NO_WRAP },
283 + { "mlink-relax", no_argument, NULL, OPTION_LINK_RELAX },
284 { NULL, no_argument, NULL, 0 }
287 @@ -518,7 +522,9 @@ md_show_usage (FILE *stream)
288 " -mno-skip-bug disable warnings for skipping two-word instructions\n"
289 " (default for avr4, avr5)\n"
290 " -mno-wrap reject rjmp/rcall instructions with 8K wrap-around\n"
291 - " (default for avr3, avr5)\n"));
292 + " (default for avr3, avr5)\n"
293 + " -mlink-relax generate relocations for linker relaxation\n"
295 show_mcu_list (stream);
298 @@ -580,6 +586,9 @@ md_parse_option (int c, char *arg)
302 + case OPTION_LINK_RELAX:
303 + avr_opt.link_relax = 1;
308 @@ -630,6 +639,7 @@ md_begin (void)
311 bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
312 + linkrelax = avr_opt.link_relax;
315 /* Resolve STR as a constant expression and return the result.
316 @@ -1205,6 +1215,53 @@ md_pcrel_from_section (fixS *fixp, segT
317 return fixp->fx_frag->fr_address + fixp->fx_where;
321 +relaxable_section (asection *sec)
323 + return (sec->flags & SEC_DEBUGGING) == 0;
326 +/* Does whatever the xtensa port does. */
328 +avr_validate_fix_sub (fixS *fix)
330 + segT add_symbol_segment, sub_symbol_segment;
332 + /* The difference of two symbols should be resolved by the assembler when
333 + linkrelax is not set. If the linker may relax the section containing
334 + the symbols, then an Xtensa DIFF relocation must be generated so that
335 + the linker knows to adjust the difference value. */
336 + if (!linkrelax || fix->fx_addsy == NULL)
339 + /* Make sure both symbols are in the same segment, and that segment is
340 + "normal" and relaxable. If the segment is not "normal", then the
341 + fix is not valid. If the segment is not "relaxable", then the fix
342 + should have been handled earlier. */
343 + add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
344 + if (! SEG_NORMAL (add_symbol_segment) ||
345 + ! relaxable_section (add_symbol_segment))
348 + sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
349 + return (sub_symbol_segment == add_symbol_segment);
352 +/* TC_FORCE_RELOCATION hook */
354 +/* If linkrelax is turned on, and the symbol to relocate
355 + against is in a relaxable segment, don't compute the value -
356 + generate a relocation instead. */
358 +avr_force_relocation (fixS *fix)
360 + if (linkrelax && fix->fx_addsy
361 + && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
364 + return generic_force_reloc (fix);
367 /* GAS will call this for each fixup. It should store the correct
368 value in the object file. */
370 @@ -1228,11 +1285,46 @@ md_apply_fix (fixS *fixP, valueT * valP,
374 + else if (linkrelax && fixP->fx_subsy)
376 + /* For a subtraction relocation expression, generate one
377 + of the DIFF relocs, with the value being the difference.
378 + Note that a sym1 - sym2 expression is adjusted into a
379 + section_start_sym + sym2_offset_from_section_start - sym1
380 + expression. fixP->fx_addsy holds the section start symbol,
381 + fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
382 + holds sym1. Calculate and write value, but leave fx_offset
383 + as is - during relaxation, fx_offset - value gives sym1's value */
385 + switch (fixP->fx_r_type)
388 + fixP->fx_r_type = BFD_RELOC_AVR_DIFF8;
391 + fixP->fx_r_type = BFD_RELOC_AVR_DIFF16;
394 + fixP->fx_r_type = BFD_RELOC_AVR_DIFF32;
397 + as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
401 + value = S_GET_VALUE (fixP->fx_addsy) +
402 + fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy);
404 + fixP->fx_subsy = NULL;
406 /* We don't actually support subtracting a symbol. */
407 if (fixP->fx_subsy != (symbolS *) NULL)
408 as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
410 + /* For the DIFF relocs, write the value into the object file while still
411 + keeping fx_done FALSE, as both the difference (recorded in the object file)
412 + and the sym offset (part of fixP) are needed at link relax time */
413 + where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
414 switch (fixP->fx_r_type)
417 @@ -1242,6 +1334,19 @@ md_apply_fix (fixS *fixP, valueT * valP,
418 case BFD_RELOC_AVR_13_PCREL:
422 + case BFD_RELOC_AVR_DIFF8:
423 + if (value > 255 || value < -128)
424 + as_warn_where (fixP->fx_file, fixP->fx_line,
425 + _("operand out of range: %ld"), value);
428 + case BFD_RELOC_AVR_DIFF16:
429 + bfd_putl16 ((bfd_vma) value, where);
431 + case BFD_RELOC_AVR_DIFF32:
432 + bfd_putl16 ((bfd_vma) value, where);
434 case BFD_RELOC_AVR_CALL:
437 diff -Naurp gas/config/tc-avr.h gas/config/tc-avr.h
438 --- gas/config/tc-avr.h 2011-03-29 23:46:15.000000000 +0530
439 +++ gas/config/tc-avr.h 2013-01-02 16:28:50.000000000 +0530
440 @@ -93,6 +93,18 @@ extern void avr_cons_fix_new (fragS *,in
441 visible symbols can be overridden. */
442 #define EXTERN_FORCE_RELOC 0
444 +/* If defined, this macro allows control over whether fixups for a
445 + given section will be processed when the linkrelax variable is
446 + set. Define it to zero and handle things in md_apply_fix instead.*/
447 +#define TC_LINKRELAX_FIXUP(SEG) 0
449 +/* If this macro returns non-zero, it guarantees that a relocation will be emitted
450 + even when the value can be resolved locally. Do that if linkrelax is turned on */
451 +#define TC_FORCE_RELOCATION(fix) avr_force_relocation (fix)
452 +#define TC_FORCE_RELOCATION_SUB_SAME(fix, seg) \
453 + (! SEG_NORMAL (seg) || avr_force_relocation (fix))
454 +extern int avr_force_relocation (struct fix *);
456 /* Values passed to md_apply_fix don't include the symbol value. */
457 #define MD_APPLY_SYM_VALUE(FIX) 0
459 @@ -144,6 +156,12 @@ extern long md_pcrel_from_section (struc
464 +/* This macro is evaluated for any fixup with a fx_subsy that
465 + fixup_segment cannot reduce to a number. If the macro returns
466 + false an error will be reported. */
467 +#define TC_VALIDATE_FIX_SUB(fix, seg) avr_validate_fix_sub (fix)
468 +extern int avr_validate_fix_sub (struct fix *);
470 /* This target is buggy, and sets fix size too large. */
471 #define TC_FX_SIZE_SLACK(FIX) 2
472 diff -Naurp include/elf/avr.h include/elf/avr.h
473 --- include/elf/avr.h 2013-01-02 16:27:32.000000000 +0530
474 +++ include/elf/avr.h 2013-01-02 16:28:50.000000000 +0530
475 @@ -83,6 +83,9 @@ START_RELOC_NUMBERS (elf_avr_reloc_type)
476 RELOC_NUMBER (R_AVR_8_HI8, 28)
477 RELOC_NUMBER (R_AVR_8_HLO8, 29)
478 RELOC_NUMBER (R_AVR_7_LDS16, 30)
479 + RELOC_NUMBER (R_AVR_DIFF8, 31)
480 + RELOC_NUMBER (R_AVR_DIFF16, 32)
481 + RELOC_NUMBER (R_AVR_DIFF32, 33)
482 END_RELOC_NUMBERS (R_AVR_max)
484 #endif /* _ELF_AVR_H */