Back from Intel with Steve
authorDavid Henkel-Wallace <gumby@cygnus>
Thu, 21 Mar 1991 21:29:07 +0000 (21:29 +0000)
committerDavid Henkel-Wallace <gumby@cygnus>
Thu, 21 Mar 1991 21:29:07 +0000 (21:29 +0000)
18 files changed:
binutils/TODO [new file with mode: 0644]
binutils/alloca.c [new file with mode: 0644]
binutils/copy.c [new file with mode: 0644]
binutils/cplus-dem.c [new file with mode: 0644]
binutils/gmalloc.c [new file with mode: 0644]
binutils/m68k-pinsn.c
binutils/ostrip.c [new file with mode: 0755]
binutils/sparc-pinsn.c
binutils/strip.c [new file with mode: 0755]
ld/config.h [new file with mode: 0644]
ld/ld-emul.c
ld/ld-gld.c
ld/ld-gld960.c
ld/ld-lnk960.c
ld/ld.tex [new file with mode: 0755]
ld/ldsym.c
ld/ldsym.h [new file with mode: 0644]
ld/ldwarn.h [new file with mode: 0644]

diff --git a/binutils/TODO b/binutils/TODO
new file mode 100644 (file)
index 0000000..026f86c
--- /dev/null
@@ -0,0 +1,11 @@
+o - merge:
+       copy and strip
+       ar and ranlib
+       nm, size, and objdump
+
+o - make the long options more consistent.
+
+o - make ATT and BSD versions -- perhaps the options should be
+    controlled by an environment variable.
+
+o - Calling +help or +version should exit with a successful status (ie 0)
diff --git a/binutils/alloca.c b/binutils/alloca.c
new file mode 100644 (file)
index 0000000..9639def
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+       alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+       last edit:      86/05/30        rms
+          include config.h, since on VMS it renames some symbols.
+          Use xmalloc instead of malloc.
+
+       This implementation of the PWB library alloca() function,
+       which is used to allocate space off the run-time stack so
+       that it is automatically reclaimed upon procedure exit, 
+       was inspired by discussions with J. Q. Johnson of Cornell.
+
+       It should work under any C implementation that uses an
+       actual procedure stack (as opposed to a linked list of
+       frames).  There are some preprocessor constants that can
+       be defined when compiling for your specific system, for
+       improved efficiency; however, the defaults should be okay.
+
+       The general concept of this implementation is to keep
+       track of all alloca()-allocated blocks, and reclaim any
+       that are found to be deeper in the stack than the current
+       invocation.  This heuristic does not reclaim storage as
+       soon as it becomes invalid, but it will do so eventually.
+
+       As a special case, alloca(0) reclaims storage without
+       allocating any.  It is a good idea to use alloca(0) in
+       your main control loop, etc. to force garbage collection.
+*/
+#ifndef lint
+static char    SCCSid[] = "@(#)alloca.c        1.1";   /* for the "what" utility */
+#endif
+
+#ifdef emacs
+#include "config.h"
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+#ifdef X3J11
+typedef void   *pointer;               /* generic pointer type */
+#else
+typedef char   *pointer;               /* generic pointer type */
+#endif
+
+#define        NULL    0                       /* null pointer constant */
+
+extern void    free();
+extern pointer xmalloc();
+
+/*
+       Define STACK_DIRECTION if you know the direction of stack
+       growth for your system; otherwise it will be automatically
+       deduced at run-time.
+
+       STACK_DIRECTION > 0 => grows toward higher addresses
+       STACK_DIRECTION < 0 => grows toward lower addresses
+       STACK_DIRECTION = 0 => direction of growth unknown
+*/
+
+#ifndef STACK_DIRECTION
+#define        STACK_DIRECTION 0               /* direction unknown */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define        STACK_DIR       STACK_DIRECTION /* known at compile-time */
+
+#else  /* STACK_DIRECTION == 0; need run-time code */
+
+static int     stack_dir;              /* 1 or -1 once known */
+#define        STACK_DIR       stack_dir
+
+static void
+find_stack_direction (/* void */)
+{
+  static char  *addr = NULL;   /* address of first
+                                  `dummy', once known */
+  auto char    dummy;          /* to get stack address */
+
+  if (addr == NULL)
+    {                          /* initial entry */
+      addr = &dummy;
+
+      find_stack_direction (); /* recurse once */
+    }
+  else                         /* second entry */
+    if (&dummy > addr)
+      stack_dir = 1;           /* stack grew upward */
+    else
+      stack_dir = -1;          /* stack grew downward */
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/*
+       An "alloca header" is used to:
+       (a) chain together all alloca()ed blocks;
+       (b) keep track of stack depth.
+
+       It is very important that sizeof(header) agree with malloc()
+       alignment chunk size.  The following default should work okay.
+*/
+
+#ifndef        ALIGN_SIZE
+#define        ALIGN_SIZE      sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];      /* to force sizeof(header) */
+  struct
+    {
+      union hdr *next;         /* for chaining headers */
+      char *deep;              /* for stack depth measure */
+    } h;
+} header;
+
+/*
+       alloca( size ) returns a pointer to at least `size' bytes of
+       storage which will be automatically reclaimed upon exit from
+       the procedure that called alloca().  Originally, this space
+       was supposed to be taken from the current stack frame of the
+       caller, but that method cannot be made to work for some
+       implementations of C, for example under Gould's UTX/32.
+*/
+
+static header *last_alloca_header = NULL; /* -> last alloca header */
+
+pointer
+alloca (size)                  /* returns pointer to storage */
+     unsigned  size;           /* # bytes to allocate */
+{
+  auto char    probe;          /* probes stack depth: */
+  register char        *depth = &probe;
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)          /* unknown growth direction */
+    find_stack_direction ();
+#endif
+
+                               /* Reclaim garbage, defined as all alloca()ed storage that
+                                  was allocated from deeper in the stack than currently. */
+
+  {
+    register header    *hp;    /* traverses linked list */
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if (STACK_DIR > 0 && hp->h.deep > depth
+         || STACK_DIR < 0 && hp->h.deep < depth)
+       {
+         register header       *np = hp->h.next;
+
+         free ((pointer) hp);  /* collect garbage */
+
+         hp = np;              /* -> next header */
+       }
+      else
+       break;                  /* rest are not deeper */
+
+    last_alloca_header = hp;   /* -> last valid storage */
+  }
+
+  if (size == 0)
+    return NULL;               /* no allocation required */
+
+  /* Allocate combined header + user data storage. */
+
+  {
+    register pointer   new = xmalloc (sizeof (header) + size);
+    /* address of header */
+
+    ((header *)new)->h.next = last_alloca_header;
+    ((header *)new)->h.deep = depth;
+
+    last_alloca_header = (header *)new;
+
+    /* User storage begins just after header. */
+
+    return (pointer)((char *)new + sizeof(header));
+  }
+}
+
diff --git a/binutils/copy.c b/binutils/copy.c
new file mode 100644 (file)
index 0000000..601a2b7
--- /dev/null
@@ -0,0 +1,410 @@
+/*** copy.c -- copy object file from input to output, optionally massaging it */
+#include "sysdep.h"
+#include "bfd.h"
+
+asymbol       **sympp;
+char           *input_target = NULL;
+char           *output_target = NULL;
+char           *input_filename = NULL;
+char           *output_filename = NULL;
+
+
+static void     setup_sections();
+static void     copy_sections();
+static boolean  strip;
+static boolean verbose;
+
+/* IMPORTS */
+extern char    *program_name;
+extern char *xmalloc();
+
+static
+void            
+usage()
+{
+    fprintf(stderr,
+    "Usage %s [-S][-s srcfmt] [-d dtfmt] [-b bothfmts] infile [outfile]\n",
+           program_name);
+    exit(1);
+}
+
+
+/* Create a temp file in the same directory as supplied */
+static
+char *
+make_tempname(filename)
+char *filename;
+{
+    static char template[] = "stXXXXXX";
+    char *tmpname;
+    char *      slash = strrchr( filename, '/' );
+    if (slash != (char *)NULL){
+       *slash = 0;
+       tmpname = xmalloc(strlen(filename) + sizeof(template) + 1 );
+       strcpy(tmpname, filename);
+       strcat(tmpname, "/" );
+       strcat(tmpname, template);
+       mktemp(tmpname );
+       *slash = '/';
+    } else {
+       tmpname = xmalloc(sizeof(template));
+       strcpy(tmpname, template);
+       mktemp(tmpname);
+    }
+    return tmpname;
+}
+
+/*
+   All the symbols have been read in and point to their owning input section.
+   They have been relocated to that they are all relative to the base of
+   their owning section. On the way out, all the symbols will be relocated to
+   their new location in the output file, through some complex sums.
+
+*/
+static void
+mangle_sections(ibfd, obfd)
+    bfd            *ibfd;
+    bfd            *obfd;
+{
+    asection       *current = ibfd->sections;
+    for (; current != NULL; current = current->next) {
+       current->output_section = bfd_get_section_by_name(obfd, current->name);
+       current->output_offset = 0;
+    }
+}
+
+static 
+void
+copy_object(ibfd, obfd)
+bfd *ibfd;
+bfd *obfd;
+{
+
+    unsigned int symcount;
+
+
+    if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
+       bfd_fatal(output_filename);
+
+
+    if (verbose)
+       printf("copy from %s(%s) to %s(%s)\n",
+              ibfd->filename, ibfd->xvec->name,
+              obfd->filename, obfd->xvec->name);
+
+    if ((bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false) ||
+       (bfd_set_file_flags(obfd, (bfd_get_file_flags(ibfd) &
+                                  ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS | D_PAGED |
+                                    HAS_LOCALS))) == false) ||
+       bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false)
+       bfd_fatal(bfd_get_filename(ibfd));
+
+    /* Copy architecture of input file to output file */
+    if (!bfd_set_arch_mach(obfd, bfd_get_architecture(ibfd),
+                          bfd_get_machine(ibfd))) {
+       fprintf(stderr, "Output file cannot represent architecture %s\n",
+               bfd_printable_arch_mach(bfd_get_architecture(ibfd),
+                                       bfd_get_machine(ibfd)));
+    }
+    if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
+       {
+           bfd_fatal(ibfd->filename);
+       }
+
+    sympp = (asymbol **) xmalloc(get_symtab_upper_bound(ibfd));
+    symcount = bfd_canonicalize_symtab(ibfd, sympp);
+
+    bfd_set_symtab(obfd, sympp, strip == true ? 0 : symcount);
+    
+    /*
+      bfd mandates that all output sections be created and sizes set before
+      any output is done.  Thus, we traverse all sections twice.
+      */
+    bfd_map_over_sections(ibfd, setup_sections, (void *) obfd);
+    bfd_map_over_sections(ibfd, copy_sections, (void *) obfd);
+    mangle_sections(ibfd, obfd);
+}
+static
+char *
+cat(a,b,c)
+char *a;
+char *b;
+char *c;
+{
+    int size = strlen(a) + strlen(b) + strlen(c);
+    char *r = xmalloc(size+1);
+    strcpy(r,a);
+    strcat(r,b);
+    strcat(r,c);
+    return r;
+}
+
+static void 
+copy_archive(ibfd, obfd)
+bfd *ibfd;
+bfd *obfd;
+{
+    bfd **ptr =&( obfd->archive_head);
+    bfd *this_element;
+    /* Read each archive element in turn from the input, copy the
+       contents to a temp file, and keep the temp file handle */
+    char *dir = cat("./",make_tempname(this_element->filename),"copy-dir");
+
+    /* Make a temp directory to hold the contents */
+    mkdir(dir,0777);
+    obfd->has_armap = ibfd->has_armap;
+    this_element = bfd_openr_next_archived_file(ibfd, NULL);
+    while (this_element != (bfd *)NULL) {
+
+       /* Create an output file for this member */
+       char *output_name = cat(dir, "/",this_element->filename);
+       bfd *output_bfd = bfd_openw(output_name, output_target);
+       
+       if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
+           bfd_fatal(output_filename);
+
+       if (output_bfd == (bfd *)NULL) {
+           bfd_fatal(output_name);
+       }
+       if (bfd_check_format(this_element, bfd_object) == true) {
+           copy_object(this_element, output_bfd);
+       }
+
+       bfd_close(output_bfd);
+       /* Now open the newly output file and attatch to our list */
+       output_bfd = bfd_openr(output_name, output_target);
+       /* Mark it for deletion */
+
+       *ptr = output_bfd;
+
+       ptr =&( output_bfd->next);
+       this_element = bfd_openr_next_archived_file(ibfd, this_element);
+
+    }
+    *ptr = (bfd *)NULL;
+
+    if (!bfd_close(obfd))
+       bfd_fatal(output_filename);
+
+    /* Now delete all the files that we opened 
+      We can't use the names in the obfd list since they may have been
+      trampled by the archive output code
+      */
+    for (this_element = ibfd->archive_head;
+        this_element != (bfd *)NULL;
+        this_element = this_element->next) 
+       {
+       unlink(cat(dir,"/",this_element->filename));
+    }
+    unlink(dir);
+    if (!bfd_close(ibfd))
+       bfd_fatal(input_filename);
+
+}
+
+static
+boolean
+copy_file(input_filename, output_filename)
+    char           *input_filename;
+    char           *output_filename;
+{
+    bfd            *ibfd;
+
+
+    ibfd = bfd_openr(input_filename, input_target);
+    if (ibfd == NULL)
+       bfd_fatal(input_filename);
+
+    if (bfd_check_format(ibfd, bfd_object)) {
+       bfd * obfd = bfd_openw(output_filename, output_target);
+       if (obfd == NULL)
+           bfd_fatal(output_filename);
+
+       copy_object(ibfd, obfd);
+
+       if (!bfd_close(obfd))
+           bfd_fatal(output_filename);
+
+       if (!bfd_close(ibfd))
+           bfd_fatal(input_filename);
+    }
+    else     if (bfd_check_format(ibfd, bfd_archive)) {
+       bfd * obfd = bfd_openw(output_filename, output_target);
+       if (obfd == NULL)
+           bfd_fatal(output_filename);
+
+       copy_archive(ibfd, obfd);
+    }
+}
+
+
+
+/** Actually do the work */
+static void
+setup_sections(ibfd, isection, obfd)
+    bfd            *ibfd;
+    sec_ptr         isection;
+    bfd            *obfd;
+{
+    sec_ptr         osection;
+    char           *err;
+    osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
+    if (osection == NULL) {
+       err = "making";
+       goto loser;
+    }
+
+    if (!bfd_set_section_size(obfd,
+                             osection,
+                             bfd_section_size(ibfd, isection))) {
+       err = "size";
+       goto loser;
+    }
+
+    if (bfd_set_section_vma(obfd,
+                           osection,
+                           bfd_section_vma(ibfd, isection))
+       == false) {
+       err = "vma";
+       goto loser;
+    }                          /* on error */
+
+    if (bfd_set_section_alignment(obfd,
+                                 osection,
+                                 bfd_section_alignment(ibfd, isection))
+       == false) {
+       err = "alignment";
+       goto loser;
+    }                          /* on error */
+
+    if (!bfd_set_section_flags(obfd, osection,
+                              bfd_get_section_flags(ibfd, isection))) {
+       err = "flags";
+       goto loser;
+    }
+
+    /* All went well */
+    return;
+
+loser:
+    fprintf(stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
+           program_name,
+           bfd_get_filename(ibfd), bfd_section_name(ibfd, isection),
+           err, bfd_errmsg(bfd_error));
+    exit(1);
+}                              /* setup_sections() */
+
+static void
+copy_sections(ibfd, isection, obfd)
+    bfd            *ibfd;
+    sec_ptr         isection;
+    bfd            *obfd;
+{
+    static unsigned char *memhunk = NULL;
+    arelent       **relpp;
+    int             relcount;
+    sec_ptr         osection;
+    unsigned long   size;
+    osection = bfd_get_section_by_name(obfd,
+                                      bfd_section_name(ibfd, isection));
+
+    size = bfd_section_size(ibfd, isection);
+
+    if (size == 0)
+       return;
+
+    if (get_reloc_upper_bound(ibfd, isection) != 0) {
+       relpp = (arelent **) xmalloc(get_reloc_upper_bound(ibfd, isection));
+
+       relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, sympp);
+
+       bfd_set_reloc(obfd, osection, relpp, relcount);
+    }
+
+    if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS) {
+       memhunk = (unsigned char *) xmalloc(size);
+       /* now we have enough memory, just do it: */
+       if (!bfd_get_section_contents(ibfd, isection, memhunk, 0, size))
+           bfd_fatal(bfd_get_filename(ibfd));
+
+       if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size))
+           bfd_fatal(bfd_get_filename(obfd));
+    }                          /* only if the section has contents. */
+
+    free(memhunk);
+}
+int
+main(argc, argv)
+    int             argc;
+    char           *argv[];
+{
+    int             i;
+
+
+    program_name = argv[0];
+
+    if (strcmp(program_name,"strip") == 0) {
+       strip = true;
+    }
+
+    for (i = 1; i < argc; i++) 
+       {
+           if (argv[i][0] == '-') {
+               switch (argv[i][1]) {
+           case 'v':
+                   verbose = true;
+                   break;
+           case 'b':
+                   i++;
+                   input_target = output_target = argv[i];
+                   break;
+           case 'S':
+                   strip = true;
+                   break;
+           case 's':
+                   i++;
+                   input_target = argv[i];
+                   break;
+           case 'd':
+                   i++;
+                   output_target = argv[i];
+                   break;
+           default:
+                   usage();
+               }
+           }
+           else {
+               if (input_filename) {
+                   output_filename = argv[i];
+               }
+               else {
+                   input_filename = argv[i];
+               }
+           }
+       }
+
+    if (input_filename == (char *) NULL)
+       usage();
+
+    if (output_target == (char *) NULL)
+       output_target = input_target;
+
+    /* If there is no  destination file then create a temp and rename
+       the result into the input */
+
+    if (output_filename == (char *)NULL) {
+       char *  tmpname = make_tempname(input_filename);
+       if (copy_file(input_filename, tmpname)) {
+           output_filename = input_filename;
+           rename(tmpname, input_filename);
+           return 0;
+       }
+    }
+    else if (copy_file(input_filename, output_filename)) 
+       {
+           return 0;
+       }
+
+
+    return 1;
+}
diff --git a/binutils/cplus-dem.c b/binutils/cplus-dem.c
new file mode 100644 (file)
index 0000000..4cc6496
--- /dev/null
@@ -0,0 +1,933 @@
+/* Demangler for GNU C++ 
+   Copyright (C) 1989 Free Software Foundation, Inc.
+   written by James Clark (jjc@jclark.uucp)
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This is for g++ 1.36.1 (November 6 version). It will probably
+   require changes for any other version.
+
+   Modified for g++ 1.36.2 (November 18 version).  */
+
+/* This file exports one function
+
+   char *cplus_demangle (const char *name)
+   
+   If `name' is a mangled function name produced by g++, then
+   a pointer to a malloced string giving a C++ representation
+   of the name will be returned; otherwise NULL will be returned.
+   It is the caller's responsibility to free the string which
+   is returned.
+
+   For example,
+   
+   cplus_demangle ("_foo__1Ai")
+   
+   returns
+
+   "A::foo(int)"
+
+   This file imports xmalloc and xrealloc, which are like malloc and
+   realloc except that they generate a fatal error if there is no
+   available memory. */
+
+#if 0                          /* Should really be part of BFD */
+#define nounderscore 1         /* define this is names don't start with _ */
+#endif
+#include "sysdep.h"
+
+#include <ctype.h>
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifdef __STDC__
+extern char *cplus_demangle (const char *type);
+#else
+extern char *cplus_demangle ();
+#endif
+
+static char **typevec = 0;
+static int ntypes = 0;
+static int typevec_size = 0;
+
+static struct {
+  const char *in;
+  const char *out;
+} optable[] = {
+  "new", " new",
+  "delete", " delete",
+  "ne", "!=",
+  "eq", "==",
+  "ge", ">=",
+  "gt", ">",
+  "le", "<=",
+  "lt", "<",
+  "plus", "+",
+  "minus", "-",
+  "mult", "*",
+  "convert", "+",      /* unary + */
+  "negate", "-",       /* unary - */
+  "trunc_mod", "%",
+  "trunc_div", "/",
+  "truth_andif", "&&",
+  "truth_orif", "||",
+  "truth_not", "!",
+  "postincrement", "++",
+  "postdecrement", "--",
+  "bit_ior", "|",
+  "bit_xor", "^",
+  "bit_and", "&",
+  "bit_not", "~",
+  "call", "()",
+  "cond", "?:",
+  "alshift", "<<",
+  "arshift", ">>",
+  "component", "->",
+  "indirect", "*",
+  "method_call", "->()",
+  "addr", "&",         /* unary & */
+  "array", "[]",
+  "nop", "",                   /* for operator= */
+};
+
+/* Beware: these aren't '\0' terminated. */
+
+typedef struct {
+  char *b;                     /* pointer to start of string */
+  char *p;                     /* pointer after last character */
+  char *e;                     /* pointer after end of allocated space */
+} string;
+
+#ifdef __STDC__
+static void string_need (string *s, int n);
+static void string_delete (string *s);
+static void string_init (string *s);
+static void string_clear (string *s);
+static int string_empty (string *s);
+static void string_append (string *p, const char *s);
+static void string_appends (string *p, string *s);
+static void string_appendn (string *p, const char *s, int n);
+static void string_prepend (string *p, const char *s);
+#if 0
+static void string_prepends (string *p, string *s);
+#endif
+static void string_prependn (string *p, const char *s, int n);
+static int get_count (const char **type, int *count);
+static int do_args (const char **type, string *decl);
+static int do_type (const char **type, string *result);
+static int do_arg (const char **type, string *result);
+static int do_args (const char **type, string *decl);
+static void munge_function_name (string *name);
+#else
+static void string_need ();
+static void string_delete ();
+static void string_init ();
+static void string_clear ();
+static int string_empty ();
+static void string_append ();
+static void string_appends ();
+static void string_appendn ();
+static void string_prepend ();
+static void string_prepends ();
+static void string_prependn ();
+static int get_count ();
+static int do_args ();
+static int do_type ();
+static int do_arg ();
+static int do_args ();
+static void munge_function_name ();
+#endif
+
+char *
+cplus_demangle (type)
+     const char *type;
+{
+  string decl;
+  int n;
+  int success = 0;
+  int constructor = 0;
+  int const_flag = 0;
+  int i;
+  const char *p, *premangle;
+
+  if (type == NULL || *type == '\0')
+    return NULL;
+#ifndef nounderscore
+  if (*type++ != '_')
+    return NULL;
+#endif
+  p = type;
+  while (*p != '\0' && !(*p == '_' && p[1] == '_'))
+    p++;
+  if (*p == '\0')
+    {
+      /* destructor */
+      if (type[0] == '_' && type[1] == '$' && type[2] == '_')
+       {
+         unsigned int l = (strlen (type) - 3)*2 + 3 + 2 + 1;
+         char *tem = (char *) xmalloc (l);
+         strcpy (tem, type + 3);
+         strcat (tem, "::~");
+         strcat (tem, type + 3);
+         strcat (tem, "()");
+         return tem;
+       }
+      /* static data member */
+      if (*type != '_' && (p = (char *) strchr (type, '$')) != NULL)
+       {
+         int n = strlen (type) + 2;
+         char *tem = (char *) xmalloc (n);
+         memcpy (tem, type, p - type);
+         strcpy (tem + (p - type), "::");
+         strcpy (tem + (p - type) + 2, p + 1);
+         return tem;
+       }
+      /* virtual table */
+      if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
+       {
+         int n = strlen (type + 4) + 14 + 1;
+         char *tem = (char *) xmalloc (n);
+         strcpy (tem, type + 4);
+         strcat (tem, " virtual table");
+         return tem;
+       }
+      return NULL;
+    }
+
+  string_init (&decl);
+
+  if (p == type)
+    {
+      if (!isdigit (p[2]))
+       {
+         string_delete (&decl);
+         return NULL;
+       }
+      constructor = 1;
+    }
+  else
+    {
+      string_appendn (&decl, type, p - type);
+      munge_function_name (&decl);
+    }
+  p += 2;
+
+  premangle = p;
+  switch (*p)
+    {
+    case 'C':
+      /* a const member function */
+      if (!isdigit (p[1]))
+       {
+         string_delete (&decl);
+         return NULL;
+       }
+      p += 1;
+      const_flag = 1;
+      /* fall through */
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      n = 0;
+      do
+       {
+         n *= 10;
+         n += *p - '0';
+         p += 1;
+       }
+      while (isdigit (*p));
+      if (strlen (p) < n)
+       {
+         string_delete (&decl);
+         return NULL;
+       }
+      if (constructor)
+       {
+         string_appendn (&decl, p, n);
+         string_append (&decl, "::");
+         string_appendn (&decl, p, n);
+       }
+      else
+       {
+         string_prepend (&decl, "::");
+         string_prependn (&decl, p, n);
+       }
+#ifndef LONGERNAMES
+      p = premangle;
+#else
+      p += n;
+#endif
+      success = do_args (&p, &decl);
+      if (const_flag)
+       string_append (&decl, " const");
+      break;
+    case 'F':
+      p += 1;
+      success = do_args (&p, &decl);
+      break;
+    }
+
+  for (i = 0; i < ntypes; i++)
+    if (typevec[i] != NULL)
+      free (typevec[i]);
+  ntypes = 0;
+  if (typevec != NULL)
+    {
+      free ((char *)typevec);
+      typevec = NULL;
+      typevec_size = 0;
+    }
+
+  if (success)
+    {
+      string_appendn (&decl, "", 1);
+      return decl.b;
+    }
+  else
+    {
+      string_delete (&decl);
+      return NULL;
+    }
+}
+
+static int
+get_count (type, count)
+     const char **type;
+     int *count;
+{
+  if (!isdigit (**type))
+    return 0;
+  *count = **type - '0';
+  *type += 1;
+  /* see flush_repeats in cplus-method.c */
+  if (isdigit (**type))
+    {
+      const char *p = *type;
+      int n = *count;
+      do 
+       {
+         n *= 10;
+         n += *p - '0';
+         p += 1;
+       } 
+      while (isdigit (*p));
+      if (*p == '_')
+       {
+         *type = p + 1;
+         *count = n;
+       }
+    }
+  return 1;
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+do_type (type, result)
+     const char **type;
+     string *result;
+{
+  int n;
+  int done;
+  int non_empty = 0;
+  int success;
+  string decl;
+  const char *remembered_type;
+
+  string_init (&decl);
+  string_init (result);
+
+  done = 0;
+  success = 1;
+  while (success && !done)
+    {
+      int member;
+      switch (**type)
+       {
+       case 'P':
+         *type += 1;
+         string_prepend (&decl, "*");
+         break;
+
+       case 'R':
+         *type += 1;
+         string_prepend (&decl, "&");
+         break;
+
+       case 'T':
+         *type += 1;
+         if (!get_count (type, &n) || n >= ntypes)
+           success = 0;
+         else
+           {
+             remembered_type = typevec[n];
+             type = &remembered_type;
+           }
+         break;
+
+       case 'F':
+         *type += 1;
+         if (!string_empty (&decl) && decl.b[0] == '*')
+           {
+             string_prepend (&decl, "(");
+             string_append (&decl, ")");
+           }
+         if (!do_args (type, &decl) || **type != '_')
+           success = 0;
+         else
+           *type += 1;
+         break;
+
+       case 'M':
+       case 'O':
+         {
+           int constp = 0;
+           int volatilep = 0;
+
+           member = **type == 'M';
+           *type += 1;
+           if (!isdigit (**type))
+             {
+               success = 0;
+               break;
+             }
+           n = 0;
+           do
+             {
+               n *= 10;
+               n += **type - '0';
+               *type += 1;
+             } 
+           while (isdigit (**type));
+           if (strlen (*type) < n)
+             {
+               success = 0;
+               break;
+             }
+           string_append (&decl, ")");
+           string_prepend (&decl, "::");
+           string_prependn (&decl, *type, n);
+           string_prepend (&decl, "(");
+           *type += n;
+           if (member)
+             {
+               if (**type == 'C')
+                 {
+                   *type += 1;
+                   constp = 1;
+                 }
+               if (**type == 'V')
+                 {
+                   *type += 1;
+                   volatilep = 1;
+                 }
+               if (*(*type)++ != 'F')
+                 {
+                   success = 0;
+                   break;
+                 }
+             }
+           if ((member && !do_args (type, &decl)) || **type != '_')
+             {
+               success = 0;
+               break;
+             }
+           *type += 1;
+           if (constp)
+             {
+               if (non_empty)
+                 string_append (&decl, " ");
+               else
+                 non_empty = 1;
+               string_append (&decl, "const");
+             }
+           if (volatilep)
+             {
+               if (non_empty)
+                 string_append (&decl, " ");
+               else
+                 non_empty = 1;
+               string_append (&decl, "volatilep");
+             }
+           break;
+         }
+
+       case 'C':
+         if ((*type)[1] == 'P')
+           {
+             *type += 1;
+             if (!string_empty (&decl))
+               string_prepend (&decl, " ");
+             string_prepend (&decl, "const");
+             break;
+           }
+
+         /* fall through */
+       default:
+         done = 1;
+         break;
+       }
+    }
+
+  done = 0;
+  non_empty = 0;
+  while (success && !done)
+    {
+      switch (**type)
+       {
+       case 'C':
+         *type += 1;
+         if (non_empty)
+           string_append (result, " ");
+         else
+           non_empty = 1;
+         string_append (result, "const");
+         break;
+       case 'U':
+         *type += 1;
+         if (non_empty)
+           string_append (result, " ");
+         else
+           non_empty = 1;
+         string_append (result, "unsigned");
+         break;
+       case 'V':
+         *type += 1;
+         if (non_empty)
+           string_append (result, " ");
+         else
+           non_empty = 1;
+         string_append (result, "volatile");
+         break;
+       default:
+         done = 1;
+         break;
+       }
+    }
+
+  if (success)
+    switch (**type)
+      {
+      case '\0':
+      case '_':
+       break;
+      case 'v':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "void");
+       break;
+      case 'l':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "long");
+       break;
+      case 'i':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "int");
+       break;
+      case 's':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "short");
+       break;
+      case 'c':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "char");
+       break;
+      case 'r':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "long double");
+       break;
+      case 'd':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "double");
+       break;
+      case 'f':
+       *type += 1;
+       if (non_empty)
+         string_append (result, " ");
+       string_append (result, "float");
+       break;
+      case 'G':
+       *type += 1;
+       if (!isdigit (**type))
+         {
+           success = 0;
+           break;
+         }
+       /* fall through */
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+       n = 0;
+       do
+         {
+           n *= 10;
+           n += **type - '0';
+           *type += 1;
+         }
+       while (isdigit (**type));
+       if (strlen (*type) < n)
+         {
+           success = 0;
+           break;
+         }
+       if (non_empty)
+         string_append (result, " ");
+       string_appendn (result, *type, n);
+       *type += n;
+       break;
+      default:
+       success = 0;
+       break;
+      }
+
+  if (success)
+    {
+      if (!string_empty (&decl))
+       {
+         string_append (result, " ");
+         string_appends (result, &decl);
+       }
+      string_delete (&decl);
+      return 1;
+    }
+  else
+    {
+      string_delete (&decl);
+      string_delete (result);
+      return 0;
+    }
+}
+
+/* `result' will be initialised in do_type; it will be freed on failure */
+
+static int
+do_arg (type, result)
+     const char **type;
+     string *result;
+{
+  char *tem;
+  int len;
+  const char *start;
+  const char *end;
+
+  start = *type;
+  if (!do_type (type, result))
+    return 0;
+  end = *type;
+  if (ntypes >= typevec_size)
+    {
+      if (typevec_size == 0)
+       {
+         typevec_size = 3;
+         typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
+       }
+      else
+       {
+         typevec_size *= 2;
+         typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
+       }
+    }
+  len = end - start;
+  tem = (char *) xmalloc (len + 1);
+  memcpy (tem, start, len);
+  tem[len] = '\0';
+  typevec[ntypes++] = tem;
+  return 1;
+}
+
+/* `decl' must be already initialised, usually non-empty;
+   it won't be freed on failure */
+
+static int
+do_args (type, decl)
+     const char **type;
+     string *decl;
+{
+  string arg;
+  int need_comma = 0;
+  int dont_want_first;
+
+#ifndef LONGERNAMES
+  dont_want_first = 1;
+#else
+  dont_want_first = 0;
+#endif
+
+  string_append (decl, "(");
+
+  while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
+    {
+      if (**type == 'N')
+       {
+         int r;
+         int t;
+         *type += 1;
+         if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
+           return 0;
+         while (--r >= 0)
+           {
+             const char *tem = typevec[t];
+             if (need_comma)
+               string_append (decl, ", ");
+             if (!do_arg (&tem, &arg))
+               return 0;
+             string_appends (decl, &arg);
+             string_delete (&arg);
+             need_comma = 1;
+           }
+       }
+      else
+       {
+         if (need_comma)
+           string_append (decl, ", ");
+         if (!do_arg (type, &arg))
+           return 0;
+         if (dont_want_first)
+           dont_want_first = 0;
+         else
+           {
+             string_appends (decl, &arg);
+             need_comma = 1;
+           }
+         string_delete (&arg);
+       }
+    }
+
+  if (**type == 'v')
+    *type += 1;
+  else if (**type == 'e')
+    {
+      *type += 1;
+      if (need_comma)
+       string_append (decl, ",");
+      string_append (decl, "...");
+    }
+
+  string_append (decl, ")");
+  return 1;
+}
+
+static void
+munge_function_name (name)
+     string *name;
+{
+  if (!string_empty (name) && name->p - name->b >= 3 
+      && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
+    {
+           unsigned int i;
+      /* see if it's an assignment expression */
+      if (name->p - name->b >= 10 /* op$assign_ */
+         && memcmp (name->b + 3, "assign_", 7) == 0)
+       {
+         for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+           {
+             int len = name->p - name->b - 10;
+             if (strlen (optable[i].in) == len
+                 && memcmp (optable[i].in, name->b + 10, len) == 0)
+               {
+                 string_clear (name);
+                 string_append (name, "operator");
+                 string_append (name, optable[i].out);
+                 string_append (name, "=");
+                 return;
+               }
+           }
+       }
+      else
+       {
+         for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+           {
+             int len = name->p - name->b - 3;
+             if (strlen (optable[i].in) == len 
+                 && memcmp (optable[i].in, name->b + 3, len) == 0)
+               {
+                 string_clear (name);
+                 string_append (name, "operator");
+                 string_append (name, optable[i].out);
+                 return;
+               }
+           }
+       }
+      return;
+    }
+  else if (!string_empty (name) && name->p - name->b >= 5
+          && memcmp (name->b, "type$", 5) == 0)
+    {
+      /* type conversion operator */
+      string type;
+      const char *tem = name->b + 5;
+      if (do_type (&tem, &type))
+       {
+         string_clear (name);
+         string_append (name, "operator ");
+         string_appends (name, &type);
+         string_delete (&type);
+         return;
+       }
+    }
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (s, n)
+     string *s;
+     int n;
+{
+  if (s->b == NULL)
+    {
+      if (n < 32)
+       n = 32;
+      s->p = s->b = (char *) xmalloc (n);
+      s->e = s->b + n;
+    }
+  else if (s->e - s->p < n)
+    {
+      int tem = s->p - s->b;
+      n += tem;
+      n *= 2;
+      s->b = (char *) xrealloc (s->b, n);
+      s->p = s->b + tem;
+      s->e = s->b + n;
+    }
+}
+
+static void
+string_delete (s)
+     string *s;
+{
+  if (s->b != NULL)
+    {
+      free (s->b);
+      s->b = s->e = s->p = NULL;
+    }
+}
+
+static void
+string_init (s)
+     string *s;
+{
+  s->b = s->p = s->e = NULL;
+}
+
+static void 
+string_clear (s)
+     string *s;
+{
+  s->p = s->b;
+}
+
+static int
+string_empty (s)
+     string *s;
+{
+  return s->b == s->p;
+}
+
+static void
+string_append (p, s)
+     string *p;
+     const char *s;
+{
+  int n;
+  if (s == NULL || *s == '\0')
+    return;
+  n = strlen (s);
+  string_need (p, n);
+  memcpy (p->p, s, n);
+  p->p += n;
+}
+
+static void
+string_appends (p, s)
+     string *p, *s;
+{
+  int n;
+  if (s->b == s->p)
+    return;
+  n = s->p - s->b;
+  string_need (p, n);
+  memcpy (p->p, s->b, n);
+  p->p += n;
+}
+
+static void
+string_appendn (p, s, n)
+     string *p;
+     const char *s;
+     int n;
+{
+  if (n == 0)
+    return;
+  string_need (p, n);
+  memcpy (p->p, s, n);
+  p->p += n;
+}
+
+static void
+string_prepend (p, s)
+     string *p;
+     const char *s;
+{
+  if (s == NULL || *s == '\0')
+    return;
+  string_prependn (p, s, strlen (s));
+}
+
+static void
+string_prependn (p, s, n)
+     string *p;
+     const char *s;
+     int n;
+{
+  char *q;
+
+  if (n == 0)
+    return;
+  string_need (p, n);
+  for (q = p->p - 1; q >= p->b; q--)
+    q[n] = q[0];
+  memcpy (p->b, s, n);
+  p->p += n;
+}
diff --git a/binutils/gmalloc.c b/binutils/gmalloc.c
new file mode 100644 (file)
index 0000000..0468551
--- /dev/null
@@ -0,0 +1,1116 @@
+
+/* gmalloc.c - THIS FILE IS AUTOMAGICALLY GENERATED SO DON'T EDIT IT. */
+
+/* Single-file skeleton for GNU malloc.
+   Copyright 1989 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#define __ONEFILE
+
+/* DO NOT DELETE THIS LINE -- ansidecl.h INSERTED HERE. */
+/* Copyright (C) 1989 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* ANSI and traditional C compatibility macros
+
+   ANSI C is assumed if __STDC__ is #defined.
+
+       Macros
+               PTR             - Generic pointer type
+               LONG_DOUBLE     - `long double' type
+               CONST           - `const' keyword
+               VOLATILE        - `volatile' keyword
+               SIGNED          - `signed' keyword
+               PTRCONST        - Generic const pointer (void *const)
+
+       EXFUN(name, prototype)          - declare external function NAME
+                                         with prototype PROTOTYPE
+       DEFUN(name, arglist, args)      - define function NAME with
+                                         args ARGLIST of types in ARGS
+       DEFUN_VOID(name)                - define function NAME with no args
+       AND                             - argument separator for ARGS
+       NOARGS                          - null arglist
+       DOTS                            - `...' in args
+
+    For example:
+       extern int EXFUN(printf, (CONST char *format DOTS));
+       int DEFUN(fprintf, (stream, format),
+                 FILE *stream AND CONST char *format DOTS) { ... }
+       void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef        _ANSIDECL_H
+
+#define        _ANSIDECL_H     1
+
+
+/* Every source file includes this file,
+   so they will all get the switch for lint.  */
+/* LINTLIBRARY */
+
+
+#ifdef __STDC__
+
+#define        PTR             void *
+#define        PTRCONST        void *CONST
+#define        LONG_DOUBLE     long double
+
+#define        AND             ,
+#define        NOARGS          void
+#define        CONST           const
+#define        VOLATILE        volatile
+#define        SIGNED          signed
+#define        DOTS            , ...
+
+#define        EXFUN(name, proto)              name proto
+#define        DEFUN(name, arglist, args)      name(args)
+#define        DEFUN_VOID(name)                name(NOARGS)
+
+#else  /* Not ANSI C.  */
+
+#define        PTR             char *
+#define        PTRCONST        PTR
+#define        LONG_DOUBLE     double
+
+#define        AND             ;
+#define        NOARGS
+#define        CONST
+#define        VOLATILE
+#define        SIGNED
+#define        DOTS
+
+#define        EXFUN(name, proto)              name()
+#define        DEFUN(name, arglist, args)      name arglist args;
+#define        DEFUN_VOID(name)                name()
+
+#endif /* ANSI C.  */
+
+
+#endif /* ansidecl.h   */
+
+#ifdef __STDC__
+#include <limits.h>
+#else
+/* DO NOT DELETE THIS LINE -- limits.h INSERTED HERE. */
+/* Number of bits in a `char'.  */
+#define CHAR_BIT 8
+
+/* No multibyte characters supported yet.  */
+#define MB_LEN_MAX 1
+
+/* Minimum and maximum values a `signed char' can hold.  */
+#define SCHAR_MIN -128
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold.  (Minimum is 0).  */
+#define UCHAR_MAX 255U
+
+/* Minimum and maximum values a `char' can hold.  */
+#ifdef __CHAR_UNSIGNED__
+#define CHAR_MIN 0
+#define CHAR_MAX 255U
+#else
+#define CHAR_MIN -128
+#define CHAR_MAX 127
+#endif
+
+/* Minimum and maximum values a `signed short int' can hold.  */
+#define SHRT_MIN -32768
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short int' can hold.  (Minimum is 0).  */
+#define USHRT_MAX 65535U
+
+/* Minimum and maximum values a `signed int' can hold.  */
+#define INT_MIN -2147483648
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold.  (Minimum is 0).  */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long int' can hold.
+   (Same as `int').  */
+#define LONG_MIN (-LONG_MAX-1)
+#define LONG_MAX 2147483647
+
+/* Maximum value an `unsigned long int' can hold.  (Minimum is 0).  */
+#define ULONG_MAX 4294967295U
+#endif
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+/* DO NOT DELETE THIS LINE -- stddef.h INSERTED HERE. */
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+/* Signed type of difference of two pointers.  */
+
+typedef long ptrdiff_t;
+
+/* Unsigned type of `sizeof' something.  */
+
+#ifndef _SIZE_T        /* in case <sys/types.h> has defined it. */
+#define _SIZE_T
+typedef unsigned long size_t;
+#endif /* _SIZE_T */
+
+/* A null pointer constant.  */
+
+#undef NULL            /* in case <stdio.h> has defined it. */
+#define NULL 0
+
+/* Offset of member MEMBER in a struct of type TYPE.  */
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* _STDDEF_H */
+#endif
+
+/* DO NOT DELETE THIS LINE -- stdlib.h INSERTED HERE. */
+/* Fake stdlib.h supplying the stuff needed by malloc. */
+
+#ifndef __ONEFILE
+#include <stddef.h>
+#endif
+
+extern void EXFUN(abort, (void));
+extern void EXFUN(free, (PTR));
+extern PTR EXFUN(malloc, (size_t));
+extern PTR EXFUN(realloc, (PTR, size_t));
+
+/* DO NOT DELETE THIS LINE -- string.h INSERTED HERE. */
+/* Fake string.h supplying stuff used by malloc. */
+#ifndef __ONEFILE
+#include <stddef.h>
+#endif
+
+extern PTR EXFUN(memcpy, (PTR, PTR, size_t));
+extern PTR EXFUN(memset, (PTR, int, size_t));
+#define memmove memcpy
+
+#define _MALLOC_INTERNAL
+/* DO NOT DELETE THIS LINE -- malloc.h INSERTED HERE. */
+/* Declarations for `malloc' and friends.
+   Copyright 1990 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H      1
+
+#ifndef __ONEFILE
+#define        __need_NULL
+#define        __need_size_t
+#define __need_ptrdiff_t
+#include <stddef.h>
+#endif
+
+#ifdef _MALLOC_INTERNAL
+
+#ifndef __ONEFILE
+#include <limits.h>
+#endif
+
+/* The allocator divides the heap into blocks of fixed size; large
+   requests receive one or more whole blocks, and small requests
+   receive a fragment of a block.  Fragment sizes are powers of two,
+   and all fragments of a block are the same size.  When all the
+   fragments in a block have been freed, the block itself is freed.  */
+#define INT_BIT                (CHAR_BIT * sizeof(int))
+#define BLOCKLOG       (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE      (1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+   (not an absolute limit).  */
+#define HEAP           (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+   memory before they will be returned to the system.  */
+#define FINAL_FREE_BLOCKS      8
+
+/* Where to start searching the free list when looking for new memory.
+   The two possible values are 0 and _heapindex.  Starting at 0 seems
+   to reduce total memory usage, while starting at _heapindex seems to
+   run faster.  */
+#define MALLOC_SEARCH_START    _heapindex
+
+/* Data structure giving per-block information.  */
+typedef union
+  {
+    /* Heap information for a busy block.  */
+    struct
+      {
+       /* Zero for a large block, or positive giving the
+          logarithm to the base two of the fragment size.  */
+       int type;
+       union
+         {
+           struct
+             {
+               size_t nfree;   /* Free fragments in a fragmented block.  */
+               size_t first;   /* First free fragment of the block.  */
+             } frag;
+           /* Size (in blocks) of a large cluster.  */
+           size_t size;
+         } info;
+      } busy;
+    /* Heap information for a free block (that may be the first of
+       a free cluster).  */
+    struct
+      {
+       size_t size;            /* Size (in blocks) of a free cluster.  */
+       size_t next;            /* Index of next free cluster.  */
+       size_t prev;            /* Index of previous free cluster.  */
+      } free;
+  } malloc_info;
+
+/* Pointer to first block of the heap.  */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information.  */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa.  */
+#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table.  */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments.  */
+struct list
+  {
+    struct list *next;
+    struct list *prev;
+  };
+
+/* Free list headers for each fragment size.  */
+extern struct list _fraghead[];
+
+/* Instrumentation.  */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of free() used in morecore(). */
+extern void EXFUN(__free, (PTR __ptr));
+
+#endif  /* _MALLOC_INTERNAL.  */
+
+/* Underlying allocation function; successive calls should
+   return contiguous pieces of memory.  */
+extern PTR EXFUN((*__morecore), (ptrdiff_t __size));
+
+/* Default value of previous.  */
+extern PTR EXFUN(__default_morecore, (ptrdiff_t __size));
+
+/* Flag whether malloc has been called.  */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions.  */
+extern void EXFUN((*__free_hook), (PTR __ptr));
+extern PTR EXFUN((*__malloc_hook), (size_t __size));
+extern PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size));
+
+/* Activate a standard collection of debugging hooks.  */
+extern void EXFUN(mcheck, (void EXFUN((*func), (void))));
+
+/* Statistics available to the user.  */
+struct mstats
+  {
+    size_t bytes_total;                /* Total size of the heap. */
+    size_t chunks_used;                /* Chunks allocated by the user. */
+    size_t bytes_used;         /* Byte total of user-allocated chunks. */
+    size_t chunks_free;                /* Chunks in the free list. */
+    size_t bytes_free;         /* Byte total of chunks in the free list. */
+  };
+
+/* Pick up the current statistics. */
+extern struct mstats EXFUN(mstats, (NOARGS));
+
+#endif /* malloc.h  */
+
+/* DO NOT DELETE THIS LINE -- free.c INSERTED HERE. */
+/* Free a block of memory allocated by `malloc'.
+   Copyright 1990 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+/* Debugging hook for free.  */
+void EXFUN((*__free_hook), (PTR __ptr));
+
+/* Return memory to the heap.  Like free() but don't call a __free_hook
+   if there is one.  */
+void
+DEFUN(__free, (ptr), PTR ptr)
+{
+  int type;
+  size_t block, blocks;
+  register size_t i;
+  struct list *prev, *next;
+
+  block = BLOCK(ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Get as many statistics as early as we can.  */
+      --_chunks_used;
+      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+      /* Find the free cluster previous to this one in the free list.
+        Start searching at the last block referenced; this may benefit
+        programs with locality of allocation.  */
+      i = _heapindex;
+      if (i > block)
+       while (i > block)
+         i = _heapinfo[i].free.prev;
+      else
+       {
+         do
+           i = _heapinfo[i].free.next;
+         while (i > 0 && i < block);
+         i = _heapinfo[i].free.prev;
+       }
+
+      /* Determine how to link this block into the free list.  */
+      if (block == i + _heapinfo[i].free.size)
+       {
+         /* Coalesce this block with its predecessor.  */
+         _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+         block = i;
+       }
+      else
+       {
+         /* Really link this block back into the free list.  */
+         _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+         _heapinfo[block].free.next = _heapinfo[i].free.next;
+         _heapinfo[block].free.prev = i;
+         _heapinfo[i].free.next = block;
+         _heapinfo[_heapinfo[block].free.next].free.prev = block;
+         ++_chunks_free;
+       }
+
+      /* Now that the block is linked in, see if we can coalesce it
+        with its successor (by deleting its successor from the list
+        and adding in its size).  */
+      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+       {
+         _heapinfo[block].free.size
+           += _heapinfo[_heapinfo[block].free.next].free.size;
+         _heapinfo[block].free.next
+           = _heapinfo[_heapinfo[block].free.next].free.next;
+         _heapinfo[_heapinfo[block].free.next].free.prev = block;
+         --_chunks_free;
+       }
+
+      /* Now see if we can return stuff to the system.  */
+      blocks = _heapinfo[block].free.size;
+      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+         && (*__morecore)(0) == ADDRESS(block + blocks))
+       {
+         register size_t bytes = blocks * BLOCKSIZE;
+         _heaplimit -= blocks;
+         (*__morecore)(- bytes);
+         _heapinfo[_heapinfo[block].free.prev].free.next
+           = _heapinfo[block].free.next;
+         _heapinfo[_heapinfo[block].free.next].free.prev
+           = _heapinfo[block].free.prev;
+         block = _heapinfo[block].free.prev;
+         --_chunks_free;
+         _bytes_free -= bytes;
+       }
+
+      /* Set the next search to begin at this block.  */
+      _heapindex = block;
+      break;
+
+    default:
+      /* Do some of the statistics.  */
+      --_chunks_used;
+      _bytes_used -= 1 << type;
+      ++_chunks_free;
+      _bytes_free += 1 << type;
+
+      /* Get the address of the first free fragment in this block.  */
+      prev = (struct list *) ((char *) ADDRESS(block) +
+                             (_heapinfo[block].busy.info.frag.first << type));
+
+      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+       {
+         /* If all fragments of this block are free, remove them
+            from the fragment list and free the whole block.  */
+         next = prev;
+         for (i = 1; i < BLOCKSIZE >> type; ++i)
+           next = next->next;
+         prev->prev->next = next;
+         if (next != NULL)
+           next->prev = prev->prev;
+         _heapinfo[block].busy.type = 0;
+         _heapinfo[block].busy.info.size = 1;
+
+         /* Keep the statistics accurate.  */
+         ++_chunks_used;
+         _bytes_used += BLOCKSIZE;
+         _chunks_free -= BLOCKSIZE >> type;
+         _bytes_free -= BLOCKSIZE;
+
+         free(ADDRESS(block));
+       }
+      else if (_heapinfo[block].busy.info.frag.nfree != 0)
+       {
+         /* If some fragments of this block are free, link this
+            fragment into the fragment list after the first free
+            fragment of this block. */
+         next = (struct list *) ptr;
+         next->next = prev->next;
+         next->prev = prev;
+         prev->next = next;
+         if (next->next != NULL)
+           next->next->prev = next;
+         ++_heapinfo[block].busy.info.frag.nfree;
+       }
+      else
+       {
+         /* No fragments of this block are free, so link this
+            fragment into the fragment list and announce that
+            it is the first free fragment of this block. */
+         prev = (struct list *) ptr;
+         _heapinfo[block].busy.info.frag.nfree = 1;
+         _heapinfo[block].busy.info.frag.first = (unsigned int)
+           (((char *) ptr - (char *) NULL) % BLOCKSIZE >> type);
+         prev->next = _fraghead[type].next;
+         prev->prev = &_fraghead[type];
+         prev->prev->next = prev;
+         if (prev->next != NULL)
+           prev->next->prev = prev;
+       }
+      break;
+    }
+}
+
+/* Return memory to the heap.  */
+void
+DEFUN(free, (ptr), PTR ptr)
+{
+  if (ptr == NULL)
+    return;
+
+  if (__free_hook != NULL)
+    (*__free_hook)(ptr);
+  else
+    __free (ptr);
+}
+
+/* DO NOT DELETE THIS LINE -- malloc.c INSERTED HERE. */
+/* Memory allocator `malloc'.
+   Copyright 1990 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+/* How to really get more memory.  */
+PTR EXFUN((*__morecore), (ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'.  */
+PTR EXFUN((*__malloc_hook), (size_t __size));
+
+/* Pointer to the base of the first block.  */
+char *_heapbase;
+
+/* Block information table.  Allocated with align/__free (not malloc/free).  */
+malloc_info *_heapinfo;
+
+/* Number of info entries.  */
+static size_t heapsize;
+
+/* Search index in the info table.  */
+size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+size_t _heaplimit;
+
+/* Free lists for each fragment size.  */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation.  */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced?  */
+int __malloc_initialized;
+
+/* Aligned allocation.  */
+static PTR
+DEFUN(align, (size), size_t size)
+{
+  PTR result;
+  unsigned int adj;
+
+  result = (*__morecore)(size);
+  adj = (unsigned int) ((char *) result - (char *) NULL) % BLOCKSIZE;
+  if (adj != 0)
+    {
+      adj = BLOCKSIZE - adj;
+      (void) (*__morecore)(adj);
+      result = (char *) result + adj;
+    }
+  return result;
+}
+
+/* Set everything up and remember that we have.  */
+static int
+DEFUN_VOID(initialize)
+{
+  heapsize = HEAP / BLOCKSIZE;
+  _heapinfo = (malloc_info *) align(heapsize * sizeof(malloc_info));
+  if (_heapinfo == NULL)
+    return 0;
+  memset(_heapinfo, 0, heapsize * sizeof(malloc_info));
+  _heapinfo[0].free.size = 0;
+  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+  _heapindex = 0;
+  _heapbase = (char *) _heapinfo;
+  __malloc_initialized = 1;
+  return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+   growing the heap info table as necessary. */
+static PTR
+DEFUN(morecore, (size), size_t size)
+{
+  PTR result;
+  malloc_info *newinfo, *oldinfo;
+  size_t newsize;
+
+  result = align(size);
+  if (result == NULL)
+    return NULL;
+
+  /* Check if we need to grow the info table.  */
+  if (BLOCK((char *) result + size) > heapsize)
+    {
+      newsize = heapsize;
+      while (BLOCK((char *) result + size) > newsize)
+       newsize *= 2;
+      newinfo = (malloc_info *) align(newsize * sizeof(malloc_info));
+      if (newinfo == NULL)
+       {
+         (*__morecore)(- size);
+         return NULL;
+       }
+      memset(newinfo, 0, newsize * sizeof(malloc_info));
+      memcpy(newinfo, _heapinfo, heapsize * sizeof(malloc_info));
+      oldinfo = _heapinfo;
+      newinfo[BLOCK(oldinfo)].busy.type = 0;
+      newinfo[BLOCK(oldinfo)].busy.info.size
+       = BLOCKIFY(heapsize * sizeof(malloc_info));
+      _heapinfo = newinfo;
+      __free(oldinfo);
+      heapsize = newsize;
+    }
+
+  _heaplimit = BLOCK((char *) result + size);
+  return result;
+}
+
+/* Allocate memory from the heap.  */
+PTR
+DEFUN(malloc, (size), size_t size)
+{
+  PTR result;
+  size_t block, blocks, lastblocks, start;
+  register size_t i;
+  struct list *next;
+
+  if (size == 0)
+    return NULL;
+
+  if (__malloc_hook != NULL)
+    return (*__malloc_hook)(size);
+
+  if (!__malloc_initialized)
+    if (!initialize())
+      return NULL;
+
+  if (size < sizeof(struct list))
+    size = sizeof(struct list);
+
+  /* Determine the allocation policy based on the request size.  */
+  if (size <= BLOCKSIZE / 2)
+    {
+      /* Small allocation to receive a fragment of a block.
+        Determine the logarithm to base two of the fragment size. */
+      register size_t log = 1;
+      --size;
+      while ((size /= 2) != 0)
+       ++log;
+
+      /* Look in the fragment lists for a
+        free fragment of the desired size. */
+      next = _fraghead[log].next;
+      if (next != NULL)
+       {
+         /* There are free fragments of this size.
+            Pop a fragment out of the fragment list and return it.
+            Update the block's nfree and first counters. */
+         result = (PTR) next;
+         next->prev->next = next->next;
+         if (next->next != NULL)
+           next->next->prev = next->prev;
+         block = BLOCK(result);
+         if (--_heapinfo[block].busy.info.frag.nfree != 0)
+           _heapinfo[block].busy.info.frag.first = (unsigned int)
+             (((char *) next->next - (char *) NULL) % BLOCKSIZE) >> log;
+
+         /* Update the statistics.  */
+         ++_chunks_used;
+         _bytes_used += 1 << log;
+         --_chunks_free;
+         _bytes_free -= 1 << log;
+       }
+      else
+       {
+         /* No free fragments of the desired size, so get a new block
+            and break it into fragments, returning the first.  */
+         result = malloc(BLOCKSIZE);
+         if (result == NULL)
+           return NULL;
+
+         /* Link all fragments but the first into the free list.  */
+         for (i = 1; i < BLOCKSIZE >> log; ++i)
+           {
+             next = (struct list *) ((char *) result + (i << log));
+             next->next = _fraghead[log].next;
+             next->prev = &_fraghead[log];
+             next->prev->next = next;
+             if (next->next != NULL)
+               next->next->prev = next;
+           }
+
+         /* Initialize the nfree and first counters for this block.  */
+         block = BLOCK(result);
+         _heapinfo[block].busy.type = log;
+         _heapinfo[block].busy.info.frag.nfree = i - 1;
+         _heapinfo[block].busy.info.frag.first = i - 1;
+
+         _chunks_free += (BLOCKSIZE >> log) - 1;
+         _bytes_free += BLOCKSIZE - (1 << log);
+       }
+    }
+  else
+    {
+      /* Large allocation to receive one or more blocks.
+        Search the free list in a circle starting at the last place visited.
+        If we loop completely around without finding a large enough
+        space we will have to get more memory from the system.  */
+      blocks = BLOCKIFY(size);
+      start = block = MALLOC_SEARCH_START;
+      while (_heapinfo[block].free.size < blocks)
+       {
+         block = _heapinfo[block].free.next;
+         if (block == start)
+           {
+             /* Need to get more from the system.  Check to see if
+                the new core will be contiguous with the final free
+                block; if so we don't need to get as much.  */
+             block = _heapinfo[0].free.prev;
+             lastblocks = _heapinfo[block].free.size;
+             if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+                 (*__morecore)(0) == ADDRESS(block + lastblocks) &&
+                 (morecore((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+               {
+                 _heapinfo[block].free.size = blocks;
+                 _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+                 continue;
+               }
+             result = morecore(blocks * BLOCKSIZE);
+             if (result == NULL)
+               return NULL;
+             block = BLOCK(result);
+             _heapinfo[block].busy.type = 0;
+             _heapinfo[block].busy.info.size = blocks;
+             ++_chunks_used;
+             _bytes_used += blocks * BLOCKSIZE;
+             return result;
+           }
+       }
+
+      /* At this point we have found a suitable free list entry.
+        Figure out how to remove what we need from the list. */
+      result = ADDRESS(block);
+      if (_heapinfo[block].free.size > blocks)
+       {
+         /* The block we found has a bit left over,
+            so relink the tail end back into the free list. */
+         _heapinfo[block + blocks].free.size
+           = _heapinfo[block].free.size - blocks;
+         _heapinfo[block + blocks].free.next
+           = _heapinfo[block].free.next;
+         _heapinfo[block + blocks].free.prev
+           = _heapinfo[block].free.prev;
+         _heapinfo[_heapinfo[block].free.prev].free.next
+           = _heapinfo[_heapinfo[block].free.next].free.prev
+             = _heapindex = block + blocks;
+       }
+      else
+       {
+         /* The block exactly matches our requirements,
+            so just remove it from the list. */
+         _heapinfo[_heapinfo[block].free.next].free.prev
+           = _heapinfo[block].free.prev;
+         _heapinfo[_heapinfo[block].free.prev].free.next
+           = _heapindex = _heapinfo[block].free.next;
+         --_chunks_free;
+       }
+
+      _heapinfo[block].busy.type = 0;
+      _heapinfo[block].busy.info.size = blocks;
+      ++_chunks_used;
+      _bytes_used += blocks * BLOCKSIZE;
+      _bytes_free -= blocks * BLOCKSIZE;
+    }
+
+  return result;
+}
+
+/* DO NOT DELETE THIS LINE -- realloc.c INSERTED HERE. */
+/* Change the size of a block allocated by `malloc'.
+   Copyright 1990 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc.  */
+PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+   to the (possibly moved) region.  This is optimized for speed;
+   some benchmarks seem to indicate that greater compactness is
+   achieved by unconditionally allocating and copying to a
+   new region.  This module has incestuous knowledge of the
+   internals of both free and malloc. */
+PTR
+DEFUN(realloc, (ptr, size), PTR ptr AND size_t size)
+{
+  PTR result;
+  int type;
+  size_t block, blocks, oldlimit;
+
+  if (size == 0)
+    {
+      free(ptr);
+      return NULL;
+    }
+  else if (ptr == NULL)
+    return malloc(size);
+
+  if (__realloc_hook != NULL)
+    return (*__realloc_hook)(ptr, size);
+
+  block = BLOCK(ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Maybe reallocate a large block to a small fragment.  */
+      if (size <= BLOCKSIZE / 2)
+       {
+         result = malloc(size);
+         if (result != NULL)
+           {
+             memcpy(result, ptr, size);
+             free(ptr);
+             return result;
+           }
+       }
+
+      /* The new size is a large allocation as well;
+        see if we can hold it in place. */
+      blocks = BLOCKIFY(size);
+      if (blocks < _heapinfo[block].busy.info.size)
+       {
+         /* The new size is smaller; return
+            excess memory to the free list. */
+         _heapinfo[block + blocks].busy.type = 0;
+         _heapinfo[block + blocks].busy.info.size
+           = _heapinfo[block].busy.info.size - blocks;
+         _heapinfo[block].busy.info.size = blocks;
+         free(ADDRESS(block + blocks));
+         result = ptr;
+       }
+      else if (blocks == _heapinfo[block].busy.info.size)
+       /* No size change necessary.  */
+       result = ptr;
+      else
+       {
+         /* Won't fit, so allocate a new region that will.
+            Free the old region first in case there is sufficient
+            adjacent free space to grow without moving. */
+         blocks = _heapinfo[block].busy.info.size;
+         /* Prevent free from actually returning memory to the system.  */
+         oldlimit = _heaplimit;
+         _heaplimit = 0;
+         free(ptr);
+         _heaplimit = oldlimit;
+         result = malloc(size);
+         if (result == NULL)
+           {
+             (void) malloc(blocks * BLOCKSIZE);
+             return NULL;
+           }
+         if (ptr != result)
+           memmove(result, ptr, blocks * BLOCKSIZE);
+       }
+      break;
+
+    default:
+      /* Old size is a fragment; type is logarithm
+        to base two of the fragment size.  */
+      if (size > 1 << (type - 1) && size <= 1 << type)
+       /* The new size is the same kind of fragment.  */
+       result = ptr;
+      else
+       {
+         /* The new size is different; allocate a new space,
+            and copy the lesser of the new size and the old. */
+         result = malloc(size);
+         if (result == NULL)
+           return NULL;
+         memcpy(result, ptr, MIN(size, 1 << type));
+         free(ptr);
+       }
+      break;
+    }
+
+  return result;
+}
+
+/* DO NOT DELETE THIS LINE -- unix.c INSERTED HERE. */
+/* unix.c - get more memory with a UNIX system call.
+   Copyright 1990 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+extern PTR EXFUN(sbrk, (ptrdiff_t size));
+
+PTR
+DEFUN(__default_morecore, (size), ptrdiff_t size)
+{
+  PTR result;
+
+  result = sbrk(size);
+  if (result == (PTR) -1)
+    return NULL;
+  return result;
+}
+
+#define __getpagesize getpagesize
+/* DO NOT DELETE THIS LINE -- valloc.c INSERTED HERE. */
+/* Allocate memory on a page boundary.
+   Copyright 1990 Free Software Foundation
+                 Written May 1989 by Mike Haertel.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stdlib.h>
+#endif /* __ONEFILE */
+
+extern size_t EXFUN(__getpagesize, (NOARGS));
+
+static size_t pagesize;
+
+PTR
+DEFUN(valloc, (size), size_t size)
+{
+  PTR result;
+  unsigned int adj;
+
+  if (pagesize == 0)
+    pagesize = __getpagesize();
+
+  result = malloc(size + pagesize);
+  if (result == NULL)
+    return NULL;
+  adj = (unsigned int) ((char *) result - (char *) NULL) % pagesize;
+  if (adj != 0)
+    result = (char *) result + pagesize - adj;
+  return result;
+}
index 284f335..b84a869 100644 (file)
@@ -20,9 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* $Id$
    $Log$
-   Revision 1.1  1991/03/21 21:26:45  gumby
-   Initial revision
+   Revision 1.1.1.1  1991/03/21 21:26:46  gumby
+   Back from Intel with Steve
 
+ * Revision 1.1  1991/03/21  21:26:45  gumby
+ * Initial revision
+ *
  * Revision 1.1  1991/03/13  00:34:06  chrisb
  * Initial revision
  *
diff --git a/binutils/ostrip.c b/binutils/ostrip.c
new file mode 100755 (executable)
index 0000000..6ba318c
--- /dev/null
@@ -0,0 +1,418 @@
+/* strip certain symbols from a rel file.
+   Copyright (C) 1986, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "sysdep.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "getopt.h"
+#include "bfd.h"
+
+enum strip_action {
+  strip_undef,
+  strip_all,                   /* strip all symbols */
+  strip_debug,                 /* strip all debugger symbols */
+};
+
+/* Which symbols to remove. */
+enum strip_action strip_symbols;
+
+enum locals_action {
+  locals_undef,
+  locals_start_L,              /* discard locals starting with L */
+  locals_all,                  /* discard all locals */
+};
+
+/* Which local symbols to remove. */
+enum locals_action discard_locals;
+
+/* The name this program was run with. */
+char *program_name;
+
+struct option long_options[] = {
+  {"strip-all", 0, 0, 's'},
+  {"strip-debug", 0, 0, 'S'},
+  {"discard-all", 0, 0, 'x'},
+  {"discard-locals", 0, 0, 'X'},
+  {0, 0, 0, 0},
+};
+
+static char *target = NULL;
+
+static int fatal_error;
+
+extern char *malloc();
+extern char *mktemp();
+extern char *realloc();
+extern char *strcpy();
+extern int exit();
+extern int fprintf();
+extern int free();
+extern int getpid();
+extern int kill();
+extern int perror();
+extern int sprintf();
+extern int unlink();
+
+#ifdef __STDC__
+static int strip_bfd(bfd *ibfd, bfd *obfd);
+static int strip_file(char *filetostrip);
+static void usage(void);
+#else
+static int strip_bfd();
+static int strip_file();
+static void usage();
+#endif /* __STDC__ */
+static void copy_sections ();
+static void setup_sections ();
+
+int main(argc, argv)
+char **argv;
+int argc;
+{
+       int ind;
+       int c;
+       program_name = argv[0];
+       
+       strip_symbols = strip_undef;    /* default is to strip everything.  */
+       discard_locals = locals_undef;
+       
+       while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
+               switch (c) {
+               case 0:
+                       break;
+               case 's':
+                       strip_symbols = strip_all;
+                       break;
+               case 'g':
+               case 'S':
+                       strip_symbols = strip_debug;
+                       break;
+               case 'T':
+                       target = optarg;
+                       break;
+               case 'x':
+                       discard_locals = locals_all;
+                       break;
+               case 'X':
+                       discard_locals = locals_start_L;
+                       break;
+               default:
+                       usage ();
+               } /* switch on option */
+       } /* for each option */
+       
+       if (strip_symbols == strip_undef && discard_locals == locals_undef) {
+               strip_symbols = strip_all;
+       } /* Default is to strip all symbols.  */
+       
+       
+       if (argc == optind) {
+               return(strip_file("a.out"));
+       } else {
+               int retval = 0;
+
+               for ( ; optind < argc; ++optind) {
+                       retval &= strip_file(argv[optind]);
+               } /* for each file to strip */
+
+               return(retval);
+       } /* if no arguments given */
+
+} /* main() */
+
+static int delayed_signal;
+
+void delay_signal(signo)
+int signo;
+{
+       delayed_signal = signo;
+       signal(signo, delay_signal);
+} /* delay_signal() */
+
+static int sigint_handled = 0;
+static int sighup_handled = 0;
+static int sigterm_handled = 0;
+
+void handle_sigs() {
+       /* Effectively defer handling of asynchronous kill signals.  */
+       delayed_signal = 0;
+       
+       if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
+               sigint_handled = 1;
+               signal(SIGINT, delay_signal);
+       } /* if not ignored */
+       
+       if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
+               sighup_handled = 1;
+               signal(SIGHUP, delay_signal);
+       } /* if not ignored */
+       
+       if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
+               sigterm_handled = 1;
+               signal(SIGTERM, delay_signal);
+       } /* if not ignored */
+       
+       return;
+} /* handle_sigs() */
+
+void unhandle_sigs() {
+       /* Effectively undefer handling.  */
+       if (sigint_handled)
+           signal (SIGINT, SIG_DFL);
+       if (sighup_handled)
+           signal (SIGHUP, SIG_DFL);
+       if (sigterm_handled)
+           signal (SIGTERM, SIG_DFL);
+       
+       /* Handle any signal that came in while they were deferred.  */
+       if (delayed_signal)
+           kill (getpid (), delayed_signal);
+       
+       return;
+} /* unhandle_sigs() */
+
+static int strip_file(filetostrip)
+char *filetostrip;
+{
+       bfd *ibfd;
+       bfd *obfd;
+       char tmpfilename[] = "stXXXXXX";
+
+       if ((ibfd = bfd_openr(filetostrip, (char *)NULL)) == NULL) {
+               bfd_perror(filetostrip);
+               return(1);
+       } /* on error opening input */
+       
+       obfd = bfd_openw(mktemp(tmpfilename),
+                        target? target: bfd_get_target (ibfd));
+       if (obfd == NULL) {
+               bfd_perror(tmpfilename);
+
+               if (bfd_close(ibfd) == false) {
+                       bfd_perror(bfd_get_filename(ibfd));
+               } /* on close error */
+
+               return(1);
+       } /* on error opening output */
+
+       handle_sigs();
+
+       if (bfd_check_format(ibfd, bfd_object) != false) {
+               if (bfd_set_format(obfd, bfd_get_format(ibfd)) != false) {
+                       if (!strip_bfd(ibfd, obfd)) {
+                               /* success */
+
+                               if (bfd_close(ibfd) == false) {
+                                       bfd_perror(bfd_get_filename(ibfd));
+                               } /* on close error */
+
+                               if (bfd_close(obfd) == false) {
+                                       bfd_perror(bfd_get_filename(obfd));
+                               } /* on close error */
+
+                               rename(tmpfilename, filetostrip);
+                               unhandle_sigs();
+                               return(0);
+                       } /* strip_bfd prints it's own failing messages */
+               } else {
+                       bfd_perror(filetostrip);
+               } /* can't set format */
+       } else {
+               /* not an object file */
+               (void) fprintf(stderr, "File %s has format 0x%x that will not be stripped.\n",
+                              filetostrip, (unsigned) bfd_get_format(ibfd));
+       } /* if anything fails along the way */
+       
+
+       if (bfd_close(ibfd) == false) {
+               bfd_perror(bfd_get_filename(ibfd));
+       } /* on close error */
+
+       if (bfd_close(obfd) == false) {
+               bfd_perror(bfd_get_filename(obfd));
+       } /* on close error */
+       
+       if (unlink(tmpfilename)) {
+               perror(tmpfilename);
+       } /* on error */
+       
+       unhandle_sigs();
+
+       return(1);
+} /* strip_file() */
+
+
+boolean
+bfd_set_start_address (abfd, new_address)
+     bfd *abfd;
+     bfd_vma new_address;
+{
+  bfd_get_start_address (abfd) = new_address;
+  return true;
+}
+
+
+
+static int
+strip_bfd(ibfd, obfd)
+       bfd *ibfd;
+       bfd *obfd;
+{
+       if (bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false
+           || bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd) & ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS)) == false
+           || bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false) {
+               bfd_perror(bfd_get_filename(ibfd));
+               return(1);
+       } /* on error setting file attributes */
+
+      /* bfd mandates that all output sections be created and sizes set before
+        any output is done.  Thus, we traverse all sections twice.  */
+
+       fatal_error = 0;
+       bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
+       if (!fatal_error)
+               bfd_map_over_sections (ibfd, copy_sections,  (void *)obfd);
+       return fatal_error;
+}
+
+static void
+setup_sections(ibfd, isection, obfd)
+bfd *ibfd;
+sec_ptr isection;
+bfd *obfd;
+{
+       sec_ptr osection;
+       char *err;
+
+       do {
+           err = "making";
+           osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
+           if (osection == NULL)
+               break;
+           err = "size";
+           if (!bfd_set_section_size(obfd, osection, 
+                bfd_section_size(ibfd, isection)))
+               break;
+           err = "vma";
+           if (!bfd_set_section_vma(obfd, osection,
+                bfd_section_vma(ibfd, isection)))
+               break;
+           err = "alignment";
+           if (!bfd_set_section_alignment(obfd, osection,
+                bfd_section_alignment(ibfd, isection)))
+               break;
+           err = "flags";
+           if (!bfd_set_section_flags(obfd, osection,
+                bfd_get_section_flags(ibfd, isection)))
+               break;
+           return;
+       } while (0);
+
+       (void) fprintf(stderr, "file \"%s\", section \"%s\": error in %s: ",
+                      bfd_get_filename(ibfd),
+                      bfd_section_name(ibfd, isection),
+                      err);
+
+       bfd_perror("");
+       fatal_error = 1;
+}
+
+static void
+copy_sections(ibfd, isection, obfd)
+bfd *ibfd;
+sec_ptr isection;
+bfd *obfd;
+{
+       static char *memhunk = NULL;
+       static unsigned memhunksize = 0;
+
+       sec_ptr osection;
+       unsigned long size;
+       flagword iflg;
+       char *temp;
+
+       osection = bfd_get_section_by_name (obfd,
+                                           bfd_section_name(ibfd, isection));
+
+       size = bfd_section_size(ibfd, isection);
+       iflg = bfd_get_section_flags(ibfd, isection);
+
+       /* either:
+          we don't need any memory because there's nothing in this section,
+          we had no memory so we got some,
+          we had some memory but not enough so we got more,
+          or we fail to allocat. */
+
+       if (size == 0)
+               return;
+
+       if (memhunk == NULL) {
+               memhunk = malloc (size);
+               memhunksize = size;
+       }
+
+       if (size > memhunksize) {
+               temp = realloc (memhunk, size);
+               memhunksize = size;
+               if (!temp)      /* If realloc failed, blow away our mem */
+                       free (memhunk);
+               memhunk = temp;
+       }
+
+       if (memhunk == NULL) {
+               /* failed to allocate or reallocate */
+               /* FIXME, we should just copy in pieces. */
+               (void) fprintf(stderr,
+          "Could not allocate %lu bytes in which to copy section.\n", size);
+               return;
+       }
+
+       /* now we have enough memory */
+       
+       if (!bfd_get_section_contents(ibfd, isection, memhunk, 0, size)) {
+               bfd_perror(bfd_get_filename(ibfd));
+               fatal_error = 1;
+               return;
+       }
+       if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size)) {
+               bfd_perror(bfd_get_filename(obfd));
+               fatal_error = 1;
+               return;
+       }
+}
+
+void
+usage ()
+{
+  fprintf (stderr, "\
+Usage: %s [-gsxSX] [+strip-all] [+strip-debug] [+discard-all]\n\
+       [+discard-locals] file...\n", program_name);
+  exit (1);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of strip.c */
index 550722b..041cade 100644 (file)
@@ -20,9 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* $Id$
    $Log$
-   Revision 1.1  1991/03/21 21:26:55  gumby
-   Initial revision
+   Revision 1.1.1.1  1991/03/21 21:26:56  gumby
+   Back from Intel with Steve
 
+ * Revision 1.1  1991/03/21  21:26:55  gumby
+ * Initial revision
+ *
  * Revision 1.1  1991/03/13  00:34:40  chrisb
  * Initial revision
  *
diff --git a/binutils/strip.c b/binutils/strip.c
new file mode 100755 (executable)
index 0000000..cd0f3af
--- /dev/null
@@ -0,0 +1,364 @@
+/*** strip.c -- strip certain symbols from a rel file.
+   Copyright (C) 1986, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* BUGS: When there's not enough memory, this should do the copy
+   in pieces rather than just fail as it does now */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "getopt.h"
+
+
+
+#include <signal.h>
+
+/* Various program options */
+
+int show_version = 0;
+
+/* Which symbols to remove. */
+enum strip_action {
+  strip_undef,
+  strip_all,                   /* strip all symbols */
+  strip_debug,                 /* strip all debugger symbols */
+} strip_symbols;
+
+/* Which local symbols to remove. */
+enum {
+  locals_undef,
+  locals_start_L,              /* discard locals starting with L */
+  locals_all,                  /* discard all locals */
+} discard_locals;
+
+extern char *mktemp();
+
+/* IMPORTS */
+extern char *program_version;
+extern char *program_name;
+extern char *target;
+extern char *xmalloc();
+
+PROTO(static boolean, strip_file, (char *filetostrip));
+PROTO(static void, copy_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
+PROTO(static void, setup_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
+\f
+/** main, etc */
+
+static void
+usage ()
+{
+  fprintf (stderr, "strip %s\nUsage: %s [-gsxSX] files ...\n",
+          program_version, program_name);
+  exit (1);
+}
+
+struct option long_options[] = {{"strip-all", 0, 0, 's'},
+                               {"strip-debug", 0, 0, 'S'},
+                               {"discard-all", 0, 0, 'x'},
+                               {"discard-locals", 0, 0, 'X'},
+                               {0, 0, 0, 0}
+                               };
+
+int
+main (argc, argv)
+     char **argv;
+     int argc;
+{
+  int ind;
+  int c;
+  program_name = argv[0];
+       
+  strip_symbols = strip_undef; /* default is to strip everything.  */
+  discard_locals = locals_undef;
+       
+  while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
+    switch (c) {
+    case 0:
+      break;
+    case 's':
+      strip_symbols = strip_all;
+      break;
+    case 'g':
+    case 'S':
+      strip_symbols = strip_debug;
+      break;
+    case 'T':
+      target = optarg;
+      break;
+    case 'x':
+      discard_locals = locals_all;
+      break;
+    case 'X':
+      discard_locals = locals_start_L;
+      break;
+    default:
+      usage ();
+    }
+  }
+
+  /* Default is to strip all symbols: */
+  if (strip_symbols == strip_undef && discard_locals == locals_undef) {
+    strip_symbols = strip_all;
+  }
+
+  /* OK, all options now parsed.  If no filename specified, do a.out. */
+  if (optind == argc) return !strip_file ("a.out");
+  
+  /* We were given several filenames to do: */
+  while (optind < argc)
+    if (!strip_file (argv[optind++])) return 1;
+
+  return 0;
+}
+\f
+/** Hack signals */
+
+/* Why does strip need to do this, and anyway, if it does shouldn't this be
+   handled by bfd? */
+
+static int delayed_signal;
+
+static int sigint_handled = 0;
+static int sighup_handled = 0;
+static int sigterm_handled = 0;
+
+void
+delay_signal (signo)
+     int signo;
+{
+  delayed_signal = signo;
+  signal (signo, delay_signal);
+}
+
+/* Effectively defer handling of asynchronous kill signals.  */
+void
+handle_sigs ()                 /* puff puff */
+{
+  delayed_signal = 0;
+       
+  if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
+    sigint_handled = 1;
+    signal (SIGINT, delay_signal);
+  }
+       
+  if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
+    sighup_handled = 1;
+    signal (SIGHUP, delay_signal);
+  }
+       
+  if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
+    sigterm_handled = 1;
+    signal (SIGTERM, delay_signal);
+  }
+       
+  return;
+}
+
+/* Effectively undefer handling.  */
+void
+unhandle_sigs ()               /* put them down */
+{
+  if (sigint_handled) signal (SIGINT, SIG_DFL);
+
+  if (sighup_handled) signal (SIGHUP, SIG_DFL);
+
+  if (sigterm_handled) signal (SIGTERM, SIG_DFL);
+       
+  /* Handle any signal that came in while they were deferred.  */
+  if (delayed_signal)
+    kill (getpid (), delayed_signal);
+       
+  return;
+}
+\f
+
+static boolean
+strip_file (filetostrip)
+     char *filetostrip;
+{
+  static char template[] = "stXXXXXX";
+  char *slash;
+  char *tmpname;
+  bfd *ibfd;
+  bfd *obfd;
+
+  ibfd = bfd_openr (filetostrip, target);
+
+  if (ibfd == NULL) bfd_fatal (filetostrip);
+
+  handle_sigs ();              /* light up */
+
+  if (!bfd_check_format (ibfd, bfd_object)) {
+    fprintf (stderr, "Can't strip %s file %s.\n",
+            bfd_format_string (bfd_get_format (ibfd)), filetostrip);
+    exit (1);
+  }
+
+  slash = strrchr( filetostrip, '/' );
+  if ( slash ){
+    *slash = 0;
+    tmpname = xmalloc( strlen(filetostrip) + sizeof(template) + 1 );
+    strcpy( tmpname, filetostrip );
+    strcat( tmpname, "/" );
+    strcat( tmpname, template );
+    mktemp( tmpname );
+    *slash = '/';
+  } else {
+    tmpname = xmalloc( sizeof(template) );
+    strcpy( tmpname, template );
+    mktemp( tmpname );
+  }
+
+  obfd = bfd_openw (mktemp(tmpname), (target ? target : bfd_get_target (ibfd)));
+  if (obfd == NULL) bfd_fatal (tmpname);
+
+  if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
+    bfd_fatal (tmpname);
+
+
+  if ((bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false) ||
+      (bfd_set_file_flags (obfd, (bfd_get_file_flags (ibfd) &
+                                 ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS |
+                                   HAS_LOCALS))) == false) ||
+      bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false)
+    bfd_fatal (bfd_get_filename (ibfd));
+
+   /* Copy architecture of input file to output file */
+   if (!bfd_set_arch_mach (obfd, bfd_get_architecture (ibfd),
+                              bfd_get_machine (ibfd))) {
+     fprintf(stderr, "Output file cannot represent architecture %s",
+       bfd_printable_arch_mach (bfd_get_architecture(ibfd),
+                                bfd_get_machine (ibfd)));
+   }
+
+  /* bfd mandates that all output sections be created and sizes set before
+     any output is done.  Thus, we traverse all sections twice.  */
+  bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
+  bfd_map_over_sections (ibfd, copy_sections, (void *)obfd);
+
+  if (!bfd_close (obfd)) bfd_fatal (filetostrip);
+  if (!bfd_close (ibfd)) bfd_fatal (filetostrip);
+
+  rename(tmpname, filetostrip);
+  free(tmpname);
+
+  unhandle_sigs();
+
+  return true;
+}
+\f
+/** Actually do the work */
+static void
+setup_sections (ibfd, isection, obfd)
+     bfd *ibfd;
+     sec_ptr isection;
+     bfd *obfd;
+{
+  sec_ptr osection;
+  char *err;
+
+  osection = bfd_make_section (obfd, bfd_section_name (ibfd, isection));
+  if (osection == NULL) {
+      err = "making";
+      goto loser;
+    }
+
+  if (!bfd_set_section_size(obfd, osection, bfd_section_size(ibfd, isection))) {
+     err = "size";
+     goto loser;
+  }
+
+  if (!bfd_set_section_vma (obfd, osection, bfd_section_vma (ibfd, isection))) {
+     err = "vma";
+     goto loser;
+  }
+
+  if (bfd_set_section_alignment (obfd, osection,
+                            bfd_section_alignment (ibfd, isection))
+      != true) {
+         err = "alignment";
+         goto loser;
+  } /* on error, I presume. */
+
+  if (!bfd_set_section_flags (obfd, osection,
+                             bfd_get_section_flags (ibfd, isection))) {
+     err = "flags";
+     goto loser;
+  }
+
+  /* All went well */
+  return;
+  
+ loser:
+  fprintf (stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
+          program_name,
+          bfd_get_filename (ibfd), bfd_section_name (ibfd, isection),
+          err, bfd_errmsg (bfd_error));
+  exit (1);
+}
+
+static void
+copy_sections (ibfd, isection, obfd)
+     bfd *ibfd;
+     sec_ptr isection;
+     bfd *obfd;
+{
+  static unsigned char *memhunk = NULL;
+  static unsigned memhunksize = 0;
+
+  sec_ptr osection;
+  unsigned long size;
+  flagword iflg;
+  unsigned char *temp;
+
+  osection = bfd_get_section_by_name (obfd, bfd_section_name (ibfd, isection));
+
+  size = bfd_section_size (ibfd, isection);
+  iflg = bfd_get_section_flags (ibfd, isection);
+
+  /* either:
+     we don't need any memory because there's nothing in this section,
+     we had no memory so we got some,
+     we had some memory but not enough so we got more,
+     or we fail to allocat. */
+
+  if (size == 0)
+     return;
+
+  if ((iflg & SEC_HAS_CONTENTS) == 0)
+      return;
+
+  if (memhunk == NULL) {
+     memhunk = (unsigned char *) xmalloc (size);
+     memhunksize = size;
+  }
+
+  if (size > memhunksize) {
+     temp = (unsigned char *) xrealloc ((char *) memhunk, size);
+     memhunksize = size;
+     memhunk = temp;
+  }
+
+  /* now we have enough memory, just do it: */
+  if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
+     bfd_fatal (bfd_get_filename (ibfd));
+
+  if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
+     bfd_fatal (bfd_get_filename (obfd));
+}
diff --git a/ld/config.h b/ld/config.h
new file mode 100644 (file)
index 0000000..756956c
--- /dev/null
@@ -0,0 +1,40 @@
+/* config.h -
+
+   Copyright (C) 1991 Free Software Foundation, Inc.
+
+   This file is part of GLD, the Gnu Linker.
+
+   GLD is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   GLD is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GLD; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Look in this environment name for the linker to pretend to be */
+#define EMULATION_ENVIRON "LDEMULATION"
+/* If in there look for the strings: */
+#define GLD_EMULATION_NAME "gld"
+#define GLD960_EMULATION_NAME "gld960"
+#define LNK960_EMULATION_NAME "lnk960"
+/* Otherwise default to this emulation */
+#define DEFAULT_EMULATION GLD960_EMULATION_NAME
+
+
+/* Look in this variable for a target format */
+#define TARGET_ENVIRON "GNUTARGET"
+/* If not there then choose this */
+#define GLD_TARGET "a.out-generic-big"
+#define LNK960_TARGET "coff-Intel-big"
+#define GLD960_TARGET "b.out.big"
+
+
+
+
index 7eb23d4..c644a7c 100755 (executable)
@@ -22,9 +22,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    $Id$ 
 
    $Log$
