]> git.pld-linux.org Git - packages/crossavr-binutils.git/blame - 009-dwarf-relax-fix.patch
- release 2 (x32 rebuild)
[packages/crossavr-binutils.git] / 009-dwarf-relax-fix.patch
CommitLineData
31ce1ede
JR
1diff -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;
7
8+static bfd_reloc_status_type
9+bfd_elf_avr_diff_reloc (bfd *abfd,
10+ arelent *reloc_entry,
11+ asymbol *symbol,
12+ void *data,
13+ asection *input_section,
14+ bfd *output_bfd,
15+ char **error_message);
16+
17 /* Hash table initialization and handling. Code is taken from the hppa port
18 and adapted to the needs of AVR. */
19
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 */
25+ 0, /* rightshift */
26+ 0, /* size (0 = byte, 1 = short, 2 = long) */
27+ 8, /* bitsize */
28+ FALSE, /* pc_relative */
29+ 0, /* bitpos */
30+ complain_overflow_bitfield, /* complain_on_overflow */
31+ bfd_elf_avr_diff_reloc, /* special_function */
32+ "R_AVR_DIFF8", /* name */
33+ FALSE, /* partial_inplace */
34+ 0, /* src_mask */
35+ 0xff, /* dst_mask */
36+ FALSE), /* pcrel_offset */
37+ HOWTO (R_AVR_DIFF16, /* type */
38+ 0, /* rightshift */
39+ 1, /* size (0 = byte, 1 = short, 2 = long) */
40+ 16, /* bitsize */
41+ FALSE, /* pc_relative */
42+ 0, /* bitpos */
43+ complain_overflow_bitfield, /* complain_on_overflow */
44+ bfd_elf_avr_diff_reloc, /* special_function */
45+ "R_AVR_DIFF16", /* name */
46+ FALSE, /* partial_inplace */
47+ 0, /* src_mask */
48+ 0xffff, /* dst_mask */
49+ FALSE), /* pcrel_offset */
50+ HOWTO (R_AVR_DIFF32, /* type */
51+ 0, /* rightshift */
52+ 2, /* size (0 = byte, 1 = short, 2 = long) */
53+ 32, /* bitsize */
54+ FALSE, /* pc_relative */
55+ 0, /* bitpos */
56+ complain_overflow_bitfield, /* complain_on_overflow */
57+ bfd_elf_avr_diff_reloc, /* special_function */
58+ "R_AVR_DIFF32", /* name */
59+ FALSE, /* partial_inplace */
60+ 0, /* src_mask */
61+ 0xffffffff, /* dst_mask */
62+ FALSE) /* pcrel_offset */
63 };
64
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 }
75 };
76
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,
79 return 0x020000;
80 }
81
82+/* Perform a diff relocation. Nothing to do, as the difference value is already
83+ written into the section's contents. */
84+
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)
93+{
94+ return bfd_reloc_ok;
95+}
96+
97+
98 /* Perform a single relocation. By default we use the standard BFD
99 routines, but a few relocs, we have to do them ourselves. */
100
101@@ -1186,6 +1253,13 @@ avr_final_link_relocate (reloc_howto_typ
102 bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents);
103 break;
104
105+ case R_AVR_DIFF8:
106+ case R_AVR_DIFF16:
107+ case R_AVR_DIFF32:
108+ /* Nothing to do here, as contents already contains the diff value. */
109+ r = bfd_reloc_ok;
110+ break;
111+
112 default:
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)
116 e_set);
117 }
118
119+/* Returns whether the relocation type passed is a diff reloc. */
120+
121+static bfd_boolean
122+elf32_avr_is_diff_reloc (Elf_Internal_Rela *irel)
123+{
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);
127+}
128+
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
131+ emitted. */
132+
133+static void
134+elf32_avr_adjust_diff_reloc_value (bfd *abfd,
135+ struct bfd_section *isec,
136+ Elf_Internal_Rela *irel,
137+ bfd_vma symval,
138+ bfd_vma shrinked_insn_address,
139+ int count)
140+{
141+ unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
142+ if (isec_contents == NULL)
143+ {
144+ if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
145+ return;
146+ }
147+
148+ isec_contents += irel->r_offset;
149+
150+ /* Read value written in object file. */
151+ bfd_vma x = 0;
152+ switch (ELF32_R_TYPE (irel->r_info))
153+ {
154+ case R_AVR_DIFF8:
155+ {
156+ x = *isec_contents;
157+ break;
158+ }
159+ case R_AVR_DIFF16:
160+ {
161+ x = bfd_get_16 (abfd, isec_contents);
162+ break;
163+ }
164+ case R_AVR_DIFF32:
165+ {
166+ x = bfd_get_32 (abfd, isec_contents);
167+ break;
168+ }
169+ default:
170+ {
171+ BFD_FAIL();
172+ }
173+ }
174+
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
178+ sym1 and sym2. */
179+
180+ bfd_vma end_address = symval + irel->r_addend;
181+ bfd_vma start_address = end_address - x;
182+
183+ if (shrinked_insn_address >= start_address &&
184+ shrinked_insn_address <= end_address)
185+ {
186+ switch (ELF32_R_TYPE (irel->r_info))
187+ {
188+ case R_AVR_DIFF8:
189+ {
190+ *isec_contents = (x - count);
191+ break;
192+ }
193+ case R_AVR_DIFF16:
194+ {
195+ bfd_put_16 (abfd, (x - count) & 0xFFFF, isec_contents);
196+ break;
197+ }
198+ case R_AVR_DIFF32:
199+ {
200+ bfd_put_32 (abfd, (x - count) & 0xFFFFFFFF, isec_contents);
201+ break;
202+ }
203+ default:
204+ {
205+ BFD_FAIL();
206+ }
207+ }
208+
209+ elf_section_data (isec)->this_hdr.contents = isec_contents - irel->r_offset;
210+ }
211+}
212
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)
218 {
219+ if (elf32_avr_is_diff_reloc (irel))
220+ {
221+ elf32_avr_adjust_diff_reloc_value (abfd, isec, irel,
222+ symval,
223+ shrinked_insn_address,
224+ count);
225+ }
226+
227 irel->r_addend -= count;
228
229 if (debug_relax)
230diff -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
234 ENUMDOC
235 This is a 7 bit reloc for the AVR that stores offset for 16bit sts/lds
236 instructions supported only by Tiny core
237+ENUM
238+ BFD_RELOC_AVR_DIFF8
239+ENUMX
240+ BFD_RELOC_AVR_DIFF16
241+ENUMX
242+ BFD_RELOC_AVR_DIFF32
243+ENUMDOC
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
249+ value.
250
251 ENUM
252 BFD_RELOC_RL78_NEG8
253diff -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
261+ relaxation. */
262 };
263
264-static struct avr_opt_s avr_opt = { 0, 0, 0 };
265+static struct avr_opt_s avr_opt = { 0, 0, 0, 0 };
266
267 const char EXP_CHARS[] = "eE";
268 const char FLT_CHARS[] = "dD";
269@@ -404,7 +406,8 @@ enum options
270 {
271 OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
272 OPTION_NO_SKIP_BUG,
273- OPTION_NO_WRAP
274+ OPTION_NO_WRAP,
275+ OPTION_LINK_RELAX
276 };
277
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 }
285 };
286
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"
294+ ));
295 show_mcu_list (stream);
296 }
297
298@@ -580,6 +586,9 @@ md_parse_option (int c, char *arg)
299 case OPTION_NO_WRAP:
300 avr_opt.no_wrap = 1;
301 return 1;
302+ case OPTION_LINK_RELAX:
303+ avr_opt.link_relax = 1;
304+ return 1;
305 }
306
307 return 0;
308@@ -630,6 +639,7 @@ md_begin (void)
309 }
310
311 bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
312+ linkrelax = avr_opt.link_relax;
313 }
314
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;
318 }
319
320+static bfd_boolean
321+relaxable_section (asection *sec)
322+{
323+ return (sec->flags & SEC_DEBUGGING) == 0;
324+}
325+
326+/* Does whatever the xtensa port does. */
327+int
328+avr_validate_fix_sub (fixS *fix)
329+{
330+ segT add_symbol_segment, sub_symbol_segment;
331+
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)
337+ return 0;
338+
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))
346+ return 0;
347+
348+ sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
349+ return (sub_symbol_segment == add_symbol_segment);
350+}
351+
352+/* TC_FORCE_RELOCATION hook */
353+
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. */
357+int
358+avr_force_relocation (fixS *fix)
359+{
360+ if (linkrelax && fix->fx_addsy
361+ && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
362+ return 1;
363+
364+ return generic_force_reloc (fix);
365+}
366+
367 /* GAS will call this for each fixup. It should store the correct
368 value in the object file. */
369
370@@ -1228,11 +1285,46 @@ md_apply_fix (fixS *fixP, valueT * valP,
371 fixP->fx_done = 1;
372 }
373 }
374+ else if (linkrelax && fixP->fx_subsy)
375+ {
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 */
384+
385+ switch (fixP->fx_r_type)
386+ {
387+ case BFD_RELOC_8:
388+ fixP->fx_r_type = BFD_RELOC_AVR_DIFF8;
389+ break;
390+ case BFD_RELOC_16:
391+ fixP->fx_r_type = BFD_RELOC_AVR_DIFF16;
392+ break;
393+ case BFD_RELOC_32:
394+ fixP->fx_r_type = BFD_RELOC_AVR_DIFF32;
395+ break;
396+ default:
397+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
398+ break;
399+ }
400+
401+ value = S_GET_VALUE (fixP->fx_addsy) +
402+ fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy);
403
404+ fixP->fx_subsy = NULL;
405+ }
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"));
409
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)
415 {
416 default:
417@@ -1242,6 +1334,19 @@ md_apply_fix (fixS *fixP, valueT * valP,
418 case BFD_RELOC_AVR_13_PCREL:
419 case BFD_RELOC_32:
420 case BFD_RELOC_16:
421+ break;
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);
426+ *where = value;
427+ break;
428+ case BFD_RELOC_AVR_DIFF16:
429+ bfd_putl16 ((bfd_vma) value, where);
430+ break;
431+ case BFD_RELOC_AVR_DIFF32:
432+ bfd_putl16 ((bfd_vma) value, where);
433+ break;
434 case BFD_RELOC_AVR_CALL:
435 break;
436 }
437diff -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
443
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
448+
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 *);
455+
456 /* Values passed to md_apply_fix don't include the symbol value. */
457 #define MD_APPLY_SYM_VALUE(FIX) 0
458
459@@ -144,6 +156,12 @@ extern long md_pcrel_from_section (struc
460 { \
461 goto SKIP; \
462 }
463+
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 *);
469
470 /* This target is buggy, and sets fix size too large. */
471 #define TC_FX_SIZE_SLACK(FIX) 2
472diff -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)
483
484 #endif /* _ELF_AVR_H */
This page took 0.150881 seconds and 4 git commands to generate.