+
+ error_return:
+ if (contents != NULL)
+ free (contents);
+ if (external_relocs != NULL && section_tdata == NULL)
+ free (external_relocs);
+ return false;
+}
+
+/* Generate a reloc when linking an ECOFF file. This is a reloc
+ requested by the linker, and does come from any input file. This
+ is used to build constructor and destructor tables when linking
+ with -Ur. */
+
+static boolean
+ecoff_reloc_link_order (output_bfd, info, output_section, link_order)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ asection *output_section;
+ struct bfd_link_order *link_order;
+{
+ enum bfd_link_order_type type;
+ asection *section;
+ bfd_vma addend;
+ arelent rel;
+ struct internal_reloc in;
+ bfd_size_type external_reloc_size;
+ bfd_byte *rbuf;
+ boolean ok;
+
+ type = link_order->type;
+ section = NULL;
+ addend = link_order->u.reloc.p->addend;
+
+ /* We set up an arelent to pass to the backend adjust_reloc_out
+ routine. */
+ rel.address = link_order->offset;
+
+ rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
+ if (rel.howto == 0)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ if (type == bfd_section_reloc_link_order)
+ {
+ section = link_order->u.reloc.p->u.section;
+ rel.sym_ptr_ptr = section->symbol_ptr_ptr;
+ }
+ else
+ {
+ struct bfd_link_hash_entry *h;
+
+ /* Treat a reloc against a defined symbol as though it were
+ actually against the section. */
+ h = bfd_wrapped_link_hash_lookup (output_bfd, info,
+ link_order->u.reloc.p->u.name,
+ false, false, false);
+ if (h != NULL
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
+ {
+ type = bfd_section_reloc_link_order;
+ section = h->u.def.section->output_section;
+ /* It seems that we ought to add the symbol value to the
+ addend here, but in practice it has already been added
+ because it was passed to constructor_callback. */
+ addend += section->vma + h->u.def.section->output_offset;
+ }
+ else
+ {
+ /* We can't set up a reloc against a symbol correctly,
+ because we have no asymbol structure. Currently no
+ adjust_reloc_out routine cares. */
+ rel.sym_ptr_ptr = (asymbol **) NULL;
+ }
+ }
+
+ /* All ECOFF relocs are in-place. Put the addend into the object
+ file. */
+
+ BFD_ASSERT (rel.howto->partial_inplace);
+ if (addend != 0)
+ {
+ bfd_size_type size;
+ bfd_reloc_status_type rstat;
+ bfd_byte *buf;
+ boolean ok;
+
+ size = bfd_get_reloc_size (rel.howto);
+ buf = (bfd_byte *) bfd_zmalloc (size);
+ if (buf == (bfd_byte *) NULL)
+ return false;
+ rstat = _bfd_relocate_contents (rel.howto, output_bfd, addend, buf);
+ switch (rstat)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ if (! ((*info->callbacks->reloc_overflow)
+ (info,
+ (link_order->type == bfd_section_reloc_link_order
+ ? bfd_section_name (output_bfd, section)
+ : link_order->u.reloc.p->u.name),
+ rel.howto->name, addend, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
+ {
+ free (buf);
+ return false;
+ }
+ break;
+ }
+ ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
+ (file_ptr) link_order->offset, size);
+ free (buf);
+ if (! ok)
+ return false;
+ }
+
+ rel.addend = 0;
+
+ /* Move the information into a internal_reloc structure. */
+ in.r_vaddr = (rel.address
+ + bfd_get_section_vma (output_bfd, output_section));
+ in.r_type = rel.howto->type;
+
+ if (type == bfd_symbol_reloc_link_order)
+ {
+ struct ecoff_link_hash_entry *h;
+
+ h = ((struct ecoff_link_hash_entry *)
+ bfd_wrapped_link_hash_lookup (output_bfd, info,
+ link_order->u.reloc.p->u.name,
+ false, false, true));
+ if (h != (struct ecoff_link_hash_entry *) NULL
+ && h->indx != -1)
+ in.r_symndx = h->indx;
+ else
+ {
+ if (! ((*info->callbacks->unattached_reloc)
+ (info, link_order->u.reloc.p->u.name, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
+ return false;
+ in.r_symndx = 0;
+ }
+ in.r_extern = 1;
+ }
+ else
+ {
+ CONST char *name;
+
+ name = bfd_get_section_name (output_bfd, section);
+ if (strcmp (name, ".text") == 0)
+ in.r_symndx = RELOC_SECTION_TEXT;
+ else if (strcmp (name, ".rdata") == 0)
+ in.r_symndx = RELOC_SECTION_RDATA;
+ else if (strcmp (name, ".data") == 0)
+ in.r_symndx = RELOC_SECTION_DATA;
+ else if (strcmp (name, ".sdata") == 0)
+ in.r_symndx = RELOC_SECTION_SDATA;
+ else if (strcmp (name, ".sbss") == 0)
+ in.r_symndx = RELOC_SECTION_SBSS;
+ else if (strcmp (name, ".bss") == 0)
+ in.r_symndx = RELOC_SECTION_BSS;
+ else if (strcmp (name, ".init") == 0)
+ in.r_symndx = RELOC_SECTION_INIT;
+ else if (strcmp (name, ".lit8") == 0)
+ in.r_symndx = RELOC_SECTION_LIT8;
+ else if (strcmp (name, ".lit4") == 0)
+ in.r_symndx = RELOC_SECTION_LIT4;
+ else if (strcmp (name, ".xdata") == 0)
+ in.r_symndx = RELOC_SECTION_XDATA;
+ else if (strcmp (name, ".pdata") == 0)
+ in.r_symndx = RELOC_SECTION_PDATA;
+ else if (strcmp (name, ".fini") == 0)
+ in.r_symndx = RELOC_SECTION_FINI;
+ else if (strcmp (name, ".lita") == 0)
+ in.r_symndx = RELOC_SECTION_LITA;
+ else if (strcmp (name, "*ABS*") == 0)
+ in.r_symndx = RELOC_SECTION_ABS;
+ else if (strcmp (name, ".rconst") == 0)
+ in.r_symndx = RELOC_SECTION_RCONST;
+ else
+ abort ();
+ in.r_extern = 0;
+ }
+
+ /* Let the BFD backend adjust the reloc. */
+ (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in);
+
+ /* Get some memory and swap out the reloc. */
+ external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size;
+ rbuf = (bfd_byte *) bfd_malloc ((size_t) external_reloc_size);
+ if (rbuf == (bfd_byte *) NULL)
+ return false;
+
+ (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf);
+
+ ok = (bfd_seek (output_bfd,
+ (output_section->rel_filepos +
+ output_section->reloc_count * external_reloc_size),
+ SEEK_SET) == 0
+ && (bfd_write ((PTR) rbuf, 1, external_reloc_size, output_bfd)
+ == external_reloc_size));
+
+ if (ok)
+ ++output_section->reloc_count;
+
+ free (rbuf);
+
+ return ok;