-   Revision 1.1  1991/03/21 21:28:19  gumby
-   Initial revision
+   Revision 1.1.1.1  1991/03/21 21:28:20  gumby
+   Back from Intel with Steve
 
+ * Revision 1.1  1991/03/21  21:28:19  gumby
+ * Initial revision
+ *
  * Revision 1.1  1991/03/13  00:48:09  chrisb
  * Initial revision
  *
index 4c3df1a..34d7fd6 100755 (executable)
@@ -20,8 +20,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  *  $Id$ 
  *
  *  $Log$
- *  Revision 1.1  1991/03/21 21:28:24  gumby
- *  Initial revision
+ *  Revision 1.1.1.1  1991/03/21 21:28:25  gumby
+ *  Back from Intel with Steve
+ *
+ * Revision 1.1  1991/03/21  21:28:24  gumby
+ * Initial revision
  *
  * Revision 1.2  1991/03/15  18:45:55  rich
  * foo
index 5e0c1a2..d2ac6bc 100755 (executable)
@@ -20,9 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    $Id$ 
 
    $Log$
-   Revision 1.1  1991/03/21 21:28:26  gumby
-   Initial revision
+   Revision 1.1.1.1  1991/03/21 21:28:27  gumby
+   Back from Intel with Steve
 
+ * Revision 1.1  1991/03/21  21:28:26  gumby
+ * Initial revision
+ *
  * Revision 1.3  1991/03/16  22:27:24  rich
  * fish
  *
