* ldlang.c (record_bfd_errors): Remove.
[binutils-gdb.git] / ld / emultempl / aix.em
index ae0d7ddf7f0c12c1ca2e52da585f20dd7a0b56a5..9b037a0d63215b8f79530f61af92f74c995cb121 100644 (file)
@@ -1,12 +1,19 @@
 # This shell script emits a C file. -*- C -*-
 # It does some substitutions.
+if [ -z "$MACHINE" ]; then
+  OUTPUT_ARCH=${ARCH}
+else
+  OUTPUT_ARCH=${ARCH}:${MACHINE}
+fi
 cat >e${EMULATION_NAME}.c <<EOF
 /* This file is is generated by a shell script.  DO NOT EDIT! */
 
 /* AIX emulation code for ${EMULATION_NAME}
-   Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
+   Copyright 1991, 1993, 1995, 1996, 1997, 1998, 2000, 2001
+   Free Software Foundation, Inc.
    Written by Steve Chamberlain <sac@cygnus.com>
    AIX support by Ian Lance Taylor <ian@cygnus.com>
+   AIX 64 bit support by Tom Rix <trix@redhat.com>
 
 This file is part of GLD, the Gnu Linker.
 
@@ -30,6 +37,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "sysdep.h"
 #include "libiberty.h"
 #include "getopt.h"
+#include "obstack.h"
 #include "bfdlink.h"
 
 #include <ctype.h>
@@ -41,12 +49,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "ldmisc.h"
 #include "ldexp.h"
 #include "ldlang.h"
+#include "ldctor.h"
+#include "ldgram.h"
+
+#include "coff/internal.h"
+#include "coff/xcoff.h"
 
 static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
 static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **));
+static void gld${EMULATION_NAME}_after_open PARAMS ((void));
 static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
 static void gld${EMULATION_NAME}_read_file PARAMS ((const char *, boolean));
 static void gld${EMULATION_NAME}_free PARAMS ((PTR));
+static void gld${EMULATION_NAME}_find_relocs
+  PARAMS ((lang_statement_union_type *));
+static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
 static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
 
 /* The file alignment required for each section.  */
@@ -69,7 +86,10 @@ static unsigned short modtype = ('1' << 8) | 'L';
    permitted).  */
 static int textro;
 
-/* Structure used to hold import or export file list.  */
+/* Whether to implement Unix like linker semantics.  */
+static int unix_ld;
+
+/* Structure used to hold import file list.  */
 
 struct filelist
 {
@@ -78,17 +98,48 @@ struct filelist
 };
 
 /* List of import files.  */
-struct filelist *import_files;
+static struct filelist *import_files;
+
+/* List of export symbols read from the export files.  */
+
+struct export_symbol_list
+{
+  struct export_symbol_list *next;
+  const char *name;
+  boolean syscall;
+};
 
-/* List of export files.  */
-struct filelist *export_files;
+static struct export_symbol_list *export_symbols;
+
+/* Maintains the 32 or 64 bit mode state of import file */
+static unsigned int symbol_mode = 0x04;
+
+/* This routine is called before anything else is done.  */
 
 static void
 gld${EMULATION_NAME}_before_parse()
 {
 #ifndef TARGET_                        /* I.e., if not generic.  */
-  ldfile_output_architecture = bfd_arch_${ARCH};
+  const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}");
+  if (arch)
+    {
+      ldfile_output_architecture = arch->arch;
+      ldfile_output_machine = arch->mach;
+      ldfile_output_machine_name = arch->printable_name;
+    }
+  else
+    ldfile_output_architecture = bfd_arch_${ARCH};
 #endif /* not TARGET_ */
+  config.has_shared = true;
+
+  /*
+   * The link_info.[init|fini]_functions are initialized in ld/lexsup.c.
+   * Override them here so we can use the link_info.init_function as a
+   * state flag that lets the backend know that -binitfini has been done.
+   */ 
+  link_info.init_function = NULL;
+  link_info.fini_function = NULL;
+
 }
 
 /* Handle AIX specific options.  */
