hppaelf.em: Merge from elf32.em and implement multiple linker stubs.
authorAlan Modra <amodra@gmail.com>
Sun, 9 Jul 2000 08:45:29 +0000 (08:45 +0000)
committerAlan Modra <amodra@gmail.com>
Sun, 9 Jul 2000 08:45:29 +0000 (08:45 +0000)
Makefile.am: Re-enable ehppaelf.o, add ehppalinux.o
configure.tgt: targ_emul=hppalinux for hppa*linux

ld/ChangeLog
ld/Makefile.am
ld/Makefile.in
ld/configure.tgt
ld/emulparams/hppaelf.sh
ld/emulparams/hppalinux.sh [new file with mode: 0644]
ld/emultempl/hppaelf.em

index 4109d25..bffdd5d 100644 (file)
@@ -1,3 +1,49 @@
+2000-07-09  Alan Modra  <alan@linuxcare.com.au>
+
+       Changes to create multiple linker stubs, positioned immediately
+       before the section where they are required.
+       * emultempl/hppaelf.em: Include elf32-hppa.h.
+       (stub_sec, file_chain): Delete.
+       (hppaelf_create_output_section_statements): Don't make a stub
+       section here.
+       (hook_stub_info): New struct.
+       (hook_in_stub): New function.
+       (hppaelf_add_stub_section): New function.
+       (hppaelf_finish): Do nothing for relocateable links.  Modify the
+       call to elf32_hppa_size_stubs.  Move code for updating section
+       layout from here...
+       (hppaelf_layaout_sections_again): ..to here, a new function.
+
+       * emultempl/hppaelf.em (hppaelf_delete_padding_statements): Fix
+       broken list handling.  Pass in a pointer to the list.
+       (hppaelf_finish): Update call to hppaelf_delete_padding_statements
+       for above changes.
+       (hppaelf_before_parse): Prototype.
+       (hppaelf_set_output_arch): Prototype.
+       (hppaelf_create_output_section_statements): Prototype.
+       (hppaelf_delete_padding_statements): Prototype.
+       (hppaelf_finish): Prototype.
+
+       Merge from elf32.em
+       * emultempl/hppaelf.em: Include ctype.h.
+       (struct orphan_save): New.
+       (gld${EMULATION_NAME}_place_orphan): New.
+       (output_rel_find): New.
+       (hppaelf_get_script): Update from elf32.em.
+       (ld_hppaelf_emulation): Rename to ld_${EMULATION_NAME}_emulation.
+       Change emulation_name field to "${EMULATION_NAME}".  Add
+       gld${EMULATION_NAME}_place_orphan. 
+
+       * Makefile.am (ALL_EMULATIONS): Reinstate ehppaelf.o,  add
+       ehppalinux.o, sort it.  Regenerate dependencies.
+       (ehppalinux.c): Depend on hppaelf.em
+       * Makefile.in: Regenerate.
+
+       * configure.tgt: targ_emul=hppalinux for hppa*linux
+
+       * emulparams/hppalinux.sh: New.
+       * emulparams/hppaelf.sh (TARGET_PAGE_SIZE): Write in hex.
+
 2000-07-08  Alan Modra  <alan@linuxcare.com.au>
 
        * lexsup.c (parse_args): Copy section name.
index 0569ce0..1ab671d 100644 (file)
@@ -104,53 +104,53 @@ ALL_EMULATIONS = \
        eaixrs6.o \
        ealpha.o \
        earcelf.o \
-       earmelf.o \
-       earmelf_oabi.o \
-       earmelf_linux.o \
-       earmelf_linux26.o \
+       earm_epoc_pe.o \
        earmaoutb.o \
        earmaoutl.o \
        earmcoff.o \
+       earmelf.o \
+       earmelf_linux.o \
+       earmelf_linux26.o \
+       earmelf_oabi.o \
        earmnbsd.o \
        earmpe.o \
-       earm_epoc_pe.o \
        eavr1200.o \
        eavr23xx.o \
-       eavr44x4.o \
        eavr4433.o \
+       eavr44x4.o \
        eavr85xx.o \
-       eavrmega603.o \
        eavrmega103.o \
        eavrmega161.o \
+       eavrmega603.o \
        ecoff_sparc.o \
        ed10velf.o \
-       ed30velf.o \
        ed30v_e.o \
        ed30v_o.o \
+       ed30velf.o \
        edelta68.o \
        eebmon29k.o \
-       eelf32_sparc.o \
        eelf32_i960.o \
+       eelf32_sparc.o \
        eelf32b4300.o \
        eelf32bmip.o \
-       eelf32ebmip.o \
-       eelf32elmip.o \
        eelf32bmipn32.o \
        eelf32btsmip.o \
+       eelf32ebmip.o \
+       eelf32elmip.o \
+       eelf32fr30.o \
        eelf32i370.o \
        eelf32l4300.o \
        eelf32lmip.o \
        eelf32lppc.o \
        eelf32lppcsim.o \
