+/* Do generic partial_inplace relocation.
+ This is a local replacement for bfd_elf_generic_reloc. */
+
+bfd_reloc_status_type
+m32r_elf_generic_reloc (input_bfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *input_bfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ bfd_reloc_status_type ret;
+ bfd_vma relocation;
+ bfd_byte *inplace_address;
+
+ /* This part is from bfd_elf_generic_reloc.
+ If we're relocating, and this an external symbol, we don't want
+ to change anything. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* Now do the reloc in the usual way.
+ ??? It would be nice to call bfd_elf_generic_reloc here,
+ but we have partial_inplace set. bfd_elf_generic_reloc will
+ pass the handling back to bfd_install_relocation which will install
+ a section relative addend which is wrong. */
+
+ /* Sanity check the address (offset in section). */
+ if (reloc_entry->address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ ret = bfd_reloc_ok;
+ if (bfd_is_und_section (symbol->section)
+ && output_bfd == (bfd *) NULL)
+ ret = bfd_reloc_undefined;
+
+ if (bfd_is_com_section (symbol->section)
+ || output_bfd != (bfd *) NULL)
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ /* Only do this for a final link. */
+ if (output_bfd == (bfd *) NULL)
+ {
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+ }
+
+ relocation += reloc_entry->addend;
+ inplace_address = (bfd_byte *) data + reloc_entry->address;
+
+#define DOIT(x) \
+ x = ( (x & ~reloc_entry->howto->dst_mask) | \
+ (((x & reloc_entry->howto->src_mask) + relocation) & \
+ reloc_entry->howto->dst_mask))
+
+ switch (reloc_entry->howto->size)
+ {
+ case 1:
+ {
+ short x = bfd_get_16 (input_bfd, inplace_address);
+ DOIT (x);
+ bfd_put_16 (input_bfd, (bfd_vma) x, inplace_address);
+ }
+ break;
+ case 2:
+ {
+ unsigned long x = bfd_get_32 (input_bfd, inplace_address);
+ DOIT (x);
+ bfd_put_32 (input_bfd, (bfd_vma)x , inplace_address);
+ }
+ break;
+ default:
+ BFD_ASSERT (0);
+ }
+
+ if (output_bfd != (bfd *) NULL)
+ reloc_entry->address += input_section->output_offset;
+
+ return ret;
+}
+