diff options
author | Alan Modra <amodra@gmail.com> | 2000-07-09 08:45:29 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2000-07-09 08:45:29 +0000 |
commit | 4900fc0695949d2c616c78553893e6cfbcac73aa (patch) | |
tree | 2652d2a9016dea2ab82df6807467c092e52d2b43 /ld/emultempl | |
parent | ad1079af05c5820e0f4e9d1ba24d30c03bff98f6 (diff) | |
download | gdb-4900fc0695949d2c616c78553893e6cfbcac73aa.zip gdb-4900fc0695949d2c616c78553893e6cfbcac73aa.tar.gz gdb-4900fc0695949d2c616c78553893e6cfbcac73aa.tar.bz2 |
hppaelf.em: Merge from elf32.em and implement multiple linker stubs.
Makefile.am: Re-enable ehppaelf.o, add ehppalinux.o
configure.tgt: targ_emul=hppalinux for hppa*linux
Diffstat (limited to 'ld/emultempl')
-rw-r--r-- | ld/emultempl/hppaelf.em | 551 |
1 files changed, 468 insertions, 83 deletions
diff --git a/ld/emultempl/hppaelf.em b/ld/emultempl/hppaelf.em index fde4362..51f3bbd 100644 --- a/ld/emultempl/hppaelf.em +++ b/ld/emultempl/hppaelf.em @@ -1,8 +1,11 @@ # This shell script emits a C file. -*- C -*- # It does some substitutions. cat >e${EMULATION_NAME}.c <<EOF +/* This file is is generated by a shell script. DO NOT EDIT! */ + /* An emulation for HP PA-RISC ELF linkers. - Copyright (C) 1991, 93, 94, 95, 97, 1999 Free Software Foundation, Inc. + Copyright (C) 1991, 93, 94, 95, 97, 99, 2000 + Free Software Foundation, Inc. Written by Steve Chamberlain steve@cygnus.com This file is part of GLD, the Gnu Linker. @@ -23,24 +26,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" +#include <ctype.h> #include "bfdlink.h" #include "ld.h" +#include "ldmain.h" #include "ldemul.h" #include "ldfile.h" +#include "ldmisc.h" #include "ldexp.h" #include "ldlang.h" -#include "ldmisc.h" -#include "ldmain.h" +#include "ldgram.h" #include "ldctor.h" +#include "elf32-hppa.h" -/* Section in which we build stubs. */ -static asection *stub_sec; -static lang_input_statement_type *stub_file; +static void hppaelf_before_parse PARAMS ((void)); +static void hppaelf_set_output_arch PARAMS ((void)); +static void hppaelf_create_output_section_statements PARAMS ((void)); +static void hppaelf_delete_padding_statements + PARAMS ((lang_statement_list_type *list)); +static void hppaelf_finish PARAMS ((void)); +static boolean gld${EMULATION_NAME}_place_orphan + PARAMS ((lang_input_statement_type *, asection *)); +static lang_output_section_statement_type *output_rel_find PARAMS ((void)); +static char *hppaelf_get_script PARAMS ((int *)); -/* FIXME. This doesn't belong here. */ -extern lang_statement_list_type file_chain; +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; /* Perform some emulation specific initialization. For PA ELF we set up the local label prefix and the output architecture. */ @@ -62,7 +75,7 @@ hppaelf_set_output_arch() } /* This is called before the input files are opened. We create a new - fake input file to hold the stub section. */ + fake input file to hold the stub sections. */ static void hppaelf_create_output_section_statements () @@ -80,66 +93,46 @@ hppaelf_create_output_section_statements () return; } - stub_sec = bfd_make_section_old_way (stub_file->the_bfd, ".text"); - /* Don't set SEC_RELOC until we actually have relocations in this - section. */ - if (stub_sec == NULL - || ! bfd_set_section_flags (stub_file->the_bfd, stub_sec, - (SEC_HAS_CONTENTS - | SEC_ALLOC - | SEC_LOAD - | SEC_CODE - | SEC_IN_MEMORY))) - { - einfo ("%X%P: can not create stub section: %E\n"); - return; - } - ldlang_add_file (stub_file); } -/* Walk all the lang statements splicing out any padding statements from +/* Walk all the lang statements splicing out any padding statements from the list. */ static void -hppaelf_delete_padding_statements (s, prev) - lang_statement_union_type *s; - lang_statement_union_type **prev; +hppaelf_delete_padding_statements (list) + lang_statement_list_type *list; { - lang_statement_union_type *sprev = NULL; - for (; s != NULL; s = s->next) + lang_statement_union_type *s; + lang_statement_union_type **ps; + for (ps = &list->head; (s = *ps) != NULL; ps = &s->next) { switch (s->header.type) { - /* We want recursively walk these sections. */ + /* We want to recursively walk these sections. */ case lang_constructors_statement_enum: - hppaelf_delete_padding_statements (constructor_list.head, - &constructor_list.head); + hppaelf_delete_padding_statements (&constructor_list); break; case lang_output_section_statement_enum: - hppaelf_delete_padding_statements (s->output_section_statement. - children.head, - &s->output_section_statement. - children.head); + hppaelf_delete_padding_statements (&s->output_section_statement.children); + break; + + case lang_group_statement_enum: + hppaelf_delete_padding_statements (&s->group_statement.children); break; - /* Huh? What is a lang_wild_statement? */ case lang_wild_statement_enum: - hppaelf_delete_padding_statements (s->wild_statement. - children.head, - &s->wild_statement. - children.head); + hppaelf_delete_padding_statements (&s->wild_statement.children); break; /* Here's what we are really looking for. Splice these out of the list. */ case lang_padding_statement_enum: - if (sprev) - sprev->header.next = s->header.next; - else - **prev = *s; + *ps = s->next; + if (*ps == NULL) + list->tail = ps; break; /* We don't care about these cases. */ @@ -157,51 +150,435 @@ hppaelf_delete_padding_statements (s, prev) abort (); break; } - sprev = s; } } + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static boolean +hook_in_stub (info, lp) + struct hook_stub_info *info; + lang_statement_union_type **lp; +{ + lang_statement_union_type *l; + boolean ret; + + for (; (l = *lp) != NULL; lp = &l->next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (l->input_section.section == info->input_section) + { + /* We've found our section. Insert the stub immediately + before its associated input section. */ + *lp = info->add.head; + *(info->add.tail) = l; + return true; + } + break; + + case lang_data_statement_enum: + case lang_reloc_statement_enum: + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + case lang_input_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return false; +} + +/* Call-back for elf32_hppa_size_stubs. */ + +/* Create a new stub section, and arrange for it to be linked + immediately before INPUT_SECTION. */ + +static asection * +hppaelf_add_stub_section (stub_name, input_section) + const char *stub_name; + asection *input_section; +{ + asection *stub_sec; + flagword flags; + asection *output_section; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + stub_sec = bfd_make_section_anyway (stub_file->the_bfd, stub_name); + if (stub_sec == NULL) + goto err_ret; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP); + if (!bfd_set_section_flags (stub_file->the_bfd, stub_sec, flags)) + goto err_ret; + + output_section = input_section->output_section; + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + info.input_section = input_section; + lang_list_init (&info.add); + wild_doit (&info.add, stub_sec, os, stub_file); + + if (info.add.head == NULL) + goto err_ret; + + if (hook_in_stub (&info, &os->children.head)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + +/* Another call-back for elf32_hppa_size_stubs. */ + +static void +hppaelf_layaout_sections_again () +{ + /* If we have changed sizes of the stub sections, then we need + to recalculate all the section offsets. This may mean we need to + add even more stubs. */ + + /* Delete all the padding statements, they're no longer valid. */ + hppaelf_delete_padding_statements (stat_ptr); + + /* Resize the sections. */ + lang_size_sections (stat_ptr->head, abs_output_section, + &stat_ptr->head, 0, (bfd_vma) 0, false); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (stat_ptr->head, abs_output_section, + (fill_type) 0, (bfd_vma) 0); +} + + /* Final emulation specific call. For the PA we use this opportunity to build linker stubs. */ static void hppaelf_finish () { + /* If generating a relocateable output file, then we don't + have to examine the relocs. */ + if (link_info.relocateable) + return; + /* Call into the BFD backend to do the real work. */ - if (elf32_hppa_size_stubs (stub_file->the_bfd, output_bfd, &link_info) - == false) + if (elf32_hppa_size_stubs (stub_file->the_bfd, + &link_info, + &hppaelf_add_stub_section, + &hppaelf_layaout_sections_again) == false) { einfo ("%X%P: can not size stub section: %E\n"); return; } - - /* If the size of the stub section is nonzero, then we need - to resize the sections, recompute the assignments, and finally - build the stubs. */ - if (bfd_section_size (stub_file->the_bfd, stub_file->the_bfd->sections) != 0) + + /* Now build the linker stubs. */ + if (stub_file->the_bfd->sections != NULL) { - /* Delete all the padding statements, they're no longer valid. */ - hppaelf_delete_padding_statements (stat_ptr->head, &stat_ptr->head); - - /* Resize the sections. */ - lang_size_sections (stat_ptr->head, abs_output_section, - &stat_ptr->head, 0, (bfd_vma) 0, false); - - /* Redo special stuff. */ - ldemul_after_allocation (); - - /* Do the assignments again. */ - lang_do_assignments (stat_ptr->head, - abs_output_section, - (fill_type) 0, (bfd_vma) 0); - - /* Now build the linker stubs. */ if (elf32_hppa_build_stubs (stub_file->the_bfd, &link_info) == false) + einfo ("%X%P: can not build stubs: %E\n"); + } +} + + +/* Place an orphan section. We use this to put random SHF_ALLOC + sections in the right segment. */ + +struct orphan_save +{ + lang_output_section_statement_type *os; + asection **section; + lang_statement_union_type **stmt; +}; + +/*ARGSUSED*/ +static boolean +gld${EMULATION_NAME}_place_orphan (file, s) + lang_input_statement_type *file; + asection *s; +{ + static struct orphan_save hold_text; + static struct orphan_save hold_rodata; + static struct orphan_save hold_data; + static struct orphan_save hold_bss; + static struct orphan_save hold_rel; + static struct orphan_save hold_interp; + struct orphan_save *place; + lang_statement_list_type *old; + lang_statement_list_type add; + etree_type *address; + const char *secname, *ps; + const char *outsecname; + lang_output_section_statement_type *os; + + secname = bfd_get_section_name (s->owner, s); + + /* Look through the script to see where to place this section. */ + os = lang_output_section_find (secname); + + if (os != NULL + && os->bfd_section != NULL + && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0) + { + /* We have already placed a section with this name. */ + wild_doit (&os->children, s, os, file); + return true; + } + + if (hold_text.os == NULL) + hold_text.os = lang_output_section_find (".text"); + + /* If this is a final link, then always put .gnu.warning.SYMBOL + sections into the .text section to get them out of the way. */ + if (! link_info.shared + && ! link_info.relocateable + && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 + && hold_text.os != NULL) + { + wild_doit (&hold_text.os->children, s, hold_text.os, file); + return true; + } + + /* Decide which segment the section should go in based on the + section name and section flags. We put loadable .note sections + right after the .interp section, so that the PT_NOTE segment is + stored right after the program headers where the OS can read it + in the first page. */ +#define HAVE_SECTION(hold, name) \ +(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) + + if (s->flags & SEC_EXCLUDE) + return false; + else if ((s->flags & SEC_ALLOC) == 0) + place = NULL; + else if ((s->flags & SEC_LOAD) != 0 + && strncmp (secname, ".note", 4) == 0 + && HAVE_SECTION (hold_interp, ".interp")) + place = &hold_interp; + else if ((s->flags & SEC_HAS_CONTENTS) == 0 + && HAVE_SECTION (hold_bss, ".bss")) + place = &hold_bss; + else if ((s->flags & SEC_READONLY) == 0 + && HAVE_SECTION (hold_data, ".data")) + place = &hold_data; + else if (strncmp (secname, ".rel", 4) == 0 + && (hold_rel.os != NULL + || (hold_rel.os = output_rel_find ()) != NULL)) + place = &hold_rel; + else if ((s->flags & SEC_CODE) == 0 + && (s->flags & SEC_READONLY) != 0 + && HAVE_SECTION (hold_rodata, ".rodata")) + place = &hold_rodata; + else if ((s->flags & SEC_READONLY) != 0 + && hold_text.os != NULL) + place = &hold_text; + else + place = NULL; + +#undef HAVE_SECTION + + /* Choose a unique name for the section. This will be needed if the + same section name appears in the input file with different + loadable or allocateable characteristics. */ + outsecname = secname; + if (bfd_get_section_by_name (output_bfd, outsecname) != NULL) + { + unsigned int len; + char *newname; + unsigned int i; + + len = strlen (outsecname); + newname = xmalloc (len + 5); + strcpy (newname, outsecname); + i = 0; + do + { + sprintf (newname + len, "%d", i); + ++i; + } + while (bfd_get_section_by_name (output_bfd, newname) != NULL); + + outsecname = newname; + } + + if (place != NULL) + { + /* Start building a list of statements for this section. */ + old = stat_ptr; + stat_ptr = &add; + lang_list_init (stat_ptr); + + /* If the name of the section is representable in C, then create + symbols to mark the start and the end of the section. */ + for (ps = outsecname; *ps != '\0'; ps++) + if (! isalnum ((unsigned char) *ps) && *ps != '_') + break; + if (*ps == '\0' && config.build_constructors) { - einfo ("%X%P: can not build stubs: %E\n"); - return; + char *symname; + etree_type *e_align; + + symname = (char *) xmalloc (ps - outsecname + sizeof "__start_"); + sprintf (symname, "__start_%s", outsecname); + e_align = exp_unop (ALIGN_K, + exp_intop ((bfd_vma) 1 << s->alignment_power)); + lang_add_assignment (exp_assop ('=', symname, e_align)); } } + + if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) + address = exp_intop ((bfd_vma) 0); + else + address = NULL; + + os = lang_enter_output_section_statement (outsecname, address, 0, + (bfd_vma) 0, + (etree_type *) NULL, + (etree_type *) NULL, + (etree_type *) NULL); + + wild_doit (&os->children, s, os, file); + + lang_leave_output_section_statement + ((bfd_vma) 0, "*default*", + (struct lang_output_section_phdr_list *) NULL, "*default*"); + + if (place != NULL) + { + asection *snew, **pps; + + stat_ptr = &add; + + if (*ps == '\0' && config.build_constructors) + { + char *symname; + + symname = (char *) xmalloc (ps - outsecname + sizeof "__stop_"); + sprintf (symname, "__stop_%s", outsecname); + lang_add_assignment (exp_assop ('=', symname, + exp_nameop (NAME, "."))); + } + stat_ptr = old; + + snew = os->bfd_section; + if (place->os->bfd_section != NULL || place->section != NULL) + { + /* Shuffle the section to make the output file look neater. */ + if (place->section == NULL) + { +#if 0 + /* Finding the end of the list is a little tricky. We + make a wild stab at it by comparing section flags. */ + flagword first_flags = place->os->bfd_section->flags; + for (pps = &place->os->bfd_section->next; + *pps != NULL && (*pps)->flags == first_flags; + pps = &(*pps)->next) + ; + place->section = pps; +#else + /* Put orphans after the first section on the list. */ + place->section = &place->os->bfd_section->next; +#endif + } + + /* Unlink the section. */ + for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) + ; + *pps = snew->next; + + /* Now tack it on to the "place->os" section list. */ + snew->next = *place->section; + *place->section = snew; + } + place->section = &snew->next; /* Save the end of this list. */ + + if (place->stmt == NULL) + { + /* Put the new statement list right at the head. */ + *add.tail = place->os->header.next; + place->os->header.next = add.head; + } + else + { + /* Put it after the last orphan statement we added. */ + *add.tail = *place->stmt; + *place->stmt = add.head; + } + place->stmt = add.tail; /* Save the end of this list. */ + } + + return true; +} + +/* A variant of lang_output_section_find. */ +static lang_output_section_statement_type * +output_rel_find () +{ + lang_statement_union_type *u; + lang_output_section_statement_type *lookup; + + for (u = lang_output_section_statement.head; + u != (lang_statement_union_type *) NULL; + u = lookup->next) + { + lookup = &u->output_section_statement; + if (strncmp (".rel", lookup->name, 4) == 0 + && lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + { + return lookup; + } + } + return (lang_output_section_statement_type *) NULL; } /* The script itself gets inserted here. */ @@ -219,7 +596,7 @@ then sc="-f stringify.sed" cat >>e${EMULATION_NAME}.c <<EOF -{ +{ *isfile = 0; if (link_info.relocateable == true && config.build_constructors == true) @@ -232,6 +609,12 @@ echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME} sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c + +if test -n "$GENERATE_SHLIB_SCRIPT" ; then +echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c +fi + echo ' ; else return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c echo '; }' >> e${EMULATION_NAME}.c @@ -251,6 +634,8 @@ cat >>e${EMULATION_NAME}.c <<EOF return "ldscripts/${EMULATION_NAME}.xbn"; else if (!config.magic_demand_paged) return "ldscripts/${EMULATION_NAME}.xn"; + else if (link_info.shared) + return "ldscripts/${EMULATION_NAME}.xs"; else return "ldscripts/${EMULATION_NAME}.x"; } @@ -260,7 +645,7 @@ fi cat >>e${EMULATION_NAME}.c <<EOF -struct ld_emulation_xfer_struct ld_hppaelf_emulation = +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { hppaelf_before_parse, syslib_default, @@ -272,17 +657,17 @@ struct ld_emulation_xfer_struct ld_hppaelf_emulation = ldemul_default_target, before_allocation_default, hppaelf_get_script, - "hppaelf", + "${EMULATION_NAME}", "elf32-hppa", hppaelf_finish, hppaelf_create_output_section_statements, - NULL, /* open dynamic archive */ - NULL, /* place orphan */ - NULL, /* set symbols */ - NULL, /* parse args */ - NULL, /* unrecognized file */ - NULL, /* list options */ - NULL, /* recognized file */ - NULL /* find_potential_libraries */ + NULL, /* open dynamic */ + gld${EMULATION_NAME}_place_orphan, + NULL, /* set_symbols */ + NULL, /* parse_args */ + NULL, /* unrecognized_file */ + NULL, /* list_options */ + NULL, /* recognized_file */ + NULL /* find_potential_libraries */ }; EOF |