diff options
-rw-r--r-- | gas/ChangeLog | 5 | ||||
-rw-r--r-- | gas/write.c | 21 |
2 files changed, 22 insertions, 4 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index fa0cec6..475929e 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2011-11-15 Maciej W. Rozycki <macro@codesourcery.com> + + * write.c (dump_section_relocs): Don't convert PC-relative relocs + that have an in-place addend narrower than the addresses used. + 2011-11-14 Maciej W. Rozycki <macro@codesourcery.com> * config/tc-mips.c (can_swap_branch_p): Exclude microMIPS diff --git a/gas/write.c b/gas/write.c index cf59d7d..a1e0205 100644 --- a/gas/write.c +++ b/gas/write.c @@ -654,15 +654,21 @@ dump_section_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, FILE *stream) static void resolve_reloc_expr_symbols (void) { + bfd_vma addr_mask = 1; struct reloc_list *r; + /* Avoid a shift by the width of type. */ + addr_mask <<= bfd_arch_bits_per_address (stdoutput) - 1; + addr_mask <<= 1; + addr_mask -= 1; + for (r = reloc_list; r; r = r->next) { + reloc_howto_type *howto = r->u.a.howto; expressionS *symval; symbolS *sym; bfd_vma offset, addend; asection *sec; - reloc_howto_type *howto; resolve_symbol_value (r->u.a.offset_sym); symval = symbol_get_value_expression (r->u.a.offset_sym); @@ -709,7 +715,16 @@ resolve_reloc_expr_symbols (void) } else if (sym != NULL) { - if (S_IS_LOCAL (sym) && !symbol_section_p (sym)) + /* Convert relocs against local symbols to refer to the + corresponding section symbol plus offset instead. Keep + PC-relative relocs of the REL variety intact though to + prevent the offset from overflowing the relocated field, + unless it has enough bits to cover the whole address + space. */ + if (S_IS_LOCAL (sym) && !symbol_section_p (sym) + && !(howto->partial_inplace + && howto->pc_relative + && howto->src_mask != addr_mask)) { asection *symsec = S_GET_SEGMENT (sym); if (!(((symsec->flags & SEC_MERGE) != 0 @@ -730,8 +745,6 @@ resolve_reloc_expr_symbols (void) sym = abs_section_sym; } - howto = r->u.a.howto; - r->u.b.sec = sec; r->u.b.s = symbol_get_bfdsym (sym); r->u.b.r.sym_ptr_ptr = &r->u.b.s; |