]> git.pld-linux.org Git - packages/crossavr-binutils.git/blob - 009-dwarf-relax-fix.patch
- release 2 (x32 rebuild)
[packages/crossavr-binutils.git] / 009-dwarf-relax-fix.patch
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;
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)
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
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
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 
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      }
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
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
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)
483  
484  #endif /* _ELF_AVR_H */
This page took 0.09519 seconds and 3 git commands to generate.