@@ -100,25 +151,84 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
 {
   int prevoptind = optind;
   int prevopterr = opterr;
+  int indx;
   int longind;
   int optc;
-  long val;
+  bfd_signed_vma val;
   char *end;
 
-#define OPTION_IGNORE (300)
-#define OPTION_AUTOIMP (OPTION_IGNORE + 1)
-#define OPTION_ERNOTOK (OPTION_AUTOIMP + 1)
-#define OPTION_EROK (OPTION_ERNOTOK + 1)
-#define OPTION_EXPORT (OPTION_EROK + 1)
-#define OPTION_IMPORT (OPTION_EXPORT + 1)
-#define OPTION_MAXDATA (OPTION_IMPORT + 1)
-#define OPTION_MAXSTACK (OPTION_MAXDATA + 1)
-#define OPTION_MODTYPE (OPTION_MAXSTACK + 1)
-#define OPTION_NOAUTOIMP (OPTION_MODTYPE + 1)
-#define OPTION_NOSTRCMPCT (OPTION_NOAUTOIMP + 1)
-#define OPTION_STRCMPCT (OPTION_NOSTRCMPCT + 1)
-
-  static struct option longopts[] = {
+  enum {
+    OPTION_IGNORE = 300,
+    OPTION_AUTOIMP, 
+    OPTION_ERNOTOK, 
+    OPTION_EROK, 
+    OPTION_EXPORT, 
+    OPTION_IMPORT, 
+    OPTION_INITFINI, 
+    OPTION_LOADMAP, 
+    OPTION_MAXDATA, 
+    OPTION_MAXSTACK, 
+    OPTION_MODTYPE, 
+    OPTION_NOAUTOIMP, 
+    OPTION_NOSTRCMPCT, 
+    OPTION_PD, 
+    OPTION_PT, 
+    OPTION_STRCMPCT, 
+    OPTION_UNIX
+  };
+
+  /*
+    b64 is an empty option.  The native linker uses -b64 for xcoff64 support
+    Our linker uses -m aixppc64 for xcoff64 support. The choice for the 
+    correct emulation is done in collect2.c via the environmental varible
+    LDEMULATION.
+       
+    binitfini has special handling in the linker backend.  The native linker
+    uses the arguemnts to generate a table of init and fini functions for
+    the executable.  The important use for this option is to support aix 4.2+
+    c++ constructors and destructors.  This is tied into gcc via collect2.c.
+       The function table is accessed by the runtime linker/loader by checking if
+       the first symbol in the loader symbol table is "__rtinit".  The native
+       linker generates this table and the loader symbol.  The gnu linker looks
+       for the symbol "__rtinit" and makes it the first loader symbol.  It is the
+       responsiblity of the user to define the __rtinit symbol.  The format for
+       __rtinit is given by the aix system file /usr/include/rtinit.h.  You can
+       look at collect2.c to see an example of how this is done for 32 and 64 bit.
+       Below is an exmaple of a 32 bit assembly file that defines __rtinit.
+
+       .file   "my_rtinit.s"
+       
+       .csect .data[RW],3
+       .globl __rtinit
+       .extern init_function
+       .extern fini_function
+       
+       __rtinit:
+               .long 0
+               .long f1i - __rtinit
+               .long f1f - __rtinit
+               .long f2i - f1i
+               .align 3
+       f1i:    .long init_function
+               .long s1i - __rtinit
+               .long 0
+       f2i:    .long 0
+               .long 0
+               .long 0
+       f1f:    .long fini_function
+               .long s1f - __rtinit
+               .long 0
+       f2f:    .long 0
+               .long 0
+               .long 0
+               .align 3
+       s1i:    .string "init_function"
+               .align 3
+       s1f:    .string "fini_function"
+
+   */
+
+  static const struct option longopts[] = {
     {"basis", no_argument, NULL, OPTION_IGNORE},
     {"bautoimp", no_argument, NULL, OPTION_AUTOIMP},
     {"bcomprld", no_argument, NULL, OPTION_IGNORE},
@@ -136,22 +246,31 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
     {"bhalt", required_argument, NULL, OPTION_IGNORE},
     {"bI", required_argument, NULL, OPTION_IMPORT},
     {"bimport", required_argument, NULL, OPTION_IMPORT},
+    {"binitfini", required_argument, NULL, OPTION_INITFINI},
+    {"bl", required_argument, NULL, OPTION_LOADMAP},
+    {"bloadmap", required_argument, NULL, OPTION_LOADMAP},
     {"bmaxdata", required_argument, NULL, OPTION_MAXDATA},
     {"bmaxstack", required_argument, NULL, OPTION_MAXSTACK},
     {"bM", required_argument, NULL, OPTION_MODTYPE},
     {"bmodtype", required_argument, NULL, OPTION_MODTYPE},
     {"bnoautoimp", no_argument, NULL, OPTION_NOAUTOIMP},
     {"bnodelcsect", no_argument, NULL, OPTION_IGNORE},
+    {"bnoentry", no_argument, NULL, OPTION_IGNORE},
     {"bnogc", no_argument, &gc, 0},
     {"bnso", no_argument, NULL, OPTION_NOAUTOIMP},
     {"bnostrcmpct", no_argument, NULL, OPTION_NOSTRCMPCT},
     {"bnotextro", no_argument, &textro, 0},
     {"bnro", no_argument, &textro, 0},
+    {"bpD", required_argument, NULL, OPTION_PD},
+    {"bpT", required_argument, NULL, OPTION_PT},
     {"bro", no_argument, &textro, 1},
     {"bS", required_argument, NULL, OPTION_MAXSTACK},
     {"bso", no_argument, NULL, OPTION_AUTOIMP},
     {"bstrcmpct", no_argument, NULL, OPTION_STRCMPCT},
     {"btextro", no_argument, &textro, 1},
+    {"b64", no_argument, NULL, 0},
+    {"static", no_argument, NULL, OPTION_NOAUTOIMP},
+    {"unix", no_argument, NULL, OPTION_UNIX},
     {NULL, no_argument, NULL, 0}
   };
 
@@ -164,29 +283,37 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
      -bnotypchk, -bnox, -bquiet, -bR, -brename, -breorder, -btypchk,
      -bx, -bX, -bxref.  */
 
-  /* If the first option starts with -b, change the first : to an =.
+  /* If the current option starts with -b, change the first : to an =.
      The AIX linker uses : to separate the option from the argument;
      changing it to = lets us treat it as a getopt option.  */
-  if (optind < argc && strncmp (argv[optind], "-b", 2) == 0)
-    {
-      char *s;
-
-      for (s = argv[optind]; *s != '\0'; s++)
-       {
-         if (*s == ':')
-           {
-             *s = '=';
-             break;
-           }
-       }
+  indx = optind;
+  if (indx == 0) {
+    indx = 1;
+  }
+
+  if (indx < argc && strncmp (argv[indx], "-b", 2) == 0) {
+    char *s;
+    
+    for (s = argv[indx]; *s != '\0'; s++) {
+      if (*s == ':') {
+       *s = '=';
+       break;
+      }
     }
+  }
+
+
+  /* We add s and u so to the short options list so that -s and -u on
+     the command line do not match -static and -unix.  */
 
   opterr = 0;
-  optc = getopt_long_only (argc, argv, "-D:H:KT:z", longopts, &longind);
+  optc = getopt_long_only (argc, argv, "-D:H:KT:zsu", longopts, &longind);
   opterr = prevopterr;
 
   switch (optc)
     {
+    case 's':
+    case 'u':
     default:
       optind = prevoptind;
       return 0;
@@ -196,7 +323,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
       break;
 
     case 'D':
-      val = strtol (optarg, &end, 0);
+      val = strtoll (optarg, &end, 0);
       if (*end != '\0')
        einfo ("%P: warning: ignoring invalid -D number %s\n", optarg);
       else if (val != -1)
@@ -223,7 +350,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
          number, we assume the AIX option is intended.  Otherwise, we
          assume the usual GNU ld -T option is intended.  We can't just
          ignore the AIX option, because gcc passes it to the linker.  */
-      val = strtoul (optarg, &end, 0);
+      val = strtoull (optarg, &end, 0);
       if (*end != '\0')
        {
          optind = prevoptind;
@@ -235,6 +362,41 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
     case OPTION_IGNORE:
       break;
 
+    case OPTION_INITFINI: {
+      /* 
+       * The aix linker init fini has the format :
+       *
+       * -binitfini:[ Initial][:Termination][:Priority]
+       *
+       * it allows the Termination and Priority to be optional.
+       *
+       * Since we support only one init/fini pair, we ignore the Priority.
+       * 
+       * Define the special symbol __rtinit.
+       *
+       * strtok does not correctly handle the case of -binitfini::fini: so
+       * do it by hand
+       */
+      char *t, *i, *f;
+
+      i = t = optarg;
+      while (*t && ':' != *t) t++;
+      if (*t) *t++ = 0;
+
+      if (0 != strlen(i)) {
+       link_info.init_function = i;
+      }
+
+      f = t;
+      while (*t && ':' != *t) t++;
+      *t = 0;
+
+      if (0 != strlen(f)) {
+       link_info.fini_function = f;
+      }
+    }
+    break;
+
     case OPTION_AUTOIMP:
       link_info.static_link = false;
       break;
@@ -248,6 +410,9 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
       break;
 
     case OPTION_EXPORT:
+      gld${EMULATION_NAME}_read_file (optarg, false);
+      break;
+
     case OPTION_IMPORT:
       {
        struct filelist *n;
@@ -256,18 +421,19 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
        n = (struct filelist *) xmalloc (sizeof (struct filelist));
        n->next = NULL;
        n->name = optarg;
-       if (optc == OPTION_EXPORT)
-         flpp = &export_files;
-       else
-         flpp = &import_files;
+       flpp = &import_files;
        while (*flpp != NULL)
          flpp = &(*flpp)->next;
        *flpp = n;
       }
       break;
 
+    case OPTION_LOADMAP:
+      config.map_filename = optarg;
+      break;
+
     case OPTION_MAXDATA:
-      val = strtoul (optarg, &end, 0);
+      val = strtoull (optarg, &end, 0);
       if (*end != '\0')
        einfo ("%P: warning: ignoring invalid -bmaxdata number %s\n",
               optarg);
@@ -276,7 +442,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
       break;
 
     case OPTION_MAXSTACK:
-      val = strtoul (optarg, &end, 0);
+      val = strtoull (optarg, &end, 0);
       if (*end != '\0')
        einfo ("%P: warning: ignoring invalid -bmaxstack number %s\n",
               optarg);
@@ -301,17 +467,149 @@ gld${EMULATION_NAME}_parse_args (argc, argv)
       break;
 
     case OPTION_NOSTRCMPCT:
-      config.traditional_format = true;
+      link_info.traditional_format = true;
+      break;
+
+    case OPTION_PD:
+      /* This sets the page that the .data section is supposed to
+         start on.  The offset within the page should still be the
+         offset within the file, so we need to build an appropriate
+         expression.  */
+      val = strtoull (optarg, &end, 0);
+      if (*end != '\0')
+       einfo ("%P: warning: ignoring invalid -pD number %s\n", optarg);
+      else
+       {
+         etree_type *t;
+
+         t = exp_binop ('+',
+                        exp_intop (val),
+                        exp_binop ('&',
+                                   exp_nameop (NAME, "."),
+                                   exp_intop (0xfff)));
+         t = exp_binop ('&',
+                        exp_binop ('+', t, exp_intop (31)),
+                        exp_intop (~ (bfd_vma) 31));
+         lang_section_start (".data", t);
+       }
+      break;
+
+    case OPTION_PT:
+      /* This set the page that the .text section is supposed to start
+         on.  The offset within the page should still be the offset
+         within the file.  */
+      val = strtoull (optarg, &end, 0);
+      if (*end != '\0')
+       einfo ("%P: warning: ignoring invalid -pT number %s\n", optarg);
+      else
+       {
+         etree_type *t;
+
+         t = exp_binop ('+',
+                        exp_intop (val),
+                        exp_nameop (SIZEOF_HEADERS, NULL));
+         t = exp_binop ('&',
+                        exp_binop ('+', t, exp_intop (31)),
+                        exp_intop (~ (bfd_vma) 31));
+         lang_section_start (".text", t);
+       }
       break;
 
     case OPTION_STRCMPCT:
-      config.traditional_format = false;
+      link_info.traditional_format = false;
+      break;
+
+    case OPTION_UNIX:
+      unix_ld = true;
       break;
     }
 
   return 1;
 }
 
+/* This is called when an input file can not be recognized as a BFD
+   object or an archive.  If the file starts with #!, we must treat it
+   as an import file.  This is for AIX compatibility.  */
+
+static boolean
+gld${EMULATION_NAME}_unrecognized_file (entry)
+     lang_input_statement_type *entry;
+{
+  FILE *e;
+  boolean ret;
+
+  e = fopen (entry->filename, FOPEN_RT);
+  if (e == NULL)
+    return false;
+
+  ret = false;
+
+  if (getc (e) == '#' && getc (e) == '!')
+    {
+      struct filelist *n;
+      struct filelist **flpp;
+
+      n = (struct filelist *) xmalloc (sizeof (struct filelist));
+      n->next = NULL;
+      n->name = entry->filename;
+      flpp = &import_files;
+      while (*flpp != NULL)
+       flpp = &(*flpp)->next;
+      *flpp = n;
+
+      ret = true;
+      entry->loaded = true;
+    }
+
+  fclose (e);
+
+  return ret;
+}
+
+/* This is called after the input files have been opened.  */
+
+static void
+gld${EMULATION_NAME}_after_open ()
+{
+  boolean r;
+  struct set_info *p;
+
+  /* Call ldctor_build_sets, after pretending that this is a
+     relocateable link.  We do this because AIX requires relocation
+     entries for all references to symbols, even in a final
+     executable.  Of course, we only want to do this if we are
+     producing an XCOFF output file.  */
+  r = link_info.relocateable;
+  if (strstr (bfd_get_target (output_bfd), "xcoff") != NULL)
+    link_info.relocateable = true;
+  ldctor_build_sets ();
+  link_info.relocateable = r;
+
+  /* For each set, record the size, so that the XCOFF backend can
+     output the correct csect length.  */
+  for (p = sets; p != (struct set_info *) NULL; p = p->next)
+    {
+      bfd_size_type 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;
+
+      if (p->reloc != BFD_RELOC_CTOR)
+       {
+         /* Handle this if we need to.  */
+         abort ();
+       }
+
+      size = (p->count + 2) * 4;
+      if (! bfd_xcoff_link_record_set (output_bfd, &link_info, p->h, size))
+       einfo ("%F%P: bfd_xcoff_link_record_set failed: %E\n");
+    }
+}
+
 /* This is called after the sections have been attached to output
    sections, but before any sizes or addresses have been set.  */
 
@@ -319,13 +617,29 @@ static void
 gld${EMULATION_NAME}_before_allocation ()
 {
   struct filelist *fl;
+  struct export_symbol_list *el;
   char *libpath;
+  asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS];
+  int i;
 
   /* Handle the import and export files, if any.  */
   for (fl = import_files; fl != NULL; fl = fl->next)
     gld${EMULATION_NAME}_read_file (fl->name, true);
-  for (fl = export_files; fl != NULL; fl = fl->next)
-    gld${EMULATION_NAME}_read_file (fl->name, false);
+  for (el = export_symbols; el != NULL; el = el->next) {
+    struct bfd_link_hash_entry *h;
+    
+    h = bfd_link_hash_lookup (link_info.hash, el->name, false, false, false);
+    if (h == NULL)
+      einfo ("%P%F: bfd_link_hash_lookup of export symbol failed: %E\n");
+    if (! bfd_xcoff_export_symbol (output_bfd, &link_info, h, el->syscall))
+      einfo ("%P%F: bfd_xcoff_export_symbol failed: %E\n");
+  }
+
+  /* Track down all relocations called for by the linker script (these
+     are typically constructor/destructor entries created by
+     CONSTRUCTORS) and let the backend know it will need to create
+     .loader relocs for them.  */
+  lang_for_each_statement (gld${EMULATION_NAME}_find_relocs);
 
   /* We need to build LIBPATH from the -L arguments.  If any -rpath
      arguments were used, though, we use -rpath instead, as a GNU
@@ -358,13 +672,198 @@ gld${EMULATION_NAME}_before_allocation ()
   if (! bfd_xcoff_size_dynamic_sections (output_bfd, &link_info, libpath,
                                         entry_symbol, file_align,
                                         maxstack, maxdata,
-                                        gc ? true : false,
+                                        gc && ! unix_ld ? true : false,
                                         modtype,
-                                        textro ? true : false))
+                                        textro ? true : false,
+                                        unix_ld,
+                                        special_sections))
     einfo ("%P%F: failed to set dynamic section sizes: %E\n");
+
+  /* Look through the special sections, and put them in the right
+     place in the link ordering.  This is especially magic.  */
+  for (i = 0; i < XCOFF_NUMBER_OF_SPECIAL_SECTIONS; i++) {
+    asection *sec;
+    lang_output_section_statement_type *os;
+    lang_statement_union_type **pls;
+    lang_input_section_type *is;
+    const char *oname;
+    boolean start;
+
+    sec = special_sections[i];
+    if (sec == NULL)
+      continue;
+
+    /* Remove this section from the list of the output section.
+       This assumes we know what the script looks like.  */
+    is = NULL;
+    os = lang_output_section_find (sec->output_section->name);
+    if (os == NULL) {
+      einfo ("%P%F: can't find output section %s\n",
+            sec->output_section->name);
+    }
+
+    for (pls = &os->children.head; *pls != NULL; pls = &(*pls)->next) {
+
+      if ((*pls)->header.type == lang_input_section_enum && 
+         (*pls)->input_section.section == sec) {
+       is = (lang_input_section_type *) *pls;
+       *pls = (*pls)->next;
+       break;
+      }
+       
+      if ((*pls)->header.type == lang_wild_statement_enum) {
+       lang_statement_union_type **pwls;
+       
+       for (pwls = &(*pls)->wild_statement.children.head;
+            *pwls != NULL;
+            pwls = &(*pwls)->next) {
+
+         if ((*pwls)->header.type == lang_input_section_enum && 
+             (*pwls)->input_section.section == sec) {
+
+             is = (lang_input_section_type *) *pwls;
+             *pwls = (*pwls)->next;
+             break;
+         }
+       }
+       
+       if (is != NULL)
+         break;
+      }
+    }  
+
+    if (is == NULL) {
+      einfo ("%P%F: can't find %s in output section\n",
+            bfd_get_section_name (sec->owner, sec));
+    }
+     
+    /* Now figure out where the section should go.  */
+    switch (i) {
+
+    default: /* to avoid warnings */
+    case XCOFF_SPECIAL_SECTION_TEXT:
+      /* _text */
+      oname = ".text";
+      start = true;
+      break;
+    
+    case XCOFF_SPECIAL_SECTION_ETEXT:
+      /* _etext */
+      oname = ".text";
+      start = false;
+      break;
+
+    case XCOFF_SPECIAL_SECTION_DATA:
+      /* _data */
+      oname = ".data";
+      start = true;
+      break;
+    
+    case XCOFF_SPECIAL_SECTION_EDATA:
+      /* _edata */
+      oname = ".data";
+      start = false;
+      break;
+
+    case XCOFF_SPECIAL_SECTION_END:
+    case XCOFF_SPECIAL_SECTION_END2:
+      /* _end and end */
+      oname = ".bss";
+      start = false;
+      break;
+    }
+
+    os = lang_output_section_find (oname);
+
+    if (start) {
+      is->header.next = os->children.head;
+      os->children.head = (lang_statement_union_type *) is;
+    } else {
+      is->header.next = NULL;
+      lang_statement_append (&os->children,
+                            (lang_statement_union_type *) is,
+                            &is->header.next);
+    }
+  }
+}
+
+static int change_symbol_mode (char *input) 
+{
+  /*
+   * 1 : state changed
+   * 0 : no change
+   */
+
+  char *symbol_mode_string[] = {
+    "# 32",   /* 0x01 */
+    "# 64",   /* 0x02 */
+    "# no32", /* 0x04 */
+    "# no64", /* 0x08 */
+    NULL,
+  };
+  unsigned int bit;
+  char *string;
+
+  for (bit = 0; ; bit++) {
+    string = symbol_mode_string[bit];
+    if (NULL == string)
+      return 0;
+    
+    if (0 == strcmp(input, string)) {
+      symbol_mode = (1 << bit);
+      return 1;
+    }
+  }
+  /* should not be here */
+  return 0;
+}
+
+
+static int is_syscall(char *input)
+{
+  /*
+   * 1 : yes
+   * 0 : ignore
+   * -1 : error, try something else
+   */
+  unsigned int bit;
+  char *string;
+  
+  char *syscall_string[] = {
+    "svc",          /* 0x01 */
+    "svc32",        /* 0x02 */
+    "svc3264",      /* 0x04 */
+    "svc64",        /* 0x08 */
+    "syscall",      /* 0x10 */
+    "syscall32",     /* 0x20 */
+    "syscall3264",   /* 0x40 */
+    "syscall64",     /* 0x80 */
+    NULL
+  };
+
+  for (bit = 0; ;bit++) {
+    
+    string = syscall_string[bit];
+    if (NULL == string) {
+      return -1;
+    }
+
+    if (0 == strcmp(input, string)) {
+      if (1 << bit & ${SYSCALL_MASK}) {
+       return 1;
+      } else {
+       return 0;
+      }
+    }
+  }
+  /* should not be here */
+  return -1;
 }
 
-/* Read an import or export file.  */
+
+/* Read an import or export file.  For an import file, this is called
+   by the before_allocation emulation routine.  For an export file,
+   this is called by the parse_args emulation routine.  */
 
 static void
 gld${EMULATION_NAME}_read_file (filename, import)
@@ -383,7 +882,7 @@ gld${EMULATION_NAME}_read_file (filename, import)
   o = (struct obstack *) xmalloc (sizeof (struct obstack));
   obstack_specify_allocation (o, 0, 0, xmalloc, gld${EMULATION_NAME}_free);
 
-  f = fopen (filename, "r");
+  f = fopen (filename, FOPEN_RT);
   if (f == NULL)
     {
       bfd_set_error (bfd_error_system_call);
@@ -397,6 +896,15 @@ gld${EMULATION_NAME}_read_file (filename, import)
   impmember = NULL;
 
   lineno = 0;
+
+  /* 
+   * default to 32 and 64 bit mode
+   * symbols at top of /lib/syscalls.exp do not have a mode modifier and they
+   * are not repeated, assume 64 bit routines also want to use them.
+   * See the routine change_symbol_mode for more information.
+   */
+  symbol_mode = 0x04;
+
   while ((c = getc (f)) != EOF)
     {
       char *s;
@@ -417,10 +925,11 @@ gld${EMULATION_NAME}_read_file (filename, import)
       s = (char *) obstack_base (o);
       while (isspace ((unsigned char) *s))
        ++s;
-      if (*s == '\0'
-         || *s == '*'
-         || (*s == '#' && s[1] == ' ')
-         || (! import && *s == '#' && s[1] == '!'))
+      if (*s == '\0'  || 
+         *s == '*' ||
+         change_symbol_mode (s) ||
+         (*s == '#' && s[1] == ' ') ||
+         (! import && *s == '#' && s[1] == '!'))
        {
          obstack_free (o, obstack_base (o));
          continue;
@@ -439,7 +948,7 @@ gld${EMULATION_NAME}_read_file (filename, import)
              obstack_free (o, obstack_base (o));
            }
          else if (*s == '(')
-           einfo ("%F%s%d: #! ([member]) is not supported in import files",
+           einfo ("%F%s%d: #! ([member]) is not supported in import files\n",
                   filename, lineno);
          else
            {
@@ -449,7 +958,7 @@ gld${EMULATION_NAME}_read_file (filename, import)
              (void) obstack_finish (o);
              keep = true;
              imppath = s;
-             impfile = NULL;
+             file = NULL;
              while (! isspace ((unsigned char) *s) && *s != '(' && *s != '\0')
                {
                  if (*s == '/')
@@ -499,88 +1008,111 @@ gld${EMULATION_NAME}_read_file (filename, import)
          continue;
        }
 
-      /* This is a symbol to be imported or exported.  */
-      symname = s;
-      syscall = false;
-      address = (bfd_vma) -1;
-
-      while (! isspace ((unsigned char) *s) && *s != '\0')
-       ++s;
-      if (*s != '\0')
-       {
-         char *se;
-
-         *s++ = '\0';
-
-         while (isspace ((unsigned char) *s))
-           ++s;
-
-         se = s;
-         while (! isspace ((unsigned char) *se) && *se != '\0')
-           ++se;
-         if (*se != '\0')
-           {
-             *se++ = '\0';
-             while (isspace ((unsigned char) *se))
-               ++se;
-             if (*se != '\0')
-               einfo ("%s%d: warning: syntax error in import/export file\n",
-                      filename, lineno);
-           }
-
-         if (strcasecmp (s, "svc") == 0
-             || strcasecmp (s, "syscall") == 0)
-           syscall = true;
-         else
-           {
+      if (symbol_mode & ${SYMBOL_MODE_MASK}) { 
+
+       /* This is a symbol to be imported or exported.  */
+       symname = s;
+       syscall = false;
+       address = (bfd_vma) -1;
+
+       while (! isspace ((unsigned char) *s) && *s != '\0')
+         ++s;
+       if (*s != '\0')
+         {
+           char *se;
+           
+           *s++ = '\0';
+
+           while (isspace ((unsigned char) *s))
+             ++s;
+
+           se = s;
+           while (! isspace ((unsigned char) *se) && *se != '\0')
+             ++se;
+           if (*se != '\0')
+             {
+               *se++ = '\0';
+               while (isspace ((unsigned char) *se))
+                 ++se;
+               if (*se != '\0')
+                 einfo ("%s%d: warning: syntax error in import/export file\n",
+                        filename, lineno);
+             }
+
+           if (s != se) {
+             int status;
              char *end;
-
-             address = strtoul (s, &end, 0);
-             if (*end != '\0')
-               einfo ("%s:%d: warning: syntax error in import/export file\n",
-                      filename, lineno);
+                         
+             status = is_syscall(s);
+                         
+             switch (status) {
+             case 1:
+               /* this is a system call */
+               syscall = true;
+               break;
+                                         
+             case 0:
+               /* ignore this system call */
+               break;
+                                         
+             default:
+               /* not a system call, check for address */
+               address = strtoul (s, &end, 0);
+               if (*end != '\0') {
+                 einfo ("%s:%d: warning: syntax error in import/export file\n", filename, lineno);
+                        
+               }
+             }
            }
-       }
-
-      h = bfd_link_hash_lookup (link_info.hash, symname, false, false, true);
-      if (h == NULL || h->type == bfd_link_hash_new)
-       {
-         /* We can just ignore attempts to import an unreferenced
-            symbol.  */
-         if (! import)
-           einfo ("%X%s:%d: attempt to export undefined symbol %s\n",
-                  filename, lineno, symname);
-       }
-      else if (import)
-       {
-         if (! bfd_xcoff_import_symbol (output_bfd, &link_info, h, address,
-                                        imppath, impfile, impmember))
-           einfo ("%X%s:%d: failed to import symbol %s: %E\n",
-                  filename, lineno, symname);
-       }
-      else
-       {
-         if (! bfd_xcoff_export_symbol (output_bfd, &link_info, h, syscall))
-           einfo ("%X%s:%d: failed to export symbol %s: %E\n",
-                  filename, lineno, symname);
-       }
-
+         }
+
+       if (! import)
+         {
+           struct export_symbol_list *n;
+
+           ldlang_add_undef (symname);
+           n = ((struct export_symbol_list *)
+                xmalloc (sizeof (struct export_symbol_list)));
+           n->next = export_symbols;
+           n->name = xstrdup (symname);
+           n->syscall = syscall;
+           export_symbols = n;
+         }
+       else
+         {
+           h = bfd_link_hash_lookup (link_info.hash, symname, false, false,
+                                     true);
+           if (h == NULL || h->type == bfd_link_hash_new)
+             {
+               /* We can just ignore attempts to import an unreferenced
+                  symbol.  */
+             }
+           else
+             {
+               if (! bfd_xcoff_import_symbol (output_bfd, &link_info, h,
+                                              address, imppath, impfile,
+                                              impmember))
+                 einfo ("%X%s:%d: failed to import symbol %s: %E\n",
+                        filename, lineno, symname);
+             }
+         }
+      }
       obstack_free (o, obstack_base (o));
     }
-
+  
   if (obstack_object_size (o) > 0)
     {
-      einfo ("%s:%d: warning: ignoring unterminated last line\n",
-            filename, lineno);
-      obstack_free (o, obstack_base (o));
-    }
+         einfo ("%s:%d: warning: ignoring unterminated last line\n",
+                filename, lineno);
+         obstack_free (o, obstack_base (o));
+       }
 
-  if (! keep)
-    {
-      obstack_free (o, NULL);
-      free (o);
+      if (! keep)
+       {
+         obstack_free (o, NULL);
+         free (o);
+       }
     }
-}
 
 /* This routine saves us from worrying about declaring free.  */
 
@@ -591,6 +1123,76 @@ gld${EMULATION_NAME}_free (p)
   free (p);
 }
 
+/* This is called by the before_allocation routine via
+   lang_for_each_statement.  It looks for relocations and assignments
+   to symbols.  */
+
+static void
+gld${EMULATION_NAME}_find_relocs (s)
+     lang_statement_union_type *s;
+{
+  if (s->header.type == lang_reloc_statement_enum)
+    {
+      lang_reloc_statement_type *rs;
+
+      rs = &s->reloc_statement;
+      if (rs->name == NULL)
+       einfo ("%F%P: only relocations against symbols are permitted\n");
+      if (! bfd_xcoff_link_count_reloc (output_bfd, &link_info, rs->name))
+       einfo ("%F%P: bfd_xcoff_link_count_reloc failed: %E\n");
+    }
+
+  if (s->header.type == lang_assignment_statement_enum)
+    gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
+}
+
+/* Look through an expression for an assignment statement.  */
+
+static void
+gld${EMULATION_NAME}_find_exp_assignment (exp)
+     etree_type *exp;
+{
+  struct bfd_link_hash_entry *h;
+
+  switch (exp->type.node_class)
+    {
+    case etree_provide:
+      h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst,
+                               false, false, false);
+      if (h == NULL)
+       break;
+      /* Fall through.  */
+    case etree_assign:
+      if (strcmp (exp->assign.dst, ".") != 0)
+       {
+         if (! bfd_xcoff_record_link_assignment (output_bfd, &link_info,
+                                                 exp->assign.dst))
+           einfo ("%P%F: failed to record assignment to %s: %E\n",
+                  exp->assign.dst);
+       }
+      gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src);
+      break;
+
+    case etree_binary:
+      gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs);
+      gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs);
+      break;
+
+    case etree_trinary:
+      gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond);
+      gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs);
+      gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs);
+      break;
+
+    case etree_unary:
+      gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child);
+      break;
+
+    default:
+      break;
+    }
+}
+
 static char *
 gld${EMULATION_NAME}_get_script(isfile)
      int *isfile;
@@ -601,7 +1203,7 @@ then
 # Scripts compiled in.
 
 # sed commands to quote an ld script as a C string.
-sc="-f ${srcdir}/emultempl/stringify.sed"
+sc="-f ${srcdir}/emultempl/ostring.sed"
 
 cat >>e${EMULATION_NAME}.c <<EOF
 {                           
@@ -651,7 +1253,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   syslib_default,
   hll_default,
   after_parse_default,
-  after_open_default,
+  gld${EMULATION_NAME}_after_open,
   after_allocation_default,
   set_output_arch_default,
   ldemul_default_target,
@@ -665,5 +1267,9 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   0,   /* place_orphan */
   0,   /* set_symbols */
   gld${EMULATION_NAME}_parse_args,
+  gld${EMULATION_NAME}_unrecognized_file,
+  NULL, /* list_options */
+  NULL, /* recognized_file */
+  NULL, /* find potential_libraries */
 };
 EOF