void
ldctor_build_sets (void)
{
  static bfd_boolean called;
  bfd_boolean header_printed;
  struct set_info *p;

  /* The emulation code may call us directly, but we only want to do
     this once.  */
  if (called)
    return;
  called = TRUE;

  if (constructors_sorted)
    {
      for (p = sets; p != NULL; p = p->next)
	{
	  int c, i;
	  struct set_element *e;
	  struct set_element **array;

	  if (p->elements == NULL)
	    continue;

	  c = 0;
	  for (e = p->elements; e != NULL; e = e->next)
	    ++c;

	  array = xmalloc (c * sizeof *array);

	  i = 0;
	  for (e = p->elements; e != NULL; e = e->next)
	    {
	      array[i] = e;
	      ++i;
	    }

	  qsort (array, c, sizeof *array, ctor_cmp);

	  e = array[0];
	  p->elements = e;
	  for (i = 0; i < c - 1; i++)
	    array[i]->next = array[i + 1];
	  array[i]->next = NULL;

	  free (array);
	}
    }

  lang_list_init (&constructor_list);
  push_stat_ptr (&constructor_list);

  header_printed = FALSE;
  for (p = sets; p != NULL; p = p->next)
    {
      struct set_element *e;
      reloc_howto_type *howto;
      int reloc_size, size;

      /* If the symbol is defined, we may have been invoked from
	 collect, and the sets may already have been built, so we do
	 not do anything.  */
      if (p->h->type == bfd_link_hash_defined
	  || p->h->type == bfd_link_hash_defweak)
	continue;

      /* For each set we build:
	   set:
	     .long number_of_elements
	     .long element0
	     ...
	     .long elementN
	     .long 0
	 except that we use the right size instead of .long.  When
	 generating relocatable output, we generate relocs instead of
	 addresses.  */
      howto = bfd_reloc_type_lookup (link_info.output_bfd, p->reloc);
      if (howto == NULL)
	{
	  if (link_info.relocatable)
	    {
	      einfo (_("%P%X: %s does not support reloc %s for set %s\n"),
		     bfd_get_target (link_info.output_bfd),
		     bfd_get_reloc_code_name (p->reloc),
		     p->h->root.string);
	      continue;
	    }

	  /* If this is not a relocatable link, all we need is the
	     size, which we can get from the input BFD.  */
	  if (p->elements->section->owner != NULL)
	    howto = bfd_reloc_type_lookup (p->elements->section->owner,
					   p->reloc);
	  if (howto == NULL)
	    {
	      einfo (_("%P%X: %s does not support reloc %s for set %s\n"),
		     bfd_get_target (p->elements->section->owner),
		     bfd_get_reloc_code_name (p->reloc),
		     p->h->root.string);
	      continue;
	    }
	}

      reloc_size = bfd_get_reloc_size (howto);
      switch (reloc_size)
	{
	case 1: size = BYTE; break;
	case 2: size = SHORT; break;
	case 4: size = LONG; break;
	case 8:
	  if (howto->complain_on_overflow == complain_overflow_signed)
	    size = SQUAD;
	  else
	    size = QUAD;
	  break;
	default:
	  einfo (_("%P%X: Unsupported size %d for set %s\n"),
		 bfd_get_reloc_size (howto), p->h->root.string);
	  size = LONG;
	  break;
	}

      lang_add_assignment (exp_assop ('=', ".",
				      exp_unop (ALIGN_K,
						exp_intop (reloc_size))));
      lang_add_assignment (exp_assop ('=', p->h->root.string,
				      exp_nameop (NAME, ".")));
      lang_add_data (size, exp_intop (p->count));

      for (e = p->elements; e != NULL; e = e->next)
	{
	  if (config.map_file != NULL)
	    {
	      int len;

	      if (! header_printed)
		{
		  minfo (_("\nSet                 Symbol\n\n"));
		  header_printed = TRUE;
		}

	      minfo ("%s", p->h->root.string);
	      len = strlen (p->h->root.string);

	      if (len >= 19)
		{
		  print_nl ();
		  len = 0;
		}
	      while (len < 20)
		{
		  print_space ();
		  ++len;
		}

	      if (e->name != NULL)
		minfo ("%T\n", e->name);
	      else
		minfo ("%G\n", e->section->owner, e->section, e->value);
	    }

	  /* Need SEC_KEEP for --gc-sections.  */
	  if (! bfd_is_abs_section (e->section))
	    e->section->flags |= SEC_KEEP;

	  if (link_info.relocatable)
	    lang_add_reloc (p->reloc, howto, e->section, e->name,
			    exp_intop (e->value));
	  else
	    lang_add_data (size, exp_relop (e->section, e->value));
	}

      lang_add_data (size, exp_intop (0));
    }

  pop_stat_ptr ();
}
/* just reloc parts - data comes later */
static void copy_section_relocs_edit (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
    bfd *obfd = obfdarg;
    arelent **relpp;
    long relcount;
    sec_ptr osection;
    bfd_size_type size;
    long relsize;
    flagword flags;


    flags = bfd_get_section_flags (ibfd, isection);
    if ((flags & SEC_GROUP) != 0)
	return;

    osection = isection->output_section;
    size = bfd_get_section_size (isection);

    if (size == 0 || osection == 0)
	return;

    relsize = bfd_get_reloc_upper_bound (ibfd, isection);

    if (relsize <= 0)
    {
	/* not good */
	bfd_perror("attempting to do relocs");
	return;
    }

    relpp = malloc (relsize);

    relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);

    /* copy each reloc, possibly removing or changing it on the fly */
    arelent **temp_relpp;
    long temp_relcount = 0;
    long i;
    int msg_cnt = 0;
    struct change_reloc_struct *change_ptr;
    struct add_reloc_struct *new_reloc;
    asymbol **osympp;

    /* count new relocs to allocate space in reloc list */
    int reloc_add_cnt;
    reloc_add_cnt = 0;
    for (new_reloc = additional_relocs; new_reloc != NULL; new_reloc = new_reloc->next) {
	reloc_add_cnt++;
    }

    osympp = bfd_get_outsymbols(obfd);

    /* note: cannot run mprobe on osympp b/c the copy contents will sometimes realloc it from internal BFD storage */

    temp_relpp = malloc (relsize + reloc_add_cnt * sizeof(arelent *));
    for (i = 0; i < relcount; i++) {

	if (is_delete_reloc(bfd_asymbol_name(*relpp[i]->sym_ptr_ptr), delete_relocs)) {
	    continue;
	}
	else if ((change_ptr = find_change_reloc(bfd_asymbol_name(*relpp[i]->sym_ptr_ptr), change_relocs)) != NULL) {
	    int sym_idx;
	    sym_idx = find_symbol(osympp, change_ptr->new_symbol_name);
	    if (sym_idx < 0) {
		fprintf(stderr, "internal error: could not find new symbol %s in output symbol table\n", change_ptr->new_symbol_name);
		exit(1);
	    }
	    relpp[i]->sym_ptr_ptr = &(osympp[sym_idx]);
	}
	temp_relpp [temp_relcount++] = relpp [i];
    }

    /* now the additional relocs from the command line */
    if (strcmp(bfd_get_section_name(ibfd, isection), ".text") == 0) {
	add_reloc_struct *add_reloc;
	for (add_reloc = additional_relocs; add_reloc != NULL; add_reloc = add_reloc->next) {
	    arelent *new_reloc;
	    int symbol_idx;

	    new_reloc = malloc(sizeof(*new_reloc));
	    if ((symbol_idx = find_symbol(osympp, add_reloc->symbol_name)) < 0) {
		fprintf(stderr, "could not find symbol %s to perform a relocation! possible internal error\n", add_reloc->symbol_name);
		continue;
	    }
	    new_reloc->sym_ptr_ptr = &osympp[symbol_idx];
	    new_reloc->address = add_reloc->loc;
	    new_reloc->addend = 0;   /* never seemed to be used in my cursory investigation */
	    new_reloc->howto = bfd_reloc_type_lookup(ibfd, BFD_RELOC_32_PCREL);
	    if (new_reloc->howto == NULL) {
		fprintf(stderr, "could not get howto back from bfd subsystem\n");
		exit(1);
	    }

	    temp_relpp[temp_relcount++] = new_reloc;
	}
    }
    temp_relpp[temp_relcount] = NULL;

    relcount = temp_relcount;
    free (relpp);
    relpp = temp_relpp;

    bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
    if (relcount == 0)
	free (relpp);

    mcheck_check_all();

}