diff options
Diffstat (limited to 'ld/ldctor.c')
-rw-r--r-- | ld/ldctor.c | 383 |
1 files changed, 0 insertions, 383 deletions
diff --git a/ld/ldctor.c b/ld/ldctor.c deleted file mode 100644 index 0a434b812e1..00000000000 --- a/ld/ldctor.c +++ /dev/null @@ -1,383 +0,0 @@ -/* ldctor.c -- constructor support routines - Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998 - Free Software Foundation, Inc. - By Steve Chamberlain <sac@cygnus.com> - -This file is part of GLD, the Gnu Linker. - -GLD is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GLD is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GLD; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -#include "bfd.h" -#include "sysdep.h" -#include "bfdlink.h" - -#include <ctype.h> - -#include "ld.h" -#include "ldexp.h" -#include "ldlang.h" -#include "ldmisc.h" -#include "ldgram.h" -#include "ldmain.h" -#include "ldctor.h" - -static int ctor_prio PARAMS ((const char *)); -static int ctor_cmp PARAMS ((const PTR, const PTR)); - -/* The list of statements needed to handle constructors. These are - invoked by the command CONSTRUCTORS in the linker script. */ -lang_statement_list_type constructor_list; - -/* Whether the constructors should be sorted. Note that this is - global for the entire link; we assume that there is only a single - CONSTRUCTORS command in the linker script. */ -boolean constructors_sorted; - -/* The sets we have seen. */ -struct set_info *sets; - -/* Add an entry to a set. H is the entry in the linker hash table. - RELOC is the relocation to use for an entry in the set. SECTION - and VALUE are the value to add. This is called during the first - phase of the link, when we are still gathering symbols together. - We just record the information now. The ldctor_find_constructors - function will construct the sets. */ - -void -ldctor_add_set_entry (h, reloc, name, section, value) - struct bfd_link_hash_entry *h; - bfd_reloc_code_real_type reloc; - const char *name; - asection *section; - bfd_vma value; -{ - struct set_info *p; - struct set_element *e; - struct set_element **epp; - - for (p = sets; p != (struct set_info *) NULL; p = p->next) - if (p->h == h) - break; - - if (p == (struct set_info *) NULL) - { - p = (struct set_info *) xmalloc (sizeof (struct set_info)); - p->next = sets; - sets = p; - p->h = h; - p->reloc = reloc; - p->count = 0; - p->elements = NULL; - } - else - { - if (p->reloc != reloc) - { - einfo (_("%P%X: Different relocs used in set %s\n"), h->root.string); - return; - } - - /* Don't permit a set to be constructed from different object - file formats. The same reloc may have different results. We - actually could sometimes handle this, but the case is - unlikely to ever arise. Sometimes constructor symbols are in - unusual sections, such as the absolute section--this appears - to be the case in Linux a.out--and in such cases we just - assume everything is OK. */ - if (p->elements != NULL - && section->owner != NULL - && p->elements->section->owner != NULL - && strcmp (bfd_get_target (section->owner), - bfd_get_target (p->elements->section->owner)) != 0) - { - einfo (_("%P%X: Different object file formats composing set %s\n"), - h->root.string); - return; - } - } - - e = (struct set_element *) xmalloc (sizeof (struct set_element)); - e->next = NULL; - e->name = name; - e->section = section; - e->value = value; - - for (epp = &p->elements; *epp != NULL; epp = &(*epp)->next) - ; - *epp = e; - - ++p->count; -} - -/* Get the priority of a g++ global constructor or destructor from the - symbol name. */ - -static int -ctor_prio (name) - const char *name; -{ - /* The name will look something like _GLOBAL_$I$65535$test02__Fv. - There might be extra leading underscores, and the $ characters - might be something else. The I might be a D. */ - - while (*name == '_') - ++name; - - if (strncmp (name, "GLOBAL_", sizeof "GLOBAL_" - 1) != 0) - return -1; - - name += sizeof "GLOBAL_" - 1; - - if (name[0] != name[2]) - return -1; - if (name[1] != 'I' && name[1] != 'D') - return -1; - if (! isdigit ((unsigned char) name[3])) - return -1; - - return atoi (name + 3); -} - -/* This function is used to sort constructor elements by priority. It - is called via qsort. */ - -static int -ctor_cmp (p1, p2) - const PTR p1; - const PTR p2; -{ - const struct set_element **pe1 = (const struct set_element **) p1; - const struct set_element **pe2 = (const struct set_element **) p2; - const char *n1; - const char *n2; - int prio1; - int prio2; - - n1 = (*pe1)->name; - if (n1 == NULL) - n1 = ""; - n2 = (*pe2)->name; - if (n2 == NULL) - n2 = ""; - - /* We need to sort in reverse order by priority. When two - constructors have the same priority, we should maintain their - current relative position. */ - - prio1 = ctor_prio (n1); - prio2 = ctor_prio (n2); - - /* We sort in reverse order because that is what g++ expects. */ - if (prio1 < prio2) - return 1; - else if (prio1 > prio2) - return -1; - - /* Force a stable sort. */ - - if (pe1 < pe2) - return -1; - else if (pe1 > pe2) - return 1; - else - return 0; -} - -/* This function is called after the first phase of the link and - before the second phase. At this point all set information has - been gathered. We now put the statements to build the sets - themselves into constructor_list. */ - -void -ldctor_build_sets () -{ - static boolean called; - lang_statement_list_type *old; - 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 = (struct set_element **) 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); - } - } - - old = stat_ptr; - stat_ptr = &constructor_list; - - lang_list_init (stat_ptr); - - header_printed = false; - for (p = sets; p != (struct set_info *) 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 relocateable output, we generate relocs instead of - addresses. */ - howto = bfd_reloc_type_lookup (output_bfd, p->reloc); - if (howto == (reloc_howto_type *) NULL) - { - if (link_info.relocateable) - { - einfo (_("%P%X: %s does not support reloc %s for set %s\n"), - bfd_get_target (output_bfd), - bfd_get_reloc_code_name (p->reloc), - p->h->root.string); - continue; - } - - /* If this is not a relocateable 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 ((bfd_vma) p->count)); - - for (e = p->elements; e != (struct set_element *) 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.relocateable) - 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)); - } - - stat_ptr = old; -} |