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(); }