+ h = NULL;
+ }
+ else
+ {
+ /* Change the symndx value to the right one for the
+ output BFD. */
+ int_rel.r_symndx = h->indx;
+ if (int_rel.r_symndx == -1)
+ {
+ /* This symbol is not being written out. */
+ (*info->callbacks->unattached_reloc)
+ (info, h->root.root.string, input_bfd, input_section,
+ int_rel.r_vaddr - input_section->vma);
+ int_rel.r_symndx = 0;
+ }
+ relocation = 0;
+ }
+ }
+ else
+ {
+ /* This is a relocation against a section. Adjust the
+ value by the amount the section moved. */
+ relocation = (s->output_section->vma
+ + s->output_offset
+ - s->vma);
+ }
+
+ relocation += addend;
+ addend = 0;
+
+ /* Adjust a PC relative relocation by removing the reference
+ to the original address in the section and including the
+ reference to the new address. */
+ if (howto->pc_relative)
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ - input_section->vma);
+
+ /* Adjust the contents. */
+ if (relocation == 0)
+ r = bfd_reloc_ok;
+ else
+ {
+ if (int_rel.r_type != MIPS_R_REFHI)
+ r = _bfd_relocate_contents (howto, input_bfd, relocation,
+ (contents
+ + int_rel.r_vaddr
+ - input_section->vma));
+ else
+ {
+ mips_relocate_hi (&int_rel,
+ use_lo ? &lo_int_rel : NULL,
+ input_bfd, input_section, contents,
+ relocation);
+ r = bfd_reloc_ok;
+ }
+ }
+
+ /* Adjust the reloc address. */
+ int_rel.r_vaddr += (input_section->output_section->vma
+ + input_section->output_offset
+ - input_section->vma);
+
+ /* Save the changed reloc information. */
+ mips_ecoff_swap_reloc_out (input_bfd, &int_rel, ext_rel);
+ }
+ else
+ {
+ /* We are producing a final executable. */
+ if (int_rel.r_extern)
+ {
+ /* This is a reloc against a symbol. */
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ asection *hsec;
+
+ hsec = h->root.u.def.section;
+ relocation = (h->root.u.def.value
+ + hsec->output_section->vma
+ + hsec->output_offset);
+ }
+ else
+ {
+ (*info->callbacks->undefined_symbol)
+ (info, h->root.root.string, input_bfd, input_section,
+ int_rel.r_vaddr - input_section->vma, TRUE);
+ relocation = 0;
+ }
+ }
+ else
+ {
+ /* This is a reloc against a section. */
+ relocation = (s->output_section->vma
+ + s->output_offset
+ - s->vma);
+
+ /* A PC relative reloc is already correct in the object
+ file. Make it look like a pcrel_offset relocation by
+ adding in the start address. */
+ if (howto->pc_relative)
+ relocation += int_rel.r_vaddr;
+ }
+
+ if (int_rel.r_type != MIPS_R_REFHI)
+ r = _bfd_final_link_relocate (howto,
+ input_bfd,
+ input_section,
+ contents,
+ (int_rel.r_vaddr
+ - input_section->vma),
+ relocation,
+ addend);
+ else
+ {
+ mips_relocate_hi (&int_rel,
+ use_lo ? &lo_int_rel : NULL,
+ input_bfd, input_section, contents,
+ relocation);
+ r = bfd_reloc_ok;
+ }
+ }
+
+ /* MIPS_R_JMPADDR requires peculiar overflow detection. The
+ instruction provides a 28 bit address (the two lower bits are
+ implicit zeroes) which is combined with the upper four bits
+ of the instruction address. */
+ if (r == bfd_reloc_ok
+ && int_rel.r_type == MIPS_R_JMPADDR
+ && (((relocation
+ + addend
+ + (int_rel.r_extern ? 0 : s->vma))
+ & 0xf0000000)
+ != ((input_section->output_section->vma
+ + input_section->output_offset
+ + (int_rel.r_vaddr - input_section->vma))
+ & 0xf0000000)))
+ r = bfd_reloc_overflow;
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ {
+ const char *name;
+
+ if (int_rel.r_extern)
+ name = NULL;
+ else
+ name = bfd_section_name (input_bfd, s);
+ (*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section,
+ int_rel.r_vaddr - input_section->vma);
+ }
+ break;
+ }
+ }
+ }
+
+ return TRUE;