+       eelf32mcore.o \
        eelf32ppc.o \
-       eelf32ppcsim.o \
        eelf32ppclinux.o \
+       eelf32ppcsim.o \
        eelf_i386.o \
        eelf_i386_be.o \
        egld960.o \
        egld960coff.o \
-       eelf32fr30.o \
-       eelf32mcore.o \
        eh8300.o \
        eh8300h.o \
        eh8300s.o \
@@ -161,6 +161,8 @@ ALL_EMULATIONS = \
        eh8500s.o \
        ehp300bsd.o \
        ehp3hpux.o \
+       ehppaelf.o \
+       ehppalinux.o \
        ei386aout.o \
        ei386beos.o \
        ei386bsd.o \
@@ -199,10 +201,10 @@ ALL_EMULATIONS = \
        emipslnews.o \
        emipspe.o \
        enews.o \
-       epjelf.o \
-       epjlelf.o \
        ens32knbsd.o \
        epc532macha.o \
+       epjelf.o \
+       epjlelf.o \
        eppcmacos.o \
        eppcnw.o \
        eppcpe.o \
@@ -210,8 +212,8 @@ ALL_EMULATIONS = \
        esa29200.o \
        esh.o \
        eshelf.o \
-       eshlelf.o \
        eshl.o \
+       eshlelf.o \
        eshpe.o \
        esparcaout.o \
        esparclinux.o \
@@ -231,20 +233,16 @@ ALL_EMULATIONS = \
        ez8001.o \
        ez8002.o
 
-# The following object file has been removed from ALL_EMULATIONS
-# because the BFD support is currently broken.
-#      ehppaelf.o 
-
 ALL_64_EMULATIONS = \
        eelf64_ia64.o \
        eelf64_sparc.o \
        eelf64alpha.o \
-       eelf64hppa.o \
-       eelf64bmip.o
+       eelf64bmip.o \
+       eelf64hppa.o
 
 ALL_EMUL_EXTRA_OFILES = \
-       pe-dll.o \
-       deffilep.o
+       deffilep.o \
+       pe-dll.o
 
 CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \
        ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \
@@ -521,6 +519,9 @@ ehp3hpux.c: $(srcdir)/emulparams/hp3hpux.sh \
 ehppaelf.c: $(srcdir)/emulparams/hppaelf.sh \
   $(srcdir)/emultempl/hppaelf.em $(srcdir)/scripttempl/hppaelf.sc ${GEN_DEPENDS}
        ${GENSCRIPTS} hppaelf "$(tdir_hppaelf)"
+ehppalinux.c: $(srcdir)/emulparams/hppalinux.sh \
+  $(srcdir)/emultempl/hppaelf.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+       ${GENSCRIPTS} hppalinux "$(tdir_hppalinux)"
 ei386aout.c: $(srcdir)/emulparams/i386aout.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
        ${GENSCRIPTS} i386aout "$(tdir_i386aout)"
index be21dcd..20693ad 100644 (file)
@@ -207,53 +207,53 @@ ALL_EMULATIONS = \
        eaixrs6.o \
        ealpha.o \
        earcelf.o \
-       earmelf.o \
-       earmelf_oabi.o \
-       earmelf_linux.o \
-       earmelf_linux26.o \
+       earm_epoc_pe.o \
        earmaoutb.o \
        earmaoutl.o \
        earmcoff.o \
+       earmelf.o \
+       earmelf_linux.o \
+       earmelf_linux26.o \
+       earmelf_oabi.o \
        earmnbsd.o \
        earmpe.o \
-       earm_epoc_pe.o \
        eavr1200.o \
        eavr23xx.o \
-       eavr44x4.o \
        eavr4433.o \
+       eavr44x4.o \
        eavr85xx.o \
-       eavrmega603.o \
        eavrmega103.o \
        eavrmega161.o \
+       eavrmega603.o \
        ecoff_sparc.o \
        ed10velf.o \
-       ed30velf.o \
        ed30v_e.o \
        ed30v_o.o \
+       ed30velf.o \
        edelta68.o \
        eebmon29k.o \
-       eelf32_sparc.o \
        eelf32_i960.o \
+       eelf32_sparc.o \
        eelf32b4300.o \
        eelf32bmip.o \
-       eelf32ebmip.o \
-       eelf32elmip.o \
        eelf32bmipn32.o \
        eelf32btsmip.o \
+       eelf32ebmip.o \
+       eelf32elmip.o \
+       eelf32fr30.o \
        eelf32i370.o \
        eelf32l4300.o \
        eelf32lmip.o \
        eelf32lppc.o \
        eelf32lppcsim.o \
+       eelf32mcore.o \
        eelf32ppc.o \
-       eelf32ppcsim.o \
        eelf32ppclinux.o \