index 0f82ebe..173bbdf 100755 (executable)
@@ -20,9 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    $Id$ 
 
    $Log$
-   Revision 1.1  1991/03/21 21:28:28  gumby
-   Initial revision
+   Revision 1.1.1.1  1991/03/21 21:28:29  gumby
+   Back from Intel with Steve
 
+ * Revision 1.1  1991/03/21  21:28:28  gumby
+ * Initial revision
+ *
  * Revision 1.2  1991/03/15  18:45:55  rich
  * foo
  *
diff --git a/ld/ld.tex b/ld/ld.tex
new file mode 100755 (executable)
index 0000000..1764ad5
--- /dev/null
+++ b/ld/ld.tex
@@ -0,0 +1,1014 @@
+\input texinfo
+@parindent=0pt
+@setfilename gld
+@c @@setchapternewpage odd
+@settitle GLD, The GNU linker
+@titlepage
+@title{gld}
+@subtitle{The gnu loader}
+@sp 1
+@subtitle Second Edition---gld version 2.0
+@subtitle January 1991
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+
+@author {Steve Chamberlain}
+@author {Cygnus Support}
+@author {steve@@cygnus.com}
+@end titlepage
+
+@node Top,,,
+@comment  node-name,  next,  previous,  up
+@ifinfo
+This file documents the GNU linker gld.
+@end ifinfo
+
+@c chapter What does a linker do ?
+@c chapter Command Language
+@noindent
+@chapter Overview
+
+
+The @code{gld} command combines a number of object and archive files,
+relocates their data and ties up symbol references. Often the last
+step in building a new compiled program to run is a call to @code{gld}.
+
+The @code{gld} command accepts Linker Command Language files in
+a superset of AT+T's Link Editor Command Language syntax,
+to provide explict and total control over the linking process.
+
+This version of @code{gld} uses the general purpose @code{bfd} libraries
+to operate on object files. This allows @code{gld} to read and
+write any of the formats supported by @code{bfd}, different
+formats may be linked together producing any available object file. 
+
+Supported formats:
+@itemize @bullet
+@item
+Sun3 68k a.out
+@item 
+IEEE-695 68k Object Module Format
+@item 
+Oasys 68k Binary Relocatable Object File Format
+@item 
+Sun4 sparc a.out
+@item 
+88k bcs coff
+@item 
+i960 coff little endian
+@item 
+i960 coff big endian
+@item 
+i960 b.out little endian
+@item 
+i960 b.out big endian
+@item
+s-records
+@end itemize
+When linking similar formats, @code{gld} maintains all debugging
+information. 
+
+@chapter Command line options
+
+@example
+  gld [ -Bstatic ]  [ -D @var{datasize} ] 
+      [ -c @var{filename} ]
+      [ -d ]  | [ -dc ] | [ -dp ]
+      [ -i ]
+      [ -e @var{entry} ]  [ -l @var{arch} ]  [ -L @var{searchdir} ]  [ -M ]  
+      [ -N | -n | -z ]  [ -noinhibit-exec ]  [ -r ]  [ -S ]  [ -s ]  
+      [ -f @var{fill} ]
+      [ -T @var{textorg} ]  [ -Tdata @var{dataorg} ]  [ -t ]  [ -u @var{sym}]
+      [ -X ]  [ -x ] 
+      [-o @var{output} ] @var{objfiles}@dots{}
+@end example
+
+Command-line options to GNU @code{gld} may be specified in any order, and
+may be repeated at will.  For the most part, repeating an option with a
+different argument will either have no further effect, or override prior
+occurrences (those further to the left on the command line) of an
+option.  
+
+The exceptions which may meaningfully be present several times
+are @code{-L}, @code{-l}, and @code{-u}.
+
+@var{objfiles} may follow, precede, or be mixed in with
+command-line options; save that an @var{objfiles} argument may not be
+placed between an option flag and its argument.
+
+Option arguments must follow the option letter without intervening
+whitespace, or be given as separate arguments immediately following the
+option that requires them.
+
+@table @code
+@item @var{objfiles}@dots{}
+The object files @var{objfiles} to be linked; at least one must be specified.
+
+@item -Bstatic 
+This flag is accepted for command-line compatibility with the SunOS linker,
+but has no effect on @code{gld}.
+
+@item -c @var{commandfile}
+Directs @code{gld} to read linkage commands from the file @var{commandfile}.
+
+@item -D @var{datasize}
+Use this option to specify a target size for the @code{data} segment of
+your linked program.  The option is only obeyed if @var{datasize} is
+larger than the natural size of the program's @code{data} segment.
+
+@var{datasize} must be an integer specified in hexadecimal.
+
+@code{ld} will simply increase the size of the @code{data} segment,
+padding the created gap with zeros, and reduce the size of the
+@code{bss} segment to match.
+
+@item -d
+Force @code{ld} to assign space to common symbols
+even if a relocatable output file is specified (@code{-r}).
+
+@item -dc | -dp
+This flags is accepted for command-line compatibility with the SunOS linker,
+but has no effect on @code{gld}.
+
+@item -e @var{entry} 
+Use @var{entry} as the explicit symbol for beginning execution of your
+program, rather than the default entry point. If this symbol is
+not specified, the symbol @code{start} is used as the entry address.
+If there is no symbol called @code{start}, then the entry address
+is set to the first address in the first output section 
+(usually the @samp{text} section).
+
+@item -f @var{fill}
+Sets the default fill pattern for ``holes'' in the output file to
+the lowest two bytes of the expression specified.
+
+@item -i
+Produce an incremental link (same as option @code{-r}).
+
+@item -l @var{arch} 
+Add an archive file @var{arch} to the list of files to link.  This 
+option may be used any number of times.  @code{ld} will search its
+path-list for occurrences of @code{lib@var{arch}.a} for every @var{arch}
+specified.
+
+@c This also has a side effect of using the "c++ demangler" if we happen
+@c to specify -llibg++.  Document?  pesch@@cygnus.com, 24jan91
+
+@item -L @var{searchdir} 
+This command adds path @var{searchdir} to the
+list of paths that @code{gld} will search for archive libraries.  You
+may use this option any number of times.
+
+@c Should we make any attempt to list the standard paths searched
+@c without listing?  When hacking on a new system I often want to know
+@c this, but this may not be the place... it's not constant across
+@c systems, of course, which is what makes it interesting.
+@c pesch@@cygnus.com, 24jan91.
+
+@item -M 
+@itemx -m
+Print (to the standard output file) a link map---diagnostic information
+about where symbols are mapped by @code{ld}, and information on global
+common storage allocation.
+
+@item -N 
+specifies read and writable @code{text} and @code{data} sections. If
+the output format supports Unix style magic numbers, then OMAGIC is set.
+
+@item -n 
+sets the text segment to be read only, and @code{NMAGIC} is written
+if possible.
+
+@item -o @var{output}
+@var{output} is a name for the program produced by @code{ld}; if this
+option is not specified, the name @samp{a.out} is used by default.
+
+@item -r 
+Generates relocatable output---i.e., generate an output file that can in
+turn serve as input to @code{gld}.  As a side effect, this option also
+sets the output file's magic number to @code{OMAGIC}; see @samp{-N}. If this
+option is not specified, an absolute file is produced.
+
+@item -S 
+Omits debugger symbol information (but not all symbols) from the output file.
+
+@item -s 
+Omits all symbol information from the output file.
+
+@item -T @var{textorg} 
+@itemx -Ttext @var{textorg}
+Use @var{textorg} as the starting address for the @code{text} segment of the
+output file.  Both forms of this option are equivalent.  The option
+argument must be a hexadecimal integer.
+
+@item -Tdata @var{dataorg} 
+Use @var{dataorg} as the starting address for the @code{data} segment of
+the output file.  The option argument must be a hexadecimal integer.
+
+@item -t 
+Prints names of input files as @code{ld} processes them.
+
+@item -u @var{sym}
+Forces @var{sym} to be entered in the output file as an undefined symbol.
+This may, for example, trigger linking of additional modules from
+standard libraries.  @code{-u} may be repeated with different option
+arguments to enter additional undefined symbols. This option is equivalent
+to the @code{EXTERN} linker command.
+
+@item -X 
+If @code{-s} or @code{-S} is also specified, delete only local symbols
+beginning with @samp{L}.
+
+@item -z
+@code{-z} sets @code{ZMAGIC}, the default: the @code{text} segment is
+read-only, demand pageable, and shared.  
+
+Specifying a relocatable output file (@code{-r}) will also set the magic
+number to @code{OMAGIC}.
+
+See description of @samp{-N}.
+
+
+@end table
+@chapter Command Language
+
+
+The command language allows explicit control over the linkage process, allowing
+specification of:
+@table @bullet
+@item input files 
+@item file formats
+@item output file format
+@item addresses of sections
+@item placement of common blocks
+@item and more
+@end table
+
+A command file may be supplied to the linker, either explicitly through the
+@code{-c} option, or implicitly as an ordinary file. If the linker opens
+a file which does not have a reasonable object or archive format, it tries
+to read the file as if it were a command file.
+@section Structure
+To be added
+
+@section Expressions
+The syntax for expressions in the command language is identical to that of
+C expressions, with the following features:
+@table @bullet
+@item All expressions evaluated as integers and
+are of ``long'' or ``unsigned long'' type.
+@item All constants are integers.
+@item All of the C arithmetic operators are provided.
+@item Global variables may be referenced, defined and created.
+@item Build in functions may be called.
+@end table
+
+@section Expressions
+
+The linker has a practice of ``lazy evaluation'' for expressions; it only
+calculates an expression when absolutely necessary. For instance, 
+when the linker reads in the command file it has to know the values
+of the start address and the length of the memory regions for linkage to continue, so these
+values are worked out, but other values (such as symbol values) are not
+known or needed until after storage allocation.
+They are evaluated later, when the other
+information, such as the sizes of output sections are available for use in
+the symbol assignment expression.
+
+When a linker expression is evaluated and assigned to a variable it is given
+either an absolute or a relocatable type. An absolute expression type
+is one in which the symbol contains the value that it will have in the
+output file, a relocateable expression type is one in which the value
+is expressed as a fixed offset from the base of a section.
+
+The type of the expression is controlled by its position in the script
+file. A symbol assigned within a @code{SECTION} specification is
+created relative to the base of the section, a symbol assigned in any
+other place is created as an absolute symbol. Since a symbol created
+within a @code{SECTION} specification is relative to the base of the
+section it will remain relocatable if relocatable output is requested.
+A symbol may be created with an absolute value even when assigned to
+within a @code{SECTION} specification by using the absolute assignment
+function @code{ABSOLUTE} For example, to create an absolute symbol
+whose address is the last byte of the output section @code{.data}:
+@example
+.data : 
+        @{
+                *(.data)
+                _edata = ABSOLUTE(.) ;
+        @} 
+@end example
+
+Unless quoted, symbol names start with a letter, underscore, point or
+minus sign and may include any letters, underscores, digits, points,
+and minus signs.  Unquoted symbol names must not conflict with any
+keywords.  To specify a symbol which contains odd characters or has
+the same name as a keyword surround it in double quotes:
+@example
+        ``SECTION'' = 9;
+        ``with a space'' = ``also with a space'' + 10;
+@end example
+
+@subsection Integers
+An octal integer is @samp{0} followed by zero or more of the octal
+digits (@samp{01234567}).
+
+A decimal integer starts with a non-zero digit followed by zero or
+more digits (@samp{0123456789}).
+
+A hexadecimal integer is @samp{0x} or @samp{0X} followed by one or
+more hexadecimal digits chosen from @samp{0123456789abcdefABCDEF}.
+
+Integers have the usual values.  To denote a negative integer, use
+the unary operator @samp{-} discussed under expressions.
+
+Additionally the suffixes @code{K} and @code{M} may be used to multiply the
+previous constant by 1024 or 
+@tex
+$1024^2$
+@end tex
+respectively.
+
+@example
+        _as_decimal = 57005;
+        _as_hex = 0xdead;
+        _as_octal = 0157255;
+
+        _4k_1 = 4K;
+        _4k_2 = 4096;
+        _4k_3 = 0x1000;
+@end example
+@subsection Operators
+The linker provides the standard C set of arithmetic operators, with
+the standard bindings and precedence levels:
+@example
+
+@end example
+@tex
+
+\vbox{\offinterlineskip
+\hrule
+\halign
+{\vrule#&\hfil#\hfil&\vrule#&\hfil#\hfil&\vrule#&\hfil#\hfil&\vrule#\cr
+height2pt&&&&&\cr
+&Level&&  associativity  &&Operators&\cr
+height2pt&&&&&\cr
+\noalign{\hrule}
+height2pt&&&&&\cr
+&highest&&&&&&\cr
+&1&&left&&$ ! -         ~$&\cr
+height2pt&&&&&\cr
+&2&&left&&*        /        \%&\cr
+height2pt&&&&&\cr
+&3&&left&&+        -&\cr
+height2pt&&&&&\cr
+&4&&left&&$>> <<$&\cr
+height2pt&&&&&\cr
+&5&&left&&$==        !=        > < <= >=$&\cr
+height2pt&&&&&\cr
+&6&&left&&\&&\cr
+height2pt&&&&&\cr
+&7&&left&&|&\cr
+height2pt&&&&&\cr
+&8&&left&&{\&\&}&\cr
+height2pt&&&&&\cr
+&9&&left&&||&\cr
+height2pt&&&&&\cr
+&10&&right&&? :&\cr
+height2pt&&&&&\cr
+&11&&right&&$${\&=        +=        -=        *=        /=}&\cr
+&lowest&&&&&&\cr
+height2pt&&&&&\cr}
+\hrule}
+@end tex
+
+@section Built in Functions
+The command language provides built in functions for use in
+expressions in linkage scripts.
+@table @bullet 
+@item @code{ALIGN(@var{exp})}
+returns the result of the current location counter (@code{dot})
+aligned to the next @var{exp} boundary, where @var{exp} is a power of
+two.  This is equivalent to @code{(. + @var{exp} -1) & ~(@var{exp}-1)}.
+As an example, to align the output @code{.data} section to the
+next 0x2000 byte boundary after the preceding section and to set a
+variable within the section to the next 0x8000 boundary after the
+input sections:
+@example
+        .data ALIGN(0x2000) :@{
+                *(.data)
+                variable = ALIGN(0x8000);
+        @}
+@end example
+
+@item @code{ADDR(@var{section name})}
+returns the absolute address of the named section if the section has
+already been bound. In the following examples the @code{symbol_1} and
+@code{symbol_2} are assigned identical values:
+@example
+        .output1:
+                @{ 
+                start_of_output_1 $= .;
+                ... 
+                @}
+        .output:
+                @{
+                symbol_1 = ADDR(.output1);
+                symbol_2 = start_of_output_1;
+                @}
+@end example
+
+@item @code{SIZEOF(@var{section name})}
+returns the size in bytes of the named section, if the section has
+been allocated.  In the following example the @code{symbol_1} and
+@code{symbol_2} are assigned identical values:
+@example
+        .output @{
+                .start = . ;
+                ...
+                .end = .;
+                @}
+        symbol_1 = .end - .start;
+        symbol_2 = SIZEOF(.output);
+@end example
+
+@item @code{DEFINED(@var{symbol name})}
+Returns 1 if the symbol is in the linker global symbol table and is
+defined, otherwise it returns 0. This example shows the setting of a
+global symbol @code{begin} to the first location in the @code{.text}
+section, only if there is no other symbol
+called @code{begin} already:
+@example
+        .text: @{
+                begin = DEFINED(begin) ? begin : . ;
+                ...
+        @}
+@end example
+@end table 
+@page
+@section MEMORY Directive
+The linker's default configuration is for all memory to be
+allocatable.  This state may be overridden by using the @code{MEMORY}
+directive.  The @code{MEMORY} directive describes the location and
+size of blocks of memory in the target.  Careful use can describe
+memory regions which may or may not be used by the linker. The linker
+does not shuffle sections to fit into the available regions, but does
+move the requested sections into the correct regions and issue errors
+when the regions become too full.  The syntax is:
+       
+@example
+        MEMORY 
+                @{
+@tex
+                 $\bigl\lbrace {\it name_1} ({\it attr_1}):$ ORIGIN = ${\it origin_1},$ LENGTH $= {\it len_1} \bigr\rbrace $
+@end tex
+
+                @}
+@end example
+@table @code
+@item @var{name}
+is a name used internally by the linker to refer to the region. Any
+symbol name may be used.  The region names are stored in a separate
+name space, and will not conflict with symbols, filenames or section
+names.
+@item @var{attr}
+is an optional list of attributes, parsed for compatibility with the
+AT+T linker
+but ignored by the both the AT+T and the gnu linker.
+@item @var{origin}
+is the start address of the region in physical memory expressed as
+standard linker expression which must evaluate to a constant before
+memory allocation is performed. The keyword @code{ORIGIN} may be
+abbreviated to @code{org} or @code{o}.
+@item @var{len}
+is the size in bytes of the region as a standard linker expression.
+The keyword @code{LENGTH} may be abbreviated to @code{len} or @code{l}
+@end table 
+
+For example, to specify that memory has two regions available for
+allocation; one starting at 0 for 256k, and the other starting at
+0x40000000 for four megabytes:
+
+@example
+        MEMORY 
+                @{
+                rom : ORIGIN= 0, LENGTH = 256K
+                ram : ORIGIN= 0x40000000, LENGTH = 4M
+                @}
+
+@end example
+
+If the combined output sections directed to a region are too big for
+the region the linker will emit an error message.
+@page
+@section SECTIONS Directive
+The @code{SECTIONS} directive 
+controls exactly where input sections are placed into output sections, their
+order and to which output sections they are allocated.
+
+When no @code{SECTIONS} directives are specified, the default action
+of the linker is to place each input section into an identically named
+output section in the order that the sections appear in the first
+file, and then the order of the files.
+
+The syntax of the @code{SECTIONS} directive is:
+
+@example
+   SECTIONS
+   @{
+@tex
+    $\bigl\lbrace {\it name_n}\bigl[options\bigr]\colon$ $\bigl\lbrace {\it statements_n} \bigr\rbrace \bigl[ = {\it fill expression } \bigr] \bigl[ > mem spec \bigr] \bigr\rbrace $
+@end tex
+   @}
+@end example
+
+@table @code
+@item @var{name}
+controls the name of the output section. In formats which only support
+a limited number of sections, such as @code{a.out}, the name must be
+one of the names supported by the format (in the case of a.out,
+@code{.text}, @code{.data} or @code{.bss}). If the output format
+supports any number of sections, but with numbers and not names (in
+the case of IEEE), the name should be supplied as a quoted numeric
+string.  A section name may consist of any sequence characters, but
+any name which does not conform to the standard @code{gld} symbol name
+syntax must be quoted. To copy sections 1 through 4 from a Oasys file
+into the @code{.text} section of an @code{a.out} file, and sections 13
+and 14 into the @code{data} section:
+@example
+
+        SECTION @{
+                .text :@{
+                        *(``1'' ``2'' ``3'' ``4'')
+                @}
+
+                .data :@{
+                        *(``13'' ``14'')
+                @}
+        @}
+@end example
+
+@item @var{fill expression}
+If present this
+expression sets the fill value. Any unallocated holes in the current output
+section when written to the output file will 
+be filled with the two least significant bytes of the value, repeated as
+necessary.
+@page
+@item @var{options}
+the @var{options} parameter is a list of optional arguments specifying
+attributes of the output section, they may be taken from the following
+list:
+@table @bullet{}
+@item @var{addr expression} 
+forces the output section to be loaded at a specified address. The
+address is specified as a standard linker expression. The following
+example generates section @var{output} at location
+@code{0x40000000}:
+@example
+         SECTIONS @{
+                 output 0x40000000: @{
+                        ...
+                   @}
+         @}
+@end example
+Since the built in function @code{ALIGN} references the location
+counter implicitly, a section may be located on a certain boundary by
+using the @code{ALIGN} function in the expression. For example, to
+locate the @code{.data} section on the next 8k boundary after the end
+of the @code{.text} section:
+@example        
+        SECTIONS @{
+                .text @{
+                        ...
+                @}
+                .data ALIGN(4K) @{
+                        ...
+                @}
+        @}
+@end example
+@end table
+@item @var{statements}
+is a list of file names, input sections and assignments. These statements control what is placed into the
+output section.
+The syntax of a single @var{statement} is one of:
+@table @bullet 
+
+@item @var{symbol}  [ $= | += | -= | *= | /= ] @var{ expression} @code{;}
+
+Global symbols may be created and have their values (addresses)
+altered using the assignment statement. The linker tries to put off
+the evaluation of an assignment until all the terms in the source
+expression are known; for instance the sizes of sections cannot be
+known until after allocation, so assignments dependent upon these are
+not performed until after allocation. Some expressions, such as those
+depending upon the location counter @code{dot}, @samp{.} must be
+evaluated during allocation. If the result of an expression is
+required, but the value is not available, then an error results: eg
+@example
+        SECTIONS @{
+              text 9+this_isnt_constant: 
+                        @{
+                        @}
+                @}
+        testscript:21: Non constant expression for initial address
+@end example
+
+@item @code{CREATE_OBJECT_SYMBOLS}
+causes the linker to create a symbol for each input file and place it
+into the specified section set with the value of the first byte of
+data written from the input file.  For instance, with @code{a.out}
+files it is conventional to have a symbol for each input file.
+@example
+        SECTIONS @{
+                .text 0x2020 :
+                         @{
+                        CREATE_OBJECT_SYMBOLS
+                        *(.text)
+                        _etext = ALIGN(0x2000);
+                        @}
+                @}
+@end example
+Supplied with four object files, @code{a.o}, @code{b.o}, @code{c.o},
+and @code{d.o} a run of
+@code{gld} could create a map:
+@example
+From functions like :
+a.c:
+        afunction() { }
+        int adata=1;
+        int abss;
+
+00000000 A __DYNAMIC
+00004020 B _abss
+00004000 D _adata
+00002020 T _afunction
+00004024 B _bbss
+00004008 D _bdata
+00002038 T _bfunction
+00004028 B _cbss
+00004010 D _cdata
+00002050 T _cfunction
+0000402c B _dbss
+00004018 D _ddata
+00002068 T _dfunction
+00004020 D _edata
+00004030 B _end
+00004000 T _etext
+00002020 t a.o
+00002038 t b.o
+00002050 t c.o
+00002068 t d.o
+
+@end example
+
+@item @var{filename} @code{(} @var{section name list} @code{)}
+This command allocates all the named sections from the input object
+file supplied into the output section at the current point. Sections
+are written in the order they appear in the list so:
+@example
+        SECTIONS @{
+                .text 0x2020 :                
+                        @{
+                        a.o(.data)
+                        b.o(.data)
+                        *(.text)
+                        @}
+                .data :
+                        @{
+                        *(.data)
+                        @}
+                .bss :
+                        @{
+                        *(.bss)
+                        COMMON
+                        @}
+        @}
+@end example
+will produce a map:
+@example
+
+        insert here 
+@end example
+@item @code{* (} @var{section name list} @code{)}
+This command causes all sections from all input files which have not
+yet been assigned output sections to be assigned the current output
+section.
+
+@item @var{filename} @code{[COMMON]}
+This allocates all the common symbols from the specified file and places
+them into the current output section.
+
+@item @code{* [COMMON]}
+This allocates all the common symbols from the files which have not
+yet had their common symbols allocated and places them into the current
+output section.
+
+@item @var{filename}
+A filename alone within a @code{SECTIONS} statement will cause all the
+input sections from the file to be placed into the current output
+section at the current location. If the file name has been mentioned
+before with a section name list then only those
+sections which have not yet been allocated are noted. 
+
+The following example reads all of the sections from file all.o and
+places them at the start of output section @code{outputa} which starts
+at location @code{0x10000}. All of the data from section @code{.input1} from
+file foo.o is placed next into the same output section.  All of
+section @code{.input2} is read from foo.o and placed into output
+section @code{outputb}.  Next all of section @code{.input1} is read
+from foo1.o. All of the remaining @code{.input1} and @code{.input2}
+sections from any files are written to output section @code{output3}.
+
+@example
+       SECTIONS        
+              @{
+                outputa 0x10000 :
+                        @{
+                        all.o
+                        foo.o (.input1)
+                        @}
+                outputb :
+                        @{
+                        foo.o (.input2)
+                        foo1.o (.input1)
+                        @}
+                outputc :
+                        @{
+                        *(.input1)
+                        *(.input2)
+                        @}
+                @}
+
+@end example        
+@end table
+@end table
+@section Using the Location Counter
+The special linker variable @code{dot}, @samp{.} always contains the
+current output location counter. Since the @code{dot} always refers to
+a location in an output section, it must always appear in an
+expression within a @code{SECTIONS} directive. The @code{dot} symbol
+may appear anywhere that an ordinary symbol may appear in an
+expression, but its assignments have a side effect. Assigning a value
+to the @code{dot} symbol will cause the location counter to be moved.
+This may be used to create holes in the output section.  The location
+counter may never be moved backwards.
+@example
+        SECTIONS
+        @{
+                output :
+                @{
+                file1(.text)
+                . = . + 1000;
+                file2(.text)
+                . += 1000;
+                file3(.text)
+                . -= 32;
+                file4(.text)
+                @} = 0x1234;
+        @}
+@end example
+In the previous example, @code{file1} is located at the beginning of
+the output section, then there is a 1000 byte gap, filled with 0x1234.
+Then @code{file2} appears, also with a 1000 byte gap following before
+@code{file3} is loaded. Then the first 32 bytes of @code{file4} are
+placed over the last 32 bytes of @code{file3}.
+@section Command Language Syntax
+@section The Entry Point
+The linker chooses the first executable instruction in an output file from a list
+of possibilities, in order:
+@itemize @bullet
+@item 
+The value of the symbol provided to the command line with the @code{-e} option, when
+present.
+@item 
+The value of the symbol provided in the @code{ENTRY} directive,
+if present.
+@item 
+The value of the symbol @code{start}, if present.
+@item 
+The value of the symbol @code{_main}, if present.
+@item 
+The address of the first byte of the @code{.text} section, if present.
+@item 
+The value 0.
+@end itemize
+If the symbol @code{start} is not defined within the set of input
+files to a link, it may be generated by a simple assignment
+expression. eg.
+@example
+        start = 0x2020;
+@end example
+@section Section Attributes
+@section Allocation of Sections into Memory
+@section Defining Symbols
+@chapter Examples of operation
+The simplest case is linking standard Unix object files on a standard
+Unix system supported by the linker. To link a file hello.o:
+@example
+$ gld -o output /lib/crt0.o hello.o -lc
+@end example
+This tells gld to produce a file called @code{output} after linking
+the file @code{/lib/crt0.o} with @code{hello.o} and the library
+@code{libc.a} which will come from the standard search directories.
+@chapter Partial Linking
+Specifying the @code{-r} on the command line causes @code{gld} to
+perform a partial link.
+
+
+@chapter BFD
+
+The linker accesses object and archive files using the @code{bfd}
+libraries. These libraries allow the linker to use the same routines
+to operate on object files whatever the object file format.
+
+A different object file format can be supported simply by creating a
+new @code{bfd} back end and adding it to the library.
+
+Formats currently supported:
+@itemize @bullet
+@item 
+Sun3 68k a.out
+@item 
+IEEE-695 68k Object Module Format
+@item 
+Oasys 68k Binary Relocatable Object File Format
+@item 
+Sun4 sparc a.out
+@item 
+88k bcs coff
+@item 
+i960 coff little endian
+@item 
+i960 coff big endian
+@item 
+i960 b.out little endian
+@item 
+i960 b.out big endian
+@end itemize
+
+As with most implementations, @code{bfd} is a compromise between
+several conflicting requirements. The major factor influencing
+@code{bfd} design was efficiency, any time used converting between
+formats is time which would not have been spent had @code{bfd} not
+been involved. This is partly offset by abstraction payback; since
+@code{bfd} simplifies applications and back ends, more time and care
+may be spent optimizing algorithms for a greater speed.
+
+One minor artifact of the @code{bfd} solution which the
+user should be aware of is information lossage.
+There are two places where useful information can be lost using the 
+@code{bfd} mechanism; during conversion and during output. 
+
+@section How it works
+When an object file is opened, @code{bfd}
+tries to automatically determine the format of the input object file, a
+descriptor is built in memory with pointers to routines to access
+elements of the object file's data structures.
+
+As different information from the the object files is required
+@code{bfd} reads from different sections of the file and processes
+them. For example a very common operation for the linker is processing
+symbol tables.  Each @code{bfd} back end provides a routine for
+converting between the object file's representation of symbols and an
+internal canonical format. When the linker asks for the symbol table
+of an object file, it calls through the memory pointer to the relevant
+@code{bfd} back end routine which reads and converts the table into
+the canonical form.  Linker then operates upon the common form. When
+the link is finished and the linker writes the symbol table of the
+output file, another @code{bfd} back end routine is called which takes
+the newly created symbol table and converts it into the output format.
+
+@section Information Leaks
+@table @bullet{}
+@item Information lost during output.
+The output formats supported by @code{bfd} do not provide identical 
+facilities, and information which may be described in one form 
+has no where to go in another format. One example of this would be
+alignment information in @code{b.out}. There is no where in an @code{a.out}
+format file to store alignment information on the contained data, so when
+a file is linked from @code{b.out} and an @code{a.out} image is produced,
+alignment information is lost. (Note that in this case the linker has the
+alignment information internally, so the link is performed correctly). 
+
+Another example is COFF section names. COFF files may contain an
+unlimited number of sections, each one with a textual section name. If
+the target of the link is a format which does not have many sections
+(eg @code{a.out}) or has sections without names (eg the Oasys format)
+the link cannot be done simply. It is possible to circumvent this
+problem by describing the desired input section to output section
+mapping with the command language.
+
+@item Information lost during canonicalization.  
+The @code{bfd}
+internal canonical form of the external formats is not exhaustive,
+there are structures in input formats for which there is no direct
+representation internally.  This means that the @code{bfd} back ends
+cannot maintain all the data richness through the transformation
+between external to internal and back to external formats.
+
+This limitation is only a problem when using the linker to read one
+format and write another. Each @code{bfd} back end is responsible for
+maintaining as much data as possible, and the internal @code{bfd}
+canonical form has structures which are opaque to the @code{bfd} core,
+and exported only to the back ends. When a file is read in one format,
+the canonical form is generated for @code{bfd} and the linker. At the
+same time, the back end saves away any information which may otherwise
+be lost. If the data is then written back to the same back end, the
+back end routine will be able to use the canonical form provided by
+the @code{bfd} core as well as the information it prepared earlier.
+Since there is a great deal of commonality between back ends, this
+mechanism is very useful. There is no information lost when linking
+big endian COFF to little endian COFF, or from a.out to b.out. When a
+mixture of formats are linked, the information is only lost from the
+files with a different format to the destination.  
+@end table 
+@section Mechanism 
+The smallest amount of information is preserved when there
+is a small union between the information provided by the source
+format, that stored by the canonical format and the information needed
+by the destination format. A brief description of the canonical form
+will help the user appreciate what is possible to be maintained
+between conversions.
+
+@table @bullet 
+@item file level Information on target machine
+architecture, particular implementation and format type are stored on
+a per file basis. Other information includes a demand pageable bit and
+a write protected bit.  Note that information like Unix magic numbers
+is not stored here, only the magic numbers meaning, so a ZMAGIC file
+would have both the demand pageable bit and the write protected text
+bit set.
+
+The byte order of the target is stored on a per file basis, so that
+both big and little endian object files may be linked together at the
+same time.
+@item section level
+Each section in the input file contains the name of the section, the
+original address in the object file, various flags, size and alignment
+information and pointers into other @code{bfd} data structures.
+@item symbol level
+Each symbol contains a pointer to the object file which originally
+defined it, its name, value and various flags bits. When a symbol
+table is read in all symbols are relocated to make them relative to
+the base of the section they were defined in, so each symbol points to
+the containing section. Each symbol also has a varying amount of
+hidden data to contain private data for the back end. Since the symbol
+points to the original file, the symbol private data format is
+accessible. Operations may be done to a list of symbols of wildly
+different formats without problems.
+
+Normal global and simple local symbols are maintained on output, so an
+output file, no matter the format will retain symbols pointing to
+functions, globals, statics and commons.  Some symbol information is
+not worth retaining; in @code{a.out} type information is stored in the
+symbol table as long symbol names. This information would be useless
+to most coff debuggers and may be thrown away with appropriate command
+line switches. (Note that gdb does support stabs in coff).
+
+There is one word of type information within the symbol, so if the
+format supports symbol type information within symbols - (eg COFF,
+IEEE, Oasys) and the type is simple enough to fit within one word
+(nearly everything but aggregates) the information will be preserved.
+
+@item relocation level
+Each canonical relocation record contains a pointer to the symbol to
+relocate to, the offset of the data to relocate, the section the data
+is in and a pointer to a relocation type descriptor. Relocation is
+performed effectively by message passing through the relocation type
+descriptor and symbol pointer. It allows relocations to be performed
+on output data using a relocation method only available in one of the
+input formats. For instance, Oasys provides a byte relocation format.
+A relocation record requesting this relocation type would point
+indirectly to a routine to perform this, so the relocation may be
+performed on a byte being written to a COFF file, even though 68k COFF
+has no such relocation type.
+
+@item line numbers
+Line numbers have to be relocated along with the symbol information.
+Each symbol with an associated list of line number records points to
+the first record of the list.  The head of a line number list consists
+of a pointer to the symbol, which allows divination of the address of
+the function who's line number is being described. The rest of the
+list is tuples offsets into the section and line indexes. Any format
+which can simply derive this information can pass it without lossage
+between formats (COFF, IEEE and Oasys).
+@end table
+
+
+@bye
+
+
index 796060c..4b0001a 100644 (file)
@@ -20,8 +20,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  *  $Id$ 
  *
  *  $Log$
