+2012-06-28  Nick Clifton  <nickc@redhat.com>
+
+       * dwarf2dbg.c (DWARF2_USE_FIXED_ADVANCE_PC): Enable when using
+       linker relaxation.
+       (dwarf2_gen_line_info): Generate real, local, labels for line
+       numbers.
+       (dwarf2dbg_convert_frag): Do not finalize the computation of the
+       frag's symbol value when linker relaxation is enabled.
+       (ADDR_DELTA_LIMIT): Define.
+       (size_fixed_inc_line_addr): Use ADDR_DELTA_LIMIT.
+       (emit_fixed_inc_line_addr): Likewise.
+       * write.c (fixup_segment): If the subtraction of two symbols
+       cannot be resolved but is valid, then prevent bogus range warnings
+       by pre-biasing add_number.
+       * config/tc-h8300.h (DWARF2_USE_FIXED_ADVANCE_PC): Define to 0.
+
 2012-06-22  Roland McGrath  <mcgrathr@google.com>
 
        * NEWS: Mention 'rep ret' too.
 
    opcodes and variable-length operands cannot be used.  If this macro is
    nonzero, use the DW_LNS_fixed_advance_pc opcode instead.  */
 #ifndef DWARF2_USE_FIXED_ADVANCE_PC
-# define DWARF2_USE_FIXED_ADVANCE_PC   0
+# define DWARF2_USE_FIXED_ADVANCE_PC   linkrelax
 #endif
 
 /* First special line opcde - leave room for the standard opcodes.
   filenum = loc->filenum;
 
   dwarf2_push_line (loc);
-  dwarf2_flush_pending_lines (symbol_temp_new (now_seg, ofs, frag_now));
+  if (linkrelax)
+    {
+      char name[120];
+
+      /* Use a non-fake name for the line number location,
+        so that it can be referred to by relocations.  */
+      sprintf (name, ".Loc.%u.%u", line, filenum);
+      dwarf2_flush_pending_lines (symbol_new (name, now_seg, ofs, frag_now));
+    }
+  else
+    dwarf2_flush_pending_lines (symbol_temp_new (now_seg, ofs, frag_now));
 }
 
 /* Returns the current source information.  If .file directives have
    line and address information, but it is required if linker relaxation
    could change the code offsets.  The following two routines *must* be
    kept in sync.  */
+#define ADDR_DELTA_LIMIT 50000
 
 static int
 size_fixed_inc_line_addr (int line_delta, addressT addr_delta)
   if (line_delta != INT_MAX)
     len = 1 + sizeof_leb128 (line_delta, 1);
 
-  if (addr_delta > 50000)
+  if (addr_delta > ADDR_DELTA_LIMIT)
     {
       /* DW_LNS_extended_op */
       len += 1 + sizeof_leb128 (sizeof_address + 1, 0);
      which this function would not be used) could change the operand by
      an unknown amount.  If the address increment is getting close to
      the limit, just reset the address.  */
-  if (addr_delta > 50000)
+  if (addr_delta > ADDR_DELTA_LIMIT)
     {
       symbolS *to_sym;
       expressionS exp;
 {
   offsetT addr_diff;
 
-  addr_diff = resolve_symbol_value (frag->fr_symbol);
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    {
+      /* If linker relaxation is enabled then the distance bewteen the two
+        symbols in the frag->fr_symbol expression might change.  Hence we
+        cannot rely upon the value computed by resolve_symbol_value.
+        Instead we leave the expression unfinalized and allow
+        emit_fixed_inc_line_addr to create a fixup (which later becomes a
+        relocation) that will allow the linker to correctly compute the
+        actual address difference.  We have to use a fixed line advance for
+        this as we cannot (easily) relocate leb128 encoded values.  */
+      int saved_finalize_syms = finalize_syms;
+
+      finalize_syms = 0;
+      addr_diff = resolve_symbol_value (frag->fr_symbol);
+      finalize_syms = saved_finalize_syms;
+    }
+  else
+    addr_diff = resolve_symbol_value (frag->fr_symbol);
 
   /* fr_var carries the max_chars that we created the fragment with.
      fr_subtype carries the current expected length.  We must, of
 
              fixP->fx_subsy = NULL;
              fixP->fx_pcrel = 1;
            }
-         else if (!TC_VALIDATE_FIX_SUB (fixP, add_symbol_segment))
+         else if (TC_VALIDATE_FIX_SUB (fixP, add_symbol_segment))
+           /* If the fix is valid, subtract fx_subsy here.  The addition of
+              fx_addsy will be performed below.  Doing this prevents bogus
+              warnings from the range check below.  */
+             add_number -= S_GET_VALUE (fixP->fx_subsy);
+         else
            {
              if (!md_register_arithmetic
                  && (add_symbol_segment == reg_section