aboutsummaryrefslogtreecommitdiff
path: root/ld/emultempl
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2000-07-09 08:45:29 +0000
committerAlan Modra <amodra@gmail.com>2000-07-09 08:45:29 +0000
commit4900fc0695949d2c616c78553893e6cfbcac73aa (patch)
tree2652d2a9016dea2ab82df6807467c092e52d2b43 /ld/emultempl
parentad1079af05c5820e0f4e9d1ba24d30c03bff98f6 (diff)
downloadgdb-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.em551
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