- *  Revision 1.1  1991/03/21 21:28:58  gumby
- *  Initial revision
+ *  Revision 1.1.1.1  1991/03/21 21:28:58  gumby
+ *  Back from Intel with Steve
+ *
+ * Revision 1.1  1991/03/21  21:28:58  gumby
+ * Initial revision
  *
  * Revision 1.1  1991/03/13  00:48:32  chrisb
  * Initial revision
diff --git a/ld/ldsym.h b/ld/ldsym.h
new file mode 100644 (file)
index 0000000..8a12bbc
--- /dev/null
@@ -0,0 +1,59 @@
+/* ldsym.h -
+
+   Copyright (C) 1991 Free Software Foundation, Inc.
+
+   This file is part of GLD, the Gnu Linker.
+
+   GLD is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   GLD is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GLD; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+typedef struct user_symbol_struct
+{
+  /* Point to next symbol in this hash chain */
+  struct user_symbol_struct *link;
+
+  /* Name of this symbol.  */
+  char *name;                  
+
+  /* Pointer to next symbol in order of symbol creation */
+  struct user_symbol_struct *next; 
+
+  /* Chain of asymbols we see from input files 
+     note that we point to the entry in the canonical table of 
+     the pointer to the asymbol, *not* the asymbol. This means
+     that we can run back and fix all refs to point to the
+     defs nearly for free.
+     */
+  asymbol **srefs_chain;
+  asymbol **sdefs_chain;
+
+  /* only ever point to the largest ever common definition -
+   * all the rest are turned into refs 
+   * scoms and sdefs are never != NULL at same time
+   */
+  asymbol **scoms_chain;
+
+} ldsym_type;
+
+
+PROTO(ldsym_type *, ldsym_get, (char *));
+PROTO(ldsym_type *, ldsym_get_soft, (char *));
+PROTO(void, ldsym_print_symbol_table,(void));
+PROTO(void, ldsym_write, (void));
+
+#define FOR_EACH_LDSYM(x)                                              \
+       extern ldsym_type *symbol_head;                                 \
+       ldsym_type *x;                                                  \
+       for (x = symbol_head; x != (ldsym_type *)NULL; x = x->next)     
+
diff --git a/ld/ldwarn.h b/ld/ldwarn.h
new file mode 100644 (file)
index 0000000..be0d107
--- /dev/null
@@ -0,0 +1,22 @@
+/* ldwarn.h -
+
+   Copyright (C) 1991 Free Software Foundation, Inc.
+
+   This file is part of GLD, the Gnu Linker.
+
+   GLD is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   GLD is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GLD; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+PROTOX(void, ldwarn,(void));