+       eelf32ppcsim.o \
        eelf_i386.o \
        eelf_i386_be.o \
        egld960.o \
        egld960coff.o \
-       eelf32fr30.o \
-       eelf32mcore.o \
        eh8300.o \
        eh8300h.o \
        eh8300s.o \
@@ -264,6 +264,8 @@ ALL_EMULATIONS = \
        eh8500s.o \
        ehp300bsd.o \
        ehp3hpux.o \
+       ehppaelf.o \
+       ehppalinux.o \
        ei386aout.o \
        ei386beos.o \
        ei386bsd.o \
@@ -302,10 +304,10 @@ ALL_EMULATIONS = \
        emipslnews.o \
        emipspe.o \
        enews.o \
-       epjelf.o \
-       epjlelf.o \
        ens32knbsd.o \
        epc532macha.o \
+       epjelf.o \
+       epjlelf.o \
        eppcmacos.o \
        eppcnw.o \
        eppcpe.o \
@@ -313,8 +315,8 @@ ALL_EMULATIONS = \
        esa29200.o \
        esh.o \
        eshelf.o \
-       eshlelf.o \
        eshl.o \
+       eshlelf.o \
        eshpe.o \
        esparcaout.o \
        esparclinux.o \
@@ -335,21 +337,17 @@ ALL_EMULATIONS = \
        ez8002.o
 
 
-# The following object file has been removed from ALL_EMULATIONS
-# because the BFD support is currently broken.
-#      ehppaelf.o 
-
 ALL_64_EMULATIONS = \
        eelf64_ia64.o \
        eelf64_sparc.o \
        eelf64alpha.o \
-       eelf64hppa.o \
-       eelf64bmip.o
+       eelf64bmip.o \
+       eelf64hppa.o
 
 
 ALL_EMUL_EXTRA_OFILES = \
-       pe-dll.o \
-       deffilep.o
+       deffilep.o \
+       pe-dll.o
 
 
 CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \
@@ -446,7 +444,7 @@ deffilep.c ldgram.c ldlex.c
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = gtar
+TAR = tar
 GZIP_ENV = --best
 SOURCES = $(ld_new_SOURCES) $(EXTRA_ld_new_SOURCES)
 OBJECTS = $(ld_new_OBJECTS)
@@ -1222,6 +1220,9 @@ ehp3hpux.c: $(srcdir)/emulparams/hp3hpux.sh \
 ehppaelf.c: $(srcdir)/emulparams/hppaelf.sh \
   $(srcdir)/emultempl/hppaelf.em $(srcdir)/scripttempl/hppaelf.sc ${GEN_DEPENDS}
        ${GENSCRIPTS} hppaelf "$(tdir_hppaelf)"
+ehppalinux.c: $(srcdir)/emulparams/hppalinux.sh \
+  $(srcdir)/emultempl/hppaelf.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+       ${GENSCRIPTS} hppalinux "$(tdir_hppalinux)"
 ei386aout.c: $(srcdir)/emulparams/i386aout.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
        ${GENSCRIPTS} i386aout "$(tdir_i386aout)"
index 8d3c4f0..9f257fd 100644 (file)
@@ -208,6 +208,7 @@ m68*-*-netbsd*)             targ_emul=m68knbsd ;;
 m68*-*-psos*)          targ_emul=m68kpsos ;;
 m68*-*-rtems*)         targ_emul=m68kcoff ;;
 hppa*64*-*)            targ_emul=elf64hppa ;;
+hppa*-*-linux-gnu*)    targ_emul=hppalinux ;;
 hppa*-*-*elf*)         targ_emul=hppaelf ;;
 hppa*-*-linux-gnu*)    targ_emul=hppaelf ;;
 hppa*-*-lites*)                targ_emul=hppaelf ;;
index 47b89ea..2cd06ac 100644 (file)
@@ -1,7 +1,7 @@
 SCRIPT_NAME=hppaelf
 OUTPUT_FORMAT="elf32-hppa"
 TEXT_START_ADDR=0x1000
-TARGET_PAGE_SIZE=4096
+TARGET_PAGE_SIZE=0x1000
 ARCH=hppa
 START="$START$"
 TEMPLATE_NAME=hppaelf
diff --git a/ld/emulparams/hppalinux.sh b/ld/emulparams/hppalinux.sh
new file mode 100644 (file)
index 0000000..e82315f
--- /dev/null
@@ -0,0 +1,10 @@
+SCRIPT_NAME=elf
+OUTPUT_FORMAT="elf32-hppa"
+TEXT_START_ADDR=0x1000
+TARGET_PAGE_SIZE=0x1000
+MAXPAGESIZE=0x1000
+ARCH=hppa
+NOP=0x08000240
+START="_start"
+TEMPLATE_NAME=hppaelf
+DATA_START_SYMBOLS='$global$ = .;'
index fde4362..51f3bbd 100644 (file)
@@ -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