Initial revision
authorDavid Henkel-Wallace <gumby@cygnus>
Thu, 21 Mar 1991 21:29:06 +0000 (21:29 +0000)
committerDavid Henkel-Wallace <gumby@cygnus>
Thu, 21 Mar 1991 21:29:06 +0000 (21:29 +0000)
32 files changed:
binutils/ar.c [new file with mode: 0644]
binutils/bucomm.c [new file with mode: 0644]
binutils/filemode.c [new file with mode: 0644]
binutils/i960-pinsn.c [new file with mode: 0644]
binutils/m68k-pinsn.c [new file with mode: 0644]
binutils/nm.c [new file with mode: 0644]
binutils/objdump.c [new file with mode: 0644]
binutils/size.c [new file with mode: 0644]
binutils/sparc-pinsn.c [new file with mode: 0644]
binutils/version.c [new file with mode: 0644]
ld/Makefile [new file with mode: 0755]
ld/ld-emul.c [new file with mode: 0755]
ld/ld-gld.c [new file with mode: 0755]
ld/ld-gld960.c [new file with mode: 0755]
ld/ld-lnk960.c [new file with mode: 0755]
ld/ld.h [new file with mode: 0644]
ld/ldexp.c [new file with mode: 0644]
ld/ldexp.h [new file with mode: 0644]
ld/ldfile.c [new file with mode: 0644]
ld/ldfile.h [new file with mode: 0644]
ld/ldgram.y [new file with mode: 0644]
ld/ldlang.c [new file with mode: 0644]
ld/ldlang.h [new file with mode: 0644]
ld/ldlex.h [new file with mode: 0644]
ld/ldlex.l [new file with mode: 0644]
ld/ldmain.c [new file with mode: 0644]
ld/ldmain.h [new file with mode: 0644]
ld/ldmisc.c [new file with mode: 0644]
ld/ldmisc.h [new file with mode: 0644]
ld/ldsym.c [new file with mode: 0644]
ld/ldwrite.c [new file with mode: 0644]
ld/ldwrite.h [new file with mode: 0644]

diff --git a/binutils/ar.c b/binutils/ar.c
new file mode 100644 (file)
index 0000000..9a8a528
--- /dev/null
@@ -0,0 +1,850 @@
+
+
+
+/* ar.c - Archive modify and extract. */
+/*
+   Bugs: should use getopt the way tar does (complete w/optional -) and
+   should have long options too. GNU ar used to check file against filesystem
+   in quick_update and replace operations (would check mtime). Doesn't warn
+   when name truncated. No way to specify pos_end. Error messages should be
+   more consistant.
+*/
+#include "sysdep.h"
+#include "bfd.h"
+#include "ar.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <errno.h>
+#define BUFSIZE 8192
+/* Not great to have these here.  Should they be exported or not? */
+PROTO(size_t, bfd_read, (void *ptr, size_t size, size_t nitems, bfd * abfd));
+PROTO(size_t, bfd_write, (void *ptr, size_t size, size_t nitems, bfd * abfd));
+/* PROTO (void, open_inarch, (char *archive_filename)); */
+#ifdef __STDC__
+static void     open_inarch(char *archive_filename);
+#else
+static void     open_inarch();
+#endif                         /* __STDC__ */
+
+PROTO(void, map_over_members, (void (*function) (), char **files, int count));
+PROTO(void, print_contents, (bfd * member));
+PROTO(void, extract_file, (bfd * abfd));
+PROTO(void, delete_members, (char **files_to_delete));
+PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
+PROTO(void, move_members, (char **files_to_move));
+PROTO(void, replace_members, (char **files_to_replace));
+PROTO(void, print_descr, (bfd * abfd));
+PROTO(void, ranlib_only, (char *archname));
+
+/** Globals and flags */
+
+char           *program_name = NULL;
+bfd             bogus_archive;
+bfd            *inarch;                /* The input arch we're manipulating */
+
+/* Nonzero means don't warn about creating the archive file if necessary.  */
+int             silent_create = 0;
+/* Nonzero means describe each action performed.  */
+int             verbose = 0;
+/* Nonzero means preserve dates of members when extracting them.  */
+int             preserve_dates = 0;
+/*
+   Nonzero means don't replace existing members whose dates are more recent
+   than the corresponding files.
+*/
+int             newer_only = 0;
+/* write a __.SYMDEF member into the modified archive.  */
+boolean         write_armap = false;
+/*
+   Nonzero means don't update __.SYMDEF unless command line explicitly
+   requested it
+*/
+int             ignore_symdef = 0;
+/*
+   Nonzero means it's the name of an existing member; position new or moved
+   files with respect to this one.
+*/
+char           *posname = NULL;
+/*
+   Sez how to use `posname': pos_before means position before that member.
+   pos_after means position after that member. pos_end means always at end.
+   pos_default means default appropriately. For the latter two, `posname'
+   should also be zero.
+*/
+enum pos {
+    pos_default, pos_before, pos_after, pos_end
+}               postype = pos_default;
+
+/*
+   The option parsing should be in its own function.  It will be when I have
+   getopt working.
+*/
+int
+main(argc, argv)
+    int             argc;
+    char          **argv;
+{
+    char           *arg_ptr;
+    char            c;
+    enum {
+       none = 0, delete, replace, print_table,
+       print_files, extract, move, quick_append
+    }               operation = none;
+    int             arg_index;
+    char          **files;
+    char           *inarch_filename;
+    char           *temp;
+    program_name = argv[0];
+
+
+    temp = strrchr(program_name, '/');
+    if (temp == (char *) NULL)
+       temp = program_name;    /* shouldn't happen, but... */
+    else
+       ++temp;
+    if (!strcmp(temp, "ranlib")) {
+       if (argc < 2)
+           fatal("Too few command arguments.");
+       ranlib_only(argv[1]);
+    }
+
+
+    if (argc < 3)
+       fatal("Too few command arguments.");
+
+    arg_ptr = argv[1];
+
+    if (*arg_ptr == '-')
+       ++arg_ptr;              /* compatibility */
+
+    while (c = *arg_ptr++) {
+       switch (c) {
+       case 'd':
+       case 'm':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 't':
+       case 'x':
+           if (operation != none)
+               fatal("two different operation switches specified");
+           switch (c) {
+           case 'd':
+               operation = delete;
+               break;
+           case 'm':
+               operation = move;
+               break;
+           case 'p':
+               operation = print_files;
+               break;
+           case 'q':
+               operation = quick_append;
+               break;
+           case 'r':
+               operation = replace;
+               break;
+           case 't':
+               operation = print_table;
+               break;
+           case 'x':
+               operation = extract;
+               break;
+           }
+       case 'l':
+           break;
+       case 'c':
+           silent_create = 1;
+           break;
+       case 'o':
+           preserve_dates = 1;
+           break;
+       case 's':
+           write_armap = true;
+           break;
+       case 'u':
+           newer_only = 1;
+           break;
+       case 'v':
+           verbose = 1;
+           break;
+       case 'a':
+           postype = pos_after;
+           break;
+       case 'b':
+           postype = pos_before;
+           break;
+       case 'i':
+           postype = pos_before;
+           break;
+       default:
+           fatal("invalid option %c", c);
+       }
+    }
+
+    if (operation == none && write_armap)
+       ranlib_only(argv[2]);
+
+    if (operation == none)
+       fatal("no operation specified");
+
+    if (newer_only && operation != replace)
+       fatal("'u' only meaningful with 'r' option.");
+
+    arg_index = 2;
+
+    if (postype != pos_default)
+       posname = argv[arg_index++];
+
+    inarch_filename = argv[arg_index++];
+
+    if (arg_index < argc) {
+       files = argv + arg_index;
+       while (arg_index < argc)
+           if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
+               ignore_symdef = 1;
+               break;
+           }
+    }
+    else
+       files = NULL;
+
+    if (operation == quick_append) {
+       if (files != NULL)
+           do_quick_append(inarch_filename, files);
+       exit(0);
+    }
+
+
+    open_inarch(inarch_filename);
+    /*
+       If we have no archive, and we've been asked to replace then create one
+    */
+
+    if (operation == replace &&
+       inarch == &bogus_archive) {
+       silent_create = 1;
+       do_quick_append(inarch_filename, 0);
+       open_inarch(inarch_filename);
+    }
+
+    switch (operation) {
+
+    case print_table:
+       map_over_members(print_descr, files, argc - 3);
+       break;
+
+    case print_files:
+       map_over_members(print_contents, files, argc - 3);
+       break;
+
+    case extract:
+       map_over_members(extract_file, files, argc - 3);
+       break;
+
+    case delete:
+       if (files != NULL)
+           delete_members(files);
+       break;
+
+    case move:
+       if (files != NULL)
+           move_members(files);
+       break;
+
+    case replace:
+       if (files != NULL || write_armap)
+           replace_members(files);
+       break;
+
+       /* Shouldn't happen! */
+    default:
+       fprintf(stderr, "Sorry; this option not implemented.\n");
+    }
+
+    return (0);
+}                              /* main() */
+
+static
+char *normalize(file)
+char *file;
+{
+    char *    filename = strrchr(file, '/');
+    if (filename != (char *)NULL) {
+       filename ++;
+    }
+    else {
+       filename = file;
+    }
+    return filename;
+}
+
+static void
+open_inarch(archive_filename)
+    char           *archive_filename;
+{
+    bfd           **last_one;
+    bfd            *next_one;
+    struct stat     sbuf;
+    bfd_error = no_error;
+    if (stat(archive_filename, &sbuf) != 0) {
+       if (errno != ENOENT)
+           bfd_fatal(archive_filename);
+       if (!silent_create)
+           fprintf(stderr,
+                   "%s: creating %s\n", program_name, archive_filename);
+
+       inarch = &bogus_archive;
+       inarch->filename = archive_filename;
+       inarch->has_armap = true;
+
+    }
+    else {
+       inarch = bfd_openr(archive_filename, NULL);
+       if (inarch == NULL) {
+    bloser:
+           bfd_perror(archive_filename);
+           exit(1);
+       }
+
+       if (bfd_check_format(inarch, bfd_archive) != true)
+           fatal("File %s is not an archive.", archive_filename);
+       last_one = &(inarch->next);
+       /* Read all the contents right away, regardless. */
+       for (next_one = bfd_openr_next_archived_file(inarch, NULL);
+            next_one;
+            next_one = bfd_openr_next_archived_file(inarch, next_one)) {
+           *last_one = next_one;
+           last_one = &next_one->next;
+       }
+       *last_one = (bfd *) NULL;
+       if (bfd_error != no_more_archived_files)
+           goto bloser;
+    }
+}
+
+
+
+/*
+   If count is 0, then function is called once on each entry. if nonzero,
+   count is the length of the files chain; function is called on each entry
+   whose name matches one in files
+*/
+void
+map_over_members(function, files, count)
+    void            (*function) ();
+    char          **files;
+    int             count;
+{
+    bfd            *head;
+
+
+
+
+    if (count == 0) {
+       for (head = inarch->next; head; head = head->next)
+           function(head);
+       return;
+    }
+    /*
+       This may appear to be a baroque way of accomplishing what we want.
+       however we have to iterate over the filenames in order to notice where
+       a filename is requested but does not exist in the archive.  Ditto
+       mapping over each file each time -- we want to hack multiple
+       references.
+    */
+
+    for (; count > 0; files++, count--) {
+       boolean         found = false;
+       for (head = inarch->next; head; head = head->next)
+           if ((head->filename != NULL) &&
+               (!strcmp(*files, head->filename))) {
+               found = true;
+               function(head);
+           }
+       if (!found)
+           fprintf(stderr, "No entry %s in archive.\n", *files);
+    }
+}
+
+
+/* Things which are interesting to map over all or some of the files: */
+
+void
+print_descr(abfd)
+    bfd            *abfd;
+{
+    print_arelt_descr(abfd, verbose);
+}
+
+void
+print_contents(abfd)
+    bfd            *abfd;
+{
+    int             ncopied = 0;
+    struct stat     buf;
+    long            size;
+    if (bfd_stat_arch_elt(abfd, &buf) != 0)
+       fatal("Internal stat error on %s", abfd->filename);
+
+    if (verbose)
+       printf("\n<member %s>\n\n", abfd->filename);
+
+    bfd_seek(abfd, 0, SEEK_SET);
+
+    size = buf.st_size;
+    while (ncopied < size) {
+       char            cbuf[BUFSIZE];
+       int             nread;
+       int             tocopy = size - ncopied;
+       if (tocopy > BUFSIZE)
+           tocopy = BUFSIZE;
+
+       nread = bfd_read(cbuf, 1, tocopy, abfd);        /* oops -- broke
+                                                          abstraction!  */
+
+       if (nread != tocopy)
+           fatal("file %s not a valid archive", abfd->my_archive->filename);
+       fwrite(cbuf, 1, nread, stdout);
+       ncopied += tocopy;
+    }
+}
+
+
+/*
+   Extract a member of the archive into its own file.
+
+We defer opening the new file until after we have read a BUFSIZ chunk of the
+   old one, since we know we have just read the archive header for the old
+   one.  Since most members are shorter than BUFSIZ, this means we will read
+   the old header, read the old data, write a new inode for the new file, and
+   write the new data, and be done. This 'optimization' is what comes from
+   sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
+   Gilmore
+*/
+
+void
+extract_file(abfd)
+    bfd            *abfd;
+{
+    FILE           *ostream;
+    char            cbuf[BUFSIZE];
+    int             nread,
+                    tocopy;
+    int             ncopied = 0;
+    long            size;
+    struct stat     buf;
+    if (bfd_stat_arch_elt(abfd, &buf) != 0)
+       fatal("Internal stat error on %s", abfd->filename);
+    size = buf.st_size;
+
+    if (verbose)
+       printf("x - %s\n", abfd->filename);
+
+    bfd_seek(abfd, 0, SEEK_SET);
+
+    ostream = 0;
+    while (ncopied < size) {
+       tocopy = size - ncopied;
+       if (tocopy > BUFSIZE)
+           tocopy = BUFSIZE;
+
+       nread = bfd_read(cbuf, 1, tocopy, abfd);
+       if (nread != tocopy)
+           fatal("file %s not a valid archive", abfd->my_archive->filename);
+
+       /* See comment above; this saves disk arm motion */
+       if (!ostream) {
+           /* Seems like an abstraction violation, eh?  Well it's OK! */
+           ostream = fopen(abfd->filename, "w");
+           if (!ostream) {
+               perror(abfd->filename);
+               exit(1);
+           }
+       }
+       /* no need to byte-swap; the two formats are presumably compatible(!) */
+       fwrite(cbuf, 1, nread, ostream);
+       ncopied += tocopy;
+    }
+
+    fclose(ostream);
+    chmod(abfd->filename, buf.st_mode);
+
+    if (preserve_dates) {
+#ifdef USG
+       long            tb[2];
+       tb[0] = buf.st_mtime;
+       tb[1] = buf.st_mtime;
+       utime(abfd->filename, tb);      /* FIXME check result */
+#else
+       struct timeval  tv[2];
+       tv[0].tv_sec = buf.st_mtime;
+       tv[0].tv_usec = 0;
+       tv[1].tv_sec = buf.st_mtime;
+       tv[1].tv_usec = 0;
+       utimes(abfd->filename, tv);     /* FIXME check result */
+#endif
+    }
+}
+
+
+/* Just do it quickly; don't worry about dups, armap, or anything like that */
+
+/* This is ugly! XXX */
+
+PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (char *filename));
+
+void
+do_quick_append(archive_filename, files_to_append)
+    char           *archive_filename;
+    char          **files_to_append;
+
+{
+    FILE           *ofile,
+                   *ifile;
+    char            buf[BUFSIZE];
+    long            tocopy,
+                    thistime;
+    bfd            *temp;
+    struct stat     sbuf;
+    boolean         newfile = false;
+    bfd_error = no_error;
+
+    if (stat(archive_filename, &sbuf) != 0) {
+       if (errno != ENOENT)
+           bfd_fatal(archive_filename);
+       newfile = true;
+    }
+
+
+    ofile = fopen(archive_filename, "a+");
+    if (ofile == NULL) {
+       perror(program_name);
+       exit(1);
+    }
+
+    /* bletch */
+    temp = bfd_openr(archive_filename, NULL);
+    if (temp == NULL) {
+       bfd_perror(archive_filename);
+       exit(1);
+    }
+    if (newfile == false) {
+       if (bfd_check_format(temp, bfd_archive) != true)
+           fatal("File %s is not an archive.", archive_filename);
+    }
+    else {
+       fwrite(ARMAG, 1, SARMAG, ofile);
+       if (!silent_create)
+           fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
+    }
+
+    /* assume it's an achive, go straight to the end, sans $200 */
+    fseek(ofile, 0, 2);
+
+    for (; files_to_append && *files_to_append; ++files_to_append) {
+       struct ar_hdr  *hdr = bfd_special_undocumented_glue(*files_to_append);
+       if (hdr == NULL) {
+           bfd_perror(*files_to_append);
+           exit(1);
+       }
+
+       BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
+
+       ifile = fopen(*files_to_append, "r");
+       if (ifile == NULL)
+           bfd_perror(program_name);
+
+       if (stat(*files_to_append, &sbuf) != 0)
+           bfd_perror(*files_to_append);
+
+       tocopy = sbuf.st_size;
+
+       /* XXX should do error-checking! */
+       fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
+
+
+       while (tocopy > 0) {
+           thistime = tocopy;
+           if (thistime > BUFSIZE)
+               thistime = BUFSIZE;
+           fread(buf, 1, thistime, ifile);
+           fwrite(buf, 1, thistime, ofile);
+           tocopy -= thistime;
+       }
+       fclose(ifile);
+       if ((sbuf.st_size % 2) == 1)
+           putc('\n', ofile);
+    }
+    fclose(ofile);
+    bfd_close(temp);
+}
+
+
+void
+write_archive()
+{
+    bfd            *obfd;
+    char           *xmalloc();
+    int             namelen = strlen(inarch->filename);
+    char           *new_name = xmalloc(namelen + 6);
+    bfd            *contents_head = inarch->next;
+    if (inarch == &bogus_archive) {
+       /* How can this be ? */
+       return;
+    }
+    else {
+
+       strcpy(new_name, inarch->filename);
+       strcpy(new_name + namelen, ".art");
+       obfd = bfd_openw(new_name, bfd_get_target(inarch));
+
+       if (obfd == NULL)
+           bfd_fatal(inarch->filename);
+
+       bfd_set_format(obfd, bfd_archive);
+       obfd->has_armap = write_armap;
+
+       if (bfd_set_archive_head(obfd, contents_head) != true)
+           bfd_fatal(inarch->filename);
+
+       if (!bfd_close(obfd))
+           bfd_fatal(inarch->filename);
+       if (rename(new_name, inarch->filename) != 0)
+           bfd_fatal(inarch->filename);
+    }
+}
+
+
+
+/*
+   returns a pointer to the pointer to the entry which should be rplacd'd
+   into when altering.  default_pos should be how to interpret pos_default,
+   and should be a pos value.
+*/
+
+bfd **
+get_pos_bfd(contents, default_pos)
+    bfd           **contents;
+    enum pos        default_pos;
+{
+    bfd           **after_bfd;
+
+    enum pos        realpos = (postype == pos_default ? default_pos : postype);
+    switch (realpos) {
+
+    case pos_end:
+       after_bfd = contents;
+       while (*after_bfd) {
+           after_bfd = &((*after_bfd)->next);
+       }
+
+       break;
+#if 0
+    case pos_after:
+       for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
+           if (!strcpy(after_bfd->filename, posname))
+               break;
+       break;
+    case pos_before:
+       for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
+           if (after_bfd->next && (!strcpy(after_bfd->next->filename, posname)))
+               break;
+#endif
+    }
+
+    return after_bfd;
+}
+
+
+void
+delete_members(files_to_delete)
+    char          **files_to_delete;
+{
+    bfd           **current_ptr_ptr;
+    boolean         found;
+    boolean         something_changed = false;
+    for (; *files_to_delete != NULL; ++files_to_delete) {
+       /*
+          In a.out systems, the armap is optional.  It's also called
+          __.SYMDEF.  So if the user asked to delete it, we should remember
+          that fact. The name is NULL in COFF archives, so using this as a
+          key is as good as anything I suppose
+       */
+       if (!strcmp(*files_to_delete, "__.SYMDEF")) {
+           inarch->has_armap = false;
+           write_armap = false;
+           continue;
+       }
+
+       found = false;
+       current_ptr_ptr = &(inarch->next);
+       while (*current_ptr_ptr) {
+           if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
+               found = true;
+               something_changed = true;
+               if (verbose)
+                   printf("d - %s\n",
+                          *files_to_delete);
+               *current_ptr_ptr = ((*current_ptr_ptr)->next);
+               goto next_file;
+
+           }
+           else {
+               current_ptr_ptr = &((*current_ptr_ptr)->next);
+           }
+       }
+
+       if (verbose && found == false) {
+           printf("No member named `%s'\n", *files_to_delete);
+       }
+next_file:;
+
+    }
+
+    if (something_changed == true) {
+       write_archive();
+    }
+}
+
+
+/* Reposition existing members within an archive */
+
+void
+move_members(files_to_move)
+    char          **files_to_move;
+{
+    bfd           **after_bfd; /* New entries go after this one */
+    bfd           **current_ptr_ptr;   /* cdr pointer into contents */
+
+
+
+
+    for (; *files_to_move; ++files_to_move) {
+       current_ptr_ptr = &(inarch->next);
+       while (*current_ptr_ptr) {
+           bfd            *current_ptr = *current_ptr_ptr;
+           if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
+               /*
+                  Move this file to the end of the list - first cut from
+                  where it is.
+               */
+               *current_ptr_ptr = current_ptr->next;
+
+               /* Now glue to end */
+               after_bfd = get_pos_bfd(&inarch->next, pos_end);
+               *after_bfd = current_ptr;
+               current_ptr->next = (bfd *) NULL;
+
+               if (verbose)
+                   printf("m - %s\n", *files_to_move);
+
+               goto next_file;
+           }
+           current_ptr_ptr = &((*current_ptr_ptr)->next);
+       }
+       fprintf(stderr, "No entry %s in archive %s!\n",
+               *files_to_move, inarch->filename);
+       exit(1);
+next_file:;
+    }
+
+    write_archive();
+}
+
+
+/* Ought to default to replacing in place, but this is existing practice! */
+
+void
+replace_members(files_to_move)
+    char          **files_to_move;
+{
+    bfd           **after_bfd; /* New entries go after this one */
+    bfd            *current;
+    bfd           **current_ptr;
+    bfd            *temp;
+    /*
+       If the first item in the archive is an __.SYMDEF then remove it
+    */
+    if (inarch->next &&
+       strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
+       inarch->next = inarch->next->next;
+    }
+
+
+
+    while (files_to_move && *files_to_move) {
+       current_ptr = &inarch->next;
+       while (*current_ptr) {
+           current = *current_ptr;
+           
+           if (!strcmp(normalize(*files_to_move), current->filename)) {
+               /* snip out this entry from the chain */
+               *current_ptr = current->next;
+               if (newer_only) {
+                   struct stat     fsbuf,
+                                   asbuf;
+                   if (stat(*files_to_move, &fsbuf) != 0) {
+                       if (errno != ENOENT)
+                           bfd_fatal(*files_to_move);
+                       goto next_file;
+                   }
+                   if (bfd_stat_arch_elt(current, &asbuf) != 0)
+                       fatal("Internal stat error on %s", current->filename);
+
+                   if (fsbuf.st_mtime <= asbuf.st_mtime)
+                       goto next_file;
+               }
+
+
+               after_bfd = get_pos_bfd(&inarch->next, pos_end);
+               temp = *after_bfd;
+               *after_bfd = bfd_openr(*files_to_move, NULL);
+               if (*after_bfd == (bfd *) NULL) {
+                   fprintf(stderr, "Can't open file %s\n", *files_to_move);
+                   exit(1);
+               }
+               (*after_bfd)->next = temp;
+
+               if (verbose) {
+                   printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
+                          *files_to_move);
+               }
+               goto next_file;
+           }
+           current_ptr = &(current->next);
+       }
+
+       /* It isn't in there, so add to end */
+
+       after_bfd = get_pos_bfd(&inarch->next, pos_end);
+       temp = *after_bfd;
+       *after_bfd = bfd_openr(*files_to_move, NULL);
+       if (*after_bfd == (bfd *) NULL) {
+           fprintf(stderr, "Can't open file %s\n", *files_to_move);
+           exit(1);
+       }
+       if (verbose) {
+           printf("c - %s\n", *files_to_move);
+       }
+
+       (*after_bfd)->next = temp;
+
+next_file:;
+
+       files_to_move++;
+    }
+
+
+    write_archive();
+}
+
+void
+ranlib_only(archname)
+    char           *archname;
+{
+    write_armap = true;
+    open_inarch(archname);
+    write_archive();
+    exit(0);
+}
diff --git a/binutils/bucomm.c b/binutils/bucomm.c
new file mode 100644 (file)
index 0000000..00f379f
--- /dev/null
@@ -0,0 +1,151 @@
+/*** bucomm.c -- Bin Utils COMmon code.
+
+     We might put this in a library someday so it could be dynamically
+     loaded, but for now it's not necessary */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include <varargs.h>
+
+char *target = NULL;           /* default as late as possible */
+
+/* Yes, this is what atexit is for, but that isn't guaranteed yet.
+   And yes, I know this isn't as good, but it does what is needed just fine */
+void (*exit_handler) ();
+\f
+/** Memory hackery */
+
+PROTO (char *, malloc, (unsigned size));
+PROTO (char *, realloc, (char *ptr, unsigned size));
+
+\f
+/* Error reporting */
+
+char *program_name;
+
+void
+bfd_fatal (string)
+     char *string;
+{
+  char *errmsg =  bfd_errmsg (bfd_error);
+  
+  if (string)
+    fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
+  else
+    fprintf (stderr, "%s: %s\n", program_name, errmsg);
+
+  if (NULL != exit_handler) (*exit_handler) ();
+  exit (1);
+}
+
+#ifndef NO_STDARG
+void
+fatal (Format)
+     const char *Format;
+{
+  va_list args;
+       
+  va_start (args, Format);
+  vfprintf (stderr, Format, args);
+  va_end (args);
+  (void) putc ('\n', stderr);
+  if (NULL != exit_handler) (*exit_handler) ();
+  exit (1);
+}
+#else
+#ifndef NO_VARARGS
+void fatal (va_alist)
+     va_dcl
+{
+       char *Format;
+       va_list args;
+       
+       va_start (args);
+       Format = va_arg(args, char *);
+       vfprintf (stderr, Format, args);
+       va_end (args);
+       (void) putc ('\n', stderr);
+       if (NULL != exit_handler) (*exit_handler) ();
+       exit (1);
+} /* fatal() */
+#else
+/*VARARGS1 */
+fatal (Format, args)
+     char *Format;
+{
+  as_where ();
+  _doprnt (Format, &args, stderr); /* not terribly portable, but... */
+  (void) putc ('\n', stderr);
+  if (NULL != exit_handler) (*exit_handler) ();
+  exit (1);
+}
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+\f
+/** Display the archive header for an element as if it were an ls -l listing */
+
+/* Mode       User\tGroup\tSize\tDate               Name */
+
+void
+print_arelt_descr (abfd, verbose)
+     bfd *abfd;
+     boolean verbose;
+{
+  struct stat buf;
+  char modebuf[11];
+  char timebuf[40];
+  long when;
+  long current_time = time ((long *) 0);
+
+  if (verbose) {
+
+    if (bfd_stat_arch_elt (abfd, &buf) == 0) { /* if not, huh? */
+
+      mode_string (buf.st_mode, modebuf);
+      modebuf[10] = '\0';
+      fputs (modebuf, stdout);
+
+      when = buf.st_mtime;
+      strcpy (timebuf, ctime (&when));
+
+      /* This code comes from gnu ls.  */
+      if ((current_time - when > 6 * 30 * 24 * 60 * 60)
+         || (current_time - when < 0)) {
+       /* The file is fairly old or in the future.
+          POSIX says the cutoff is 6 months old;
+          approximate this by 6*30 days.
+          Show the year instead of the time of day.  */
+       strcpy (timebuf + 11, timebuf + 19);
+      }
+      timebuf[16] = 0;
+
+      printf (" %d\t%d\t%ld\t%s ", buf.st_uid, buf.st_gid, buf.st_size, timebuf);
+    }
+  }
+
+  puts (abfd->filename);
+}
+
+/* Like malloc but get fatal error if memory is exhausted.  */
+char *
+xmalloc (size)
+     unsigned size;
+{
+  register char *result = malloc (size);
+  if (result == NULL && size != NULL) fatal ("virtual memory exhausted");
+
+  return result;
+}
+
+/* Like realloc but get fatal error if memory is exhausted.  */
+char *
+xrealloc (ptr, size)
+     char *ptr;
+     unsigned size;
+{
+  register char *result = realloc (ptr, size);
+  if (result == 0 && size != 0) fatal ("virtual memory exhausted");
+
+  return result;
+}
diff --git a/binutils/filemode.c b/binutils/filemode.c
new file mode 100644 (file)
index 0000000..1bb5e64
--- /dev/null
@@ -0,0 +1,193 @@
+/* filemode.c -- make a string describing file modes
+   Copyright (C) 1985, 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.  */
+\f
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+   representation of the st_mode field of file stats block STATP.
+   10 characters are stored in STR; no terminating null is added.
+   The characters stored in STR are:
+
+   0   File type.  'd' for directory, 'c' for character
+       special, 'b' for block special, 'm' for multiplex,
+       'l' for symbolic link, 's' for socket, 'p' for fifo,
+       '-' for any other file type
+
+   1   'r' if the owner may read, '-' otherwise.
+
+   2   'w' if the owner may write, '-' otherwise.
+
+   3   'x' if the owner may execute, 's' if the file is
+       set-user-id, '-' otherwise.
+       'S' if the file is set-user-id, but the execute
+       bit isn't set.
+
+   4   'r' if group members may read, '-' otherwise.
+
+   5   'w' if group members may write, '-' otherwise.
+
+   6   'x' if group members may execute, 's' if the file is
+       set-group-id, '-' otherwise.
+       'S' if it is set-group-id but not executable.
+
+   7   'r' if any user may read, '-' otherwise.
+
+   8   'w' if any user may write, '-' otherwise.
+
+   9   'x' if any user may execute, 't' if the file is "sticky"
+       (will be retained in swap space after execution), '-'
+       otherwise.
+       'T' if the file is sticky but not executable. */
+
+void
+filemodestring (statp, str)
+     struct stat *statp;
+     char *str;
+{
+  mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+   is given as an argument. */
+
+void
+mode_string (mode, str)
+     unsigned short mode;
+     char *str;
+{
+  str[0] = ftypelet (mode);
+  rwx ((mode & 0700) << 0, &str[1]);
+  rwx ((mode & 0070) << 3, &str[4]);
+  rwx ((mode & 0007) << 6, &str[7]);
+  setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+   file mode BITS:
+   'd' for directories
+   'b' for block special files
+   'c' for character special files
+   'm' for multiplexor files
+   'l' for symbolic links
+   's' for sockets
+   'p' for fifos
+   '-' for any other file type. */
+
+static char
+ftypelet (bits)
+     unsigned short bits;
+{
+  switch (bits & S_IFMT)
+    {
+    default:
+      return '-';
+    case S_IFDIR:
+      return 'd';
+#ifdef S_IFLNK
+    case S_IFLNK:
+      return 'l';
+#endif
+#ifdef S_IFCHR
+    case S_IFCHR:
+      return 'c';
+#endif
+#ifdef S_IFBLK
+    case S_IFBLK:
+      return 'b';
+#endif
+#ifdef S_IFMPC
+    case S_IFMPC:
+    case S_IFMPB:
+      return 'm';
+#endif
+#ifdef S_IFSOCK
+    case S_IFSOCK:
+      return 's';
+#endif
+#ifdef S_IFIFO
+#if S_IFIFO != S_IFSOCK
+    case S_IFIFO:
+      return 'p';
+#endif
+#endif
+#ifdef S_IFNWK                 /* HP-UX */
+    case S_IFNWK:
+      return 'n';
+#endif
+    }
+}
+
+/* Look at read, write, and execute bits in BITS and set
+   flags in CHARS accordingly. */
+
+static void
+rwx (bits, chars)
+     unsigned short bits;
+     char *chars;
+{
+  chars[0] = (bits & S_IREAD) ? 'r' : '-';
+  chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+  chars[2] = (bits & S_IEXEC) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+   according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+     unsigned short bits;
+     char *chars;
+{
+#ifdef S_ISUID
+  if (bits & S_ISUID)
+    {
+      if (chars[3] != 'x')
+       /* Set-uid, but not executable by owner. */
+       chars[3] = 'S';
+      else
+       chars[3] = 's';
+    }
+#endif
+#ifdef S_ISGID
+  if (bits & S_ISGID)
+    {
+      if (chars[6] != 'x')
+       /* Set-gid, but not executable by group. */
+       chars[6] = 'S';
+      else
+       chars[6] = 's';
+    }
+#endif
+#ifdef S_ISVTX
+  if (bits & S_ISVTX)
+    {
+      if (chars[9] != 'x')
+       /* Sticky, but not executable by others. */
+       chars[9] = 'T';
+      else
+       chars[9] = 't';
+    }
+#endif
+}
+
+
diff --git a/binutils/i960-pinsn.c b/binutils/i960-pinsn.c
new file mode 100644 (file)
index 0000000..1c7b719
--- /dev/null
@@ -0,0 +1,820 @@
+/* Disassemble i80960 instructions.
+ */
+
+/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Diddler.
+
+BFD 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.
+
+BFD 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 BFD; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ 
+   $Log
+*/
+#include <stdio.h>
+#include "sysdep.h"
+#include "bfd.h"
+
+extern char *xmalloc();
+extern int fputs();
+
+static char *reg_names[] = {
+/*  0 */       "pfp", "sp",  "rip", "r3",  "r4",  "r5",  "r6",  "r7", 
+/*  8 */       "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+/* 16 */       "g0",  "g1",  "g2",  "g3",  "g4",  "g5",  "g6",  "g7", 
+/* 24 */       "g8",  "g9",  "g10", "g11", "g12", "g13", "g14", "fp", 
+/* 32 */       "pc",  "ac",  "ip",  "tc",  "fp0", "fp1", "fp2", "fp3" 
+};
+
+
+static FILE *stream;           /* Output goes here */
+static void print_addr();
+static void ctrl();
+static void cobr();
+static void reg();
+static int mem();
+static void ea();
+static void dstop();
+static void regop();
+static void invalid();
+static int pinsn();
+static void put_abs();
+
+
+/* Print the i960 instruction at address 'memaddr' in debugged memory,
+ * on stream 's'.  Returns length of the instruction, in bytes.
+ */
+int
+print_insn_i960( memaddr, buffer, s )
+    bfd_vma memaddr;
+uint8e_type *buffer;
+    FILE *s;
+{
+    unsigned int word1, word2;
+
+    stream = s;
+    word1 =buffer [0] |( buffer[1]<< 8) | (buffer[2] << 16) | ( buffer[3] <<24);
+    word2 =buffer [4] |( buffer[5]<< 8) | (buffer[6] << 16) | ( buffer[7] <<24);
+    return pinsn( memaddr, word1, word2 );
+}
+\f
+#define IN_GDB
+
+/*****************************************************************************
+ *     All code below this point should be identical with that of
+ *     the disassembler in gdmp960.
+ *****************************************************************************/
+
+struct tabent {
+       char    *name;
+       char    numops;
+};
+
+static int
+pinsn( memaddr, word1, word2 )
+    unsigned long memaddr;
+    unsigned long word1, word2;
+{
+       int instr_len;
+
+       instr_len = 4;
+       put_abs( word1, word2 );
+
+       /* Divide instruction set into classes based on high 4 bits of opcode*/
+       switch ( (word1 >> 28) & 0xf ){
+       case 0x0:
+       case 0x1:
+               ctrl( memaddr, word1, word2 );
+               break;
+       case 0x2:
+       case 0x3:
+               cobr( memaddr, word1, word2 );
+               break;
+       case 0x5:
+       case 0x6:
+       case 0x7:
+               reg( word1 );
+               break;
+       case 0x8:
+       case 0x9:
+       case 0xa:
+       case 0xb:
+       case 0xc:
+               instr_len = mem( memaddr, word1, word2, 0 );
+               break;
+       default:
+               /* invalid instruction, print as data word */ 
+               invalid( word1 );
+               break;
+       }
+       return instr_len;
+}
+
+/****************************************/
+/* CTRL format                         */
+/****************************************/
+static void
+ctrl( memaddr, word1, word2 )
+    unsigned long memaddr;
+    unsigned long word1, word2;
+{
+       int i;
+       static struct tabent ctrl_tab[] = {
+               NULL,           0,      /* 0x00 */
+               NULL,           0,      /* 0x01 */
+               NULL,           0,      /* 0x02 */
+               NULL,           0,      /* 0x03 */
+               NULL,           0,      /* 0x04 */
+               NULL,           0,      /* 0x05 */
+               NULL,           0,      /* 0x06 */
+               NULL,           0,      /* 0x07 */
+               "b",            1,      /* 0x08 */
+               "call",         1,      /* 0x09 */
+               "ret",          0,      /* 0x0a */
+               "bal",          1,      /* 0x0b */
+               NULL,           0,      /* 0x0c */
+               NULL,           0,      /* 0x0d */
+               NULL,           0,      /* 0x0e */
+               NULL,           0,      /* 0x0f */
+               "bno",          1,      /* 0x10 */
+               "bg",           1,      /* 0x11 */
+               "be",           1,      /* 0x12 */
+               "bge",          1,      /* 0x13 */
+               "bl",           1,      /* 0x14 */
+               "bne",          1,      /* 0x15 */
+               "ble",          1,      /* 0x16 */
+               "bo",           1,      /* 0x17 */
+               "faultno",      0,      /* 0x18 */
+               "faultg",       0,      /* 0x19 */
+               "faulte",       0,      /* 0x1a */
+               "faultge",      0,      /* 0x1b */
+               "faultl",       0,      /* 0x1c */
+               "faultne",      0,      /* 0x1d */
+               "faultle",      0,      /* 0x1e */
+               "faulto",       0,      /* 0x1f */
+       };
+
+       i = (word1 >> 24) & 0xff;
+       if ( (ctrl_tab[i].name == NULL) || ((word1 & 1) != 0) ){
+               invalid( word1 );
+               return;
+       }
+
+       fputs( ctrl_tab[i].name, stream );
+       if ( word1 & 2 ){               /* Predicts branch not taken */
+               fputs( ".f", stream );
+       }
+
+       if ( ctrl_tab[i].numops == 1 ){
+               /* EXTRACT DISPLACEMENT AND CONVERT TO ADDRESS */
+               word1 &= 0x00ffffff;
+               if ( word1 & 0x00800000 ){              /* Sign bit is set */
+                       word1 |= (-1 & ~0xffffff);      /* Sign extend */
+               }
+               putc( '\t', stream );
+               print_addr( word1 + memaddr );
+       }
+}
+
+/****************************************/
+/* COBR format                         */
+/****************************************/
+static void
+cobr( memaddr, word1, word2 )
+    unsigned long memaddr;
+    unsigned long word1, word2;
+{
+       int src1;
+       int src2;
+       int i;
+
+       static struct tabent cobr_tab[] = {
+               "testno",       1,      /* 0x20 */
+               "testg",        1,      /* 0x21 */
+               "teste",        1,      /* 0x22 */
+               "testge",       1,      /* 0x23 */
+               "testl",        1,      /* 0x24 */
+               "testne",       1,      /* 0x25 */
+               "testle",       1,      /* 0x26 */
+               "testo",        1,      /* 0x27 */
+               NULL,           0,      /* 0x28 */
+               NULL,           0,      /* 0x29 */
+               NULL,           0,      /* 0x2a */
+               NULL,           0,      /* 0x2b */
+               NULL,           0,      /* 0x2c */
+               NULL,           0,      /* 0x2d */
+               NULL,           0,      /* 0x2e */
+               NULL,           0,      /* 0x2f */
+               "bbc",          3,      /* 0x30 */
+               "cmpobg",       3,      /* 0x31 */
+               "cmpobe",       3,      /* 0x32 */
+               "cmpobge",      3,      /* 0x33 */
+               "cmpobl",       3,      /* 0x34 */
+               "cmpobne",      3,      /* 0x35 */
+               "cmpoble",      3,      /* 0x36 */
+               "bbs",          3,      /* 0x37 */
+               "cmpibno",      3,      /* 0x38 */
+               "cmpibg",       3,      /* 0x39 */
+               "cmpibe",       3,      /* 0x3a */
+               "cmpibge",      3,      /* 0x3b */
+               "cmpibl",       3,      /* 0x3c */
+               "cmpibne",      3,      /* 0x3d */
+               "cmpible",      3,      /* 0x3e */
+               "cmpibo",       3,      /* 0x3f */
+       };
+
+       i = ((word1 >> 24) & 0xff) - 0x20;
+       if ( cobr_tab[i].name == NULL ){
+               invalid( word1 );
+               return;
+       }
+
+       fputs( cobr_tab[i].name, stream );
+       if ( word1 & 2 ){               /* Predicts branch not taken */
+               fputs( ".f", stream );
+       }
+       putc( '\t', stream );
+
+       src1 = (word1 >> 19) & 0x1f;
+       src2 = (word1 >> 14) & 0x1f;
+
+       if ( word1 & 0x02000 ){         /* M1 is 1 */
+               fprintf( stream, "%d", src1 );
+       } else {                        /* M1 is 0 */
+               fputs( reg_names[src1], stream );
+       }
+
+       if ( cobr_tab[i].numops > 1 ){
+               if ( word1 & 1 ){               /* S2 is 1 */
+                       fprintf( stream, ",sf%d,", src2 );
+               } else {                        /* S1 is 0 */
+                       fprintf( stream, ",%s,", reg_names[src2] );
+               }
+
+               /* Extract displacement and convert to address
+                */
+               word1 &= 0x00001ffc;
+               if ( word1 & 0x00001000 ){      /* Negative displacement */
+                       word1 |= (-1 & ~0x1fff);        /* Sign extend */
+               }
+               print_addr( memaddr + word1 );
+       }
+}
+
+/****************************************/
+/* MEM format                          */
+/****************************************/
+static int                             /* returns instruction length: 4 or 8 */
+mem( memaddr, word1, word2, noprint )
+    unsigned long memaddr;
+    unsigned long word1, word2;
+    int noprint;               /* If TRUE, return instruction length, but
+                                * don't output any text.
+                                */
+{
+       int i, j;
+       int len;
+       int mode;
+       int offset;
+       char *reg1, *reg2, *reg3;
+
+       /* This lookup table is too sparse to make it worth typing in, but not
+        * so large as to make a sparse array necessary.  We allocate the
+        * table at runtime, initialize all entries to empty, and copy the
+        * real ones in from an initialization table.
+        *
+        * NOTE: In this table, the meaning of 'numops' is:
+        *       1: single operand
+        *       2: 2 operands, load instruction
+        *      -2: 2 operands, store instruction
+        */
+       static struct tabent *mem_tab = NULL;
+       static struct { int opcode; char *name; char numops; } mem_init[] = {
+#define MEM_MIN        0x80
+               0x80,   "ldob",  2,
+               0x82,   "stob", -2,
+               0x84,   "bx",    1,
+               0x85,   "balx",  2,
+               0x86,   "callx", 1,
+               0x88,   "ldos",  2,
+               0x8a,   "stos", -2,
+               0x8c,   "lda",   2,
+               0x90,   "ld",    2,
+               0x92,   "st",   -2,
+               0x98,   "ldl",   2,
+               0x9a,   "stl",  -2,
+               0xa0,   "ldt",   2,
+               0xa2,   "stt",  -2,
+               0xb0,   "ldq",   2,
+               0xb2,   "stq",  -2,
+               0xc0,   "ldib",  2,
+               0xc2,   "stib", -2,
+               0xc8,   "ldis",  2,
+               0xca,   "stis", -2,
+#define MEM_MAX        0xca
+#define MEM_SIZ        ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent))
+               0,      NULL,   0
+       };
+
+       if ( mem_tab == NULL ){
+               mem_tab = (struct tabent *) xmalloc( MEM_SIZ );
+               bzero( (void *) mem_tab, MEM_SIZ );
+               for ( i = 0; mem_init[i].opcode != 0; i++ ){
+                       j = mem_init[i].opcode - MEM_MIN;
+                       mem_tab[j].name = mem_init[i].name;
+                       mem_tab[j].numops = mem_init[i].numops;
+               }
+       }
+
+       i = ((word1 >> 24) & 0xff) - MEM_MIN;
+       mode = (word1 >> 10) & 0xf;
+
+       if ( (mem_tab[i].name != NULL)          /* Valid instruction */
+       &&   ((mode == 5) || (mode >=12)) ){    /* With 32-bit displacement */
+               len = 8;
+       } else {
+               len = 4;
+       }
+
+       if ( noprint ){
+               return len;
+       }
+
+       if ( (mem_tab[i].name == NULL) || (mode == 6) ){
+               invalid( word1 );
+               return len;
+       }
+
+       fprintf( stream, "%s\t", mem_tab[i].name );
+
+       reg1 = reg_names[ (word1 >> 19) & 0x1f ];       /* MEMB only */
+       reg2 = reg_names[ (word1 >> 14) & 0x1f ];
+       reg3 = reg_names[ word1 & 0x1f ];               /* MEMB only */
+       offset = word1 & 0xfff;                         /* MEMA only  */
+
+       switch ( mem_tab[i].numops ){
+
+       case 2: /* LOAD INSTRUCTION */
+               if ( mode & 4 ){                        /* MEMB FORMAT */
+                       ea( memaddr, mode, reg2, reg3, word1, word2 );
+                       fprintf( stream, ",%s", reg1 );
+               } else {                                /* MEMA FORMAT */
+                       fprintf( stream, "0x%x", (unsigned) offset );
+                       if (mode & 8) {
+                               fprintf( stream, "(%s)", reg2 );
+                       }
+                       fprintf( stream, ",%s", reg1 );
+               }
+               break;
+
+       case -2: /* STORE INSTRUCTION */
+               if ( mode & 4 ){                        /* MEMB FORMAT */
+                       fprintf( stream, "%s,", reg1 );
+                       ea( memaddr, mode, reg2, reg3, word1, word2 );
+               } else {                                /* MEMA FORMAT */
+                       fprintf( stream, "%s,0x%x", reg1, (unsigned) offset );
+                       if (mode & 8) {
+                               fprintf( stream, "(%s)", reg2 );
+                       }
+               }
+               break;
+
+       case 1: /* BX/CALLX INSTRUCTION */
+               if ( mode & 4 ){                        /* MEMB FORMAT */
+                       ea( memaddr, mode, reg2, reg3, word1, word2 );
+               } else {                                /* MEMA FORMAT */
+                       fprintf( stream, "0x%x", (unsigned) offset );
+                       if (mode & 8) {
+                               fprintf( stream, "(%s)", reg2 );
+                       }
+               }
+               break;
+       }
+
+       return len;
+}
+
+/****************************************/
+/* REG format                          */
+/****************************************/
+static void
+reg( word1 )
+    unsigned long word1;
+{
+       int i, j;
+       int opcode;
+       int fp;
+       int m1, m2, m3;
+       int s1, s2;
+       int src, src2, dst;
+       char *mnemp;
+
+       /* This lookup table is too sparse to make it worth typing in, but not
+        * so large as to make a sparse array necessary.  We allocate the
+        * table at runtime, initialize all entries to empty, and copy the
+        * real ones in from an initialization table.
+        *
+        * NOTE: In this table, the meaning of 'numops' is:
+        *       1: single operand, which is NOT a destination.
+        *      -1: single operand, which IS a destination.
+        *       2: 2 operands, the 2nd of which is NOT a destination.
+        *      -2: 2 operands, the 2nd of which IS a destination.
+        *       3: 3 operands
+        *
+        *      If an opcode mnemonic begins with "F", it is a floating-point
+        *      opcode (the "F" is not printed).
+        */
+
+       static struct tabent *reg_tab = NULL;
+       static struct { int opcode; char *name; char numops; } reg_init[] = {
+#define REG_MIN        0x580
+               0x580,  "notbit",       3,
+               0x581,  "and",          3,
+               0x582,  "andnot",       3,
+               0x583,  "setbit",       3,
+               0x584,  "notand",       3,
+               0x586,  "xor",          3,
+               0x587,  "or",           3,
+               0x588,  "nor",          3,
+               0x589,  "xnor",         3,
+               0x58a,  "not",          -2,
+               0x58b,  "ornot",        3,
+               0x58c,  "clrbit",       3,
+               0x58d,  "notor",        3,
+               0x58e,  "nand",         3,
+               0x58f,  "alterbit",     3,
+               0x590,  "addo",         3,
+               0x591,  "addi",         3,
+               0x592,  "subo",         3,
+               0x593,  "subi",         3,
+               0x598,  "shro",         3,
+               0x59a,  "shrdi",        3,
+               0x59b,  "shri",         3,
+               0x59c,  "shlo",         3,
+               0x59d,  "rotate",       3,
+               0x59e,  "shli",         3,
+               0x5a0,  "cmpo",         2,
+               0x5a1,  "cmpi",         2,
+               0x5a2,  "concmpo",      2,
+               0x5a3,  "concmpi",      2,
+               0x5a4,  "cmpinco",      3,
+               0x5a5,  "cmpinci",      3,
+               0x5a6,  "cmpdeco",      3,
+               0x5a7,  "cmpdeci",      3,
+               0x5ac,  "scanbyte",     2,
+               0x5ae,  "chkbit",       2,
+               0x5b0,  "addc",         3,
+               0x5b2,  "subc",         3,
+               0x5cc,  "mov",          -2,
+               0x5d8,  "eshro",        3,
+               0x5dc,  "movl",         -2,
+               0x5ec,  "movt",         -2,
+               0x5fc,  "movq",         -2,
+               0x600,  "synmov",       2,
+               0x601,  "synmovl",      2,
+               0x602,  "synmovq",      2,
+               0x603,  "cmpstr",       3,
+               0x604,  "movqstr",      3,
+               0x605,  "movstr",       3,
+               0x610,  "atmod",        3,
+               0x612,  "atadd",        3,
+               0x613,  "inspacc",      -2,
+               0x614,  "ldphy",        -2,
+               0x615,  "synld",        -2,
+               0x617,  "fill",         3,
+               0x630,  "sdma",         3,
+               0x631,  "udma",         0,
+               0x640,  "spanbit",      -2,
+               0x641,  "scanbit",      -2,
+               0x642,  "daddc",        3,
+               0x643,  "dsubc",        3,
+               0x644,  "dmovt",        -2,
+               0x645,  "modac",        3,
+               0x646,  "condrec",      -2,
+               0x650,  "modify",       3,
+               0x651,  "extract",      3,
+               0x654,  "modtc",        3,
+               0x655,  "modpc",        3,
+               0x656,  "receive",      -2,
+               0x659,  "sysctl",       3,
+               0x660,  "calls",        1,
+               0x662,  "send",         3,
+               0x663,  "sendserv",     1,
+               0x664,  "resumprcs",    1,
+               0x665,  "schedprcs",    1,
+               0x666,  "saveprcs",     0,
+               0x668,  "condwait",     1,
+               0x669,  "wait",         1,
+               0x66a,  "signal",       1,
+               0x66b,  "mark",         0,
+               0x66c,  "fmark",        0,
+               0x66d,  "flushreg",     0,
+               0x66f,  "syncf",        0,
+               0x670,  "emul",         3,
+               0x671,  "ediv",         3,
+               0x673,  "ldtime",       -1,
+               0x674,  "Fcvtir",       -2,
+               0x675,  "Fcvtilr",      -2,
+               0x676,  "Fscalerl",     3,
+               0x677,  "Fscaler",      3,
+               0x680,  "Fatanr",       3,
+               0x681,  "Flogepr",      3,
+               0x682,  "Flogr",        3,
+               0x683,  "Fremr",        3,
+               0x684,  "Fcmpor",       2,
+               0x685,  "Fcmpr",        2,
+               0x688,  "Fsqrtr",       -2,
+               0x689,  "Fexpr",        -2,
+               0x68a,  "Flogbnr",      -2,
+               0x68b,  "Froundr",      -2,
+               0x68c,  "Fsinr",        -2,
+               0x68d,  "Fcosr",        -2,
+               0x68e,  "Ftanr",        -2,
+               0x68f,  "Fclassr",      1,
+               0x690,  "Fatanrl",      3,
+               0x691,  "Flogeprl",     3,
+               0x692,  "Flogrl",       3,
+               0x693,  "Fremrl",       3,
+               0x694,  "Fcmporl",      2,
+               0x695,  "Fcmprl",       2,
+               0x698,  "Fsqrtrl",      -2,
+               0x699,  "Fexprl",       -2,
+               0x69a,  "Flogbnrl",     -2,
+               0x69b,  "Froundrl",     -2,
+               0x69c,  "Fsinrl",       -2,
+               0x69d,  "Fcosrl",       -2,
+               0x69e,  "Ftanrl",       -2,
+               0x69f,  "Fclassrl",     1,
+               0x6c0,  "Fcvtri",       -2,
+               0x6c1,  "Fcvtril",      -2,
+               0x6c2,  "Fcvtzri",      -2,
+               0x6c3,  "Fcvtzril",     -2,
+               0x6c9,  "Fmovr",        -2,
+               0x6d9,  "Fmovrl",       -2,
+               0x6e1,  "Fmovre",       -2,
+               0x6e2,  "Fcpysre",      3,
+               0x6e3,  "Fcpyrsre",     3,
+               0x701,  "mulo",         3,
+               0x708,  "remo",         3,
+               0x70b,  "divo",         3,
+               0x741,  "muli",         3,
+               0x748,  "remi",         3,
+               0x749,  "modi",         3,
+               0x74b,  "divi",         3,
+               0x78b,  "Fdivr",        3,
+               0x78c,  "Fmulr",        3,
+               0x78d,  "Fsubr",        3,
+               0x78f,  "Faddr",        3,
+               0x79b,  "Fdivrl",       3,
+               0x79c,  "Fmulrl",       3,
+               0x79d,  "Fsubrl",       3,
+               0x79f,  "Faddrl",       3,
+#define REG_MAX        0x79f
+#define REG_SIZ        ((REG_MAX-REG_MIN+1) * sizeof(struct tabent))
+               0,      NULL,   0
+       };
+
+       if ( reg_tab == NULL ){
+               reg_tab = (struct tabent *) xmalloc( REG_SIZ );
+               bzero( (void *) reg_tab, REG_SIZ );
+               for ( i = 0; reg_init[i].opcode != 0; i++ ){
+                       j = reg_init[i].opcode - REG_MIN;
+                       reg_tab[j].name = reg_init[i].name;
+                       reg_tab[j].numops = reg_init[i].numops;
+               }
+       }
+
+       opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf);
+       i = opcode - REG_MIN;
+
+       if ( (opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL) ){
+               invalid( word1 );
+               return;
+       }
+
+       mnemp = reg_tab[i].name;
+       if ( *mnemp == 'F' ){
+               fp = 1;
+               mnemp++;
+       } else {
+               fp = 0;
+       }
+
+       fputs( mnemp, stream );
+
+       s1   = (word1 >> 5)  & 1;
+       s2   = (word1 >> 6)  & 1;
+       m1   = (word1 >> 11) & 1;
+       m2   = (word1 >> 12) & 1;
+       m3   = (word1 >> 13) & 1;
+       src  =  word1        & 0x1f;
+       src2 = (word1 >> 14) & 0x1f;
+       dst  = (word1 >> 19) & 0x1f;
+
+       if  ( reg_tab[i].numops != 0 ){
+               putc( '\t', stream );
+
+               switch ( reg_tab[i].numops ){
+               case 1:
+                       regop( m1, s1, src, fp );
+                       break;
+               case -1:
+                       dstop( m3, dst, fp );
+                       break;
+               case 2:
+                       regop( m1, s1, src, fp );
+                       putc( ',', stream );
+                       regop( m2, s2, src2, fp );
+                       break;
+               case -2:
+                       regop( m1, s1, src, fp );
+                       putc( ',', stream );
+                       dstop( m3, dst, fp );
+                       break;
+               case 3:
+                       regop( m1, s1, src, fp );
+                       putc( ',', stream );
+                       regop( m2, s2, src2, fp );
+                       putc( ',', stream );
+                       dstop( m3, dst, fp );
+                       break;
+               }
+       }
+}
+
+
+/*
+ * Print out effective address for memb instructions.
+ */
+static void
+ea( memaddr, mode, reg2, reg3, word1, word2 )
+    unsigned long memaddr;
+    int mode;
+    char *reg2, *reg3;
+int word1;
+    unsigned int word2;
+{
+       int scale;
+       static int scale_tab[] = { 1, 2, 4, 8, 16 };
+
+       scale = (word1 >> 7) & 0x07;
+       if ( (scale > 4) || ((word1 >> 5) & 0x03 != 0) ){
+               invalid( word1 );
+               return;
+       }
+       scale = scale_tab[scale];
+
+       switch (mode) {
+       case 4:                                         /* (reg) */
+               fprintf( stream, "(%s)", reg2 );
+               break;
+       case 5:                                         /* displ+8(ip) */
+               print_addr( word2+8+memaddr );
+               break;
+       case 7:                                         /* (reg)[index*scale] */
+               if (scale == 1) {
+                       fprintf( stream, "(%s)[%s]", reg2, reg3 );
+               } else {
+                       fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale);
+               }
+               break;
+       case 12:                                        /* displacement */
+               print_addr( word2 );
+               break;
+       case 13:                                        /* displ(reg) */
+               print_addr( word2 );
+               fprintf( stream, "(%s)", reg2 );
+               break;
+       case 14:                                        /* displ[index*scale] */
+               print_addr( word2 );
+               if (scale == 1) {
+                       fprintf( stream, "[%s]", reg3 );
+               } else {
+                       fprintf( stream, "[%s*%d]", reg3, scale );
+               }
+               break;
+       case 15:                                /* displ(reg)[index*scale] */
+               print_addr( word2 );
+               if (scale == 1) {
+                       fprintf( stream, "(%s)[%s]", reg2, reg3 );
+               } else {
+                       fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale );
+               }
+               break;
+       default:
+               invalid( word1 );
+               return;
+       }
+}
+
+
+/************************************************/
+/* Register Instruction Operand                */
+/************************************************/
+static void
+regop( mode, spec, reg, fp )
+    int mode, spec, reg, fp;
+{
+       if ( fp ){                              /* FLOATING POINT INSTRUCTION */
+               if ( mode == 1 ){                       /* FP operand */
+                       switch ( reg ){
+                       case 0:  fputs( "fp0", stream );        break;
+                       case 1:  fputs( "fp1", stream );        break;
+                       case 2:  fputs( "fp2", stream );        break;
+                       case 3:  fputs( "fp3", stream );        break;
+                       case 16: fputs( "0f0.0", stream );      break;
+                       case 22: fputs( "0f1.0", stream );      break;
+                       default: putc( '?', stream );           break;
+                       }
+               } else {                                /* Non-FP register */
+                       fputs( reg_names[reg], stream );
+               }
+       } else {                                /* NOT FLOATING POINT */
+               if ( mode == 1 ){                       /* Literal */
+                       fprintf( stream, "%d", reg );
+               } else {                                /* Register */
+                       if ( spec == 0 ){
+                               fputs( reg_names[reg], stream );
+                       } else {
+                               fprintf( stream, "sf%d", reg );
+                       }
+               }
+       }
+}
+
+/************************************************/
+/* Register Instruction Destination Operand    */
+/************************************************/
+static void
+dstop( mode, reg, fp )
+    int mode, reg, fp;
+{
+       /* 'dst' operand can't be a literal. On non-FP instructions,  register
+        * mode is assumed and "m3" acts as if were "s3";  on FP-instructions,
+        * sf registers are not allowed so m3 acts normally.
+        */
+        if ( fp ){
+               regop( mode, 0, reg, fp );
+        } else {
+               regop( 0, mode, reg, fp );
+        }
+}
+
+
+static void
+invalid( word1 )
+    int word1;
+{
+       fprintf( stream, ".word\t0x%08x", (unsigned) word1 );
+}      
+
+static void
+print_addr(a)
+int a;
+{
+       fprintf( stream, "0x%x", (unsigned) a );
+}
+
+static void
+put_abs( word1, word2 )
+    unsigned long word1, word2;
+{
+#ifdef IN_GDB
+       return;
+#else
+       int len;
+
+       switch ( (word1 >> 28) & 0xf ){
+       case 0x8:
+       case 0x9:
+       case 0xa:
+       case 0xb:
+       case 0xc:
+               /* MEM format instruction */
+               len = mem( 0, word1, word2, 1 );
+               break;
+       default:
+               len = 4;
+               break;
+       }
+
+       if ( len == 8 ){
+               fprintf( stream, "%08x %08x\t", word1, word2 );
+       } else {
+               fprintf( stream, "%08x         \t", word1 );
+       }
+;
+
+#endif
+}
diff --git a/binutils/m68k-pinsn.c b/binutils/m68k-pinsn.c
new file mode 100644 (file)
index 0000000..284f335
--- /dev/null
@@ -0,0 +1,806 @@
+/* Print m68k instructions for objdump
+   Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+
+This file is part of the binutils.
+
+The binutils are 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 binutils are distributed in the hope that they 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 binutils; see the file COPYING.  If not, write to
+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  1991/03/13  00:34:06  chrisb
+ * Initial revision
+ *
+ * Revision 1.4  1991/03/09  04:36:34  rich
+ *  Modified Files:
+ *     sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
+ *     binutils.h
+ *
+ * Pulled sysdep.h out of bfd.h.
+ *
+ * Revision 1.3  1991/03/08  21:54:45  rich
+ *  Modified Files:
+ *     Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
+ *     i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
+ *     sparc-pinsn.c strip.c
+ *
+ * Verifying Portland tree with steve's last changes.  Also, some partial
+ * porting.
+ *
+ * Revision 1.2  1991/03/08  07:46:24  sac
+ * Added -l option to disassembly - prints line numbers too.
+ *
+ * Revision 1.1  1991/02/22  16:48:02  sac
+ * Initial revision
+ *
+*/
+
+#include <stdio.h>
+#include "sysdep.h"
+#include "bfd.h"
+#include "m68k-opcode.h"
+
+extern int fputs();
+extern void print_address();
+
+/* 68k instructions are never longer than this many bytes.  */
+#define MAXLEN 22
+
+/* Number of elements in the opcode table.  */
+#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
+
+extern char *reg_names[];
+char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
+                    "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
+
+char *reg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"};
+static unsigned char *print_insn_arg ();
+static unsigned char *print_indexed ();
+static void print_base ();
+static int fetch_arg ();
+
+#define NEXTBYTE(p)  (p += 2, ((char *)p)[-1])
+
+#define NEXTWORD(p)  \
+  (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
+
+#define NEXTLONG(p)  \
+  (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
+
+#define NEXTSINGLE(p) \
+  (p += 4, *((float *)(p - 4)))
+
+#define NEXTDOUBLE(p) \
+  (p += 8, *((double *)(p - 8)))
+
+#define NEXTEXTEND(p) \
+  (p += 12, 0.0)       /* Need a function to convert from extended to double
+                          precision... */
+
+#define NEXTPACKED(p) \
+  (p += 12, 0.0)       /* Need a function to convert from packed to double
+                          precision.   Actually, it's easier to print a
+                          packed number than a double anyway, so maybe
+                          there should be a special case to handle this... */
+\f
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+   on STREAM.  Returns length of the instruction, in bytes.  */
+
+int
+print_insn_m68k(addr, buffer, stream)
+     bfd_vma addr;
+unsigned    char *buffer;
+     FILE *stream;
+{
+  register unsigned int i;
+  register unsigned char *p;
+  register char *d;
+  register unsigned int bestmask;
+  int best;
+
+
+
+  bestmask = 0;
+  best = -1;
+  for (i = 0; i < NOPCODES; i++)
+    {
+      register unsigned int opcode = m68k_opcodes[i].opcode;
+      register unsigned int match = m68k_opcodes[i].match;
+      if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
+         && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
+         && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+         && ((0xff & buffer[3] & match) == (0xff & opcode)))
+       {
+         /* Don't use for printout the variants of divul and divsl
+            that have the same register number in two places.
+            The more general variants will match instead.  */
+         for (d = m68k_opcodes[i].args; *d; d += 2)
+           if (d[1] == 'D')
+             break;
+
+         /* Don't use for printout the variants of most floating
+            point coprocessor instructions which use the same
+            register number in two places, as above. */
+         if (*d == 0)
+           for (d = m68k_opcodes[i].args; *d; d += 2)
+             if (d[1] == 't')
+               break;
+
+         if (*d == 0 && match > bestmask)
+           {
+             best = i;
+             bestmask = match;
+           }
+       }
+    }
+
+  /* Handle undefined instructions.  */
+  if (best < 0)
+    {
+      fprintf (stream, "0%o", (unsigned) (buffer[0] << 8) + buffer[1]);
+      return 2;
+    }
+
+  fprintf (stream, "%s", m68k_opcodes[best].name);
+
+  /* Point at first word of argument data,
+     and at descriptor for first argument.  */
+  p = buffer + 2;
+  
+  /* Why do this this way? -MelloN */
+  for (d = m68k_opcodes[best].args; *d; d += 2)
+    {
+      if (d[0] == '#')
+       {
+         if (d[1] == 'l' && p - buffer < 6)
+           p = buffer + 6;
+         else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
+           p = buffer + 4;
+       }
+      if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
+       p = buffer + 4;
+      if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
+       p = buffer + 6;
+      if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
+       p = buffer + 4;
+    }
+
+  d = m68k_opcodes[best].args;
+
+  if (*d)
+    fputs (" ", stream);
+
+  while (*d)
+    {
+      p = print_insn_arg (d, buffer, p, addr + p - buffer, stream);
+      d += 2;
+      if (*d && *(d - 2) != 'I' && *d != 'k')
+       fputs (",", stream);
+    }
+  return p - buffer;
+}
+
+static unsigned char *
+print_insn_arg (d, buffer, p, addr, stream)
+     char *d;
+     unsigned char *buffer;
+     register unsigned char *p;
+ bfd_vma addr;         /* PC for this arg to be relative to */
+     FILE *stream;
+{
+  register int val;
+  register int place = d[1];
+  int regno;
+  register char *regname;
+  register unsigned char *p1;
+  register double flval;
+  int flt_p;
+
+  switch (*d)
+    {
+    case 'C':
+      fprintf (stream, "ccr");
+      break;
+
+    case 'S':
+      fprintf (stream, "sr");
+      break;
+
+    case 'U':
+      fprintf (stream, "usp");
+      break;
+
+    case 'J':
+      {
+       static struct { char *name; int value; } names[]
+         = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
+            {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
+            {"msp", 0x803}, {"isp", 0x804}};
+
+       val = fetch_arg (buffer, place, 12);
+       for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+         if (names[regno].value == val)
+           {
+             fprintf (stream, names[regno].name);
+             break;
+           }
+       if (regno < 0)
+         fprintf (stream, "%d", val);
+      }
+      break;
+
+    case 'Q':
+      val = fetch_arg (buffer, place, 3);
+      if (val == 0) val = 8;
+      fprintf (stream, "#%d", val);
+      break;
+
+    case 'M':
+      val = fetch_arg (buffer, place, 8);
+      if (val & 0x80)
+       val = val - 0x100;
+      fprintf (stream, "#%d", val);
+      break;
+
+    case 'T':
+      val = fetch_arg (buffer, place, 4);
+      fprintf (stream, "#%d", val);
+      break;
+
+    case 'D':
+      fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
+      break;
+
+    case 'A':
+      fprintf (stream, "%s",
+                       reg_names[fetch_arg (buffer, place, 3) + 010]);
+      break;
+
+    case 'R':
+      fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
+      break;
+
+    case 'F':
+      fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
+      break;
+
+    case 'O':
+      val = fetch_arg (buffer, place, 6);
+      if (val & 0x20)
+       fprintf (stream, "%s", reg_names [val & 7]);
+      else
+       fprintf (stream, "%d", val);
+      break;
+
+    case '+':
+      fprintf (stream, "%s@+",
+                       reg_names[fetch_arg (buffer, place, 3) + 8]);
+      break;
+
+    case '-':
+      fprintf (stream, "%s@-",
+              reg_names[fetch_arg (buffer, place, 3) + 8]);
+      break;
+
+    case 'k':
+      if (place == 'k')
+       fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
+      else if (place == 'C')
+       {
+         val = fetch_arg (buffer, place, 7);
+         if ( val > 63 )               /* This is a signed constant. */
+           val -= 128;
+         fprintf (stream, "{#%d}", val);
+       }
+      else
+       fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+              *d, place);
+      break;
+
+    case '#':
+    case '^':
+      p1 = buffer + (*d == '#' ? 2 : 4);
+      if (place == 's')
+       val = fetch_arg (buffer, place, 4);
+      else if (place == 'C')
+       val = fetch_arg (buffer, place, 7);
+      else if (place == '8')
+       val = fetch_arg (buffer, place, 3);
+      else if (place == '3')
+       val = fetch_arg (buffer, place, 8);
+      else if (place == 'b')
+       val = NEXTBYTE (p1);
+      else if (place == 'w')
+       val = NEXTWORD (p1);
+      else if (place == 'l')
+       val = NEXTLONG (p1);
+      else
+       fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+              *d, place);
+      fprintf (stream, "#%d", val);
+      break;
+
+    case 'B':
+      if (place == 'b')
+       val = NEXTBYTE (p);
+      else if (place == 'w')
+       val = NEXTWORD (p);
+      else if (place == 'l')
+       val = NEXTLONG (p);
+      else if (place == 'g')
+       {
+         val = ((char *)buffer)[1];
+         if (val == 0)
+           val = NEXTWORD (p);
+         else if (val == -1)
+           val = NEXTLONG (p);
+       }
+      else if (place == 'c')
+       {
+         if (buffer[1] & 0x40)         /* If bit six is one, long offset */
+           val = NEXTLONG (p);
+         else
+           val = NEXTWORD (p);
+       }
+      else
+       fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+              *d, place);
+      print_address (addr + val, stream);
+      break;
+
+    case 'd':
+      val = NEXTWORD (p);
+      fprintf (stream, "%s@(%d)",
+                       reg_names[fetch_arg (buffer, place, 3)], val);
+      break;
+
+    case 's':
+      fprintf (stream, "%s",
+                       fpcr_names[fetch_arg (buffer, place, 3)]);
+      break;
+
+    case 'I':
+      val = fetch_arg (buffer, 'd', 3);                  /* Get coprocessor ID... */
+      if (val != 1)                            /* Unusual coprocessor ID? */
+       fprintf (stream, "(cpid=%d) ", val);
+      if (place == 'i')
+       p += 2;                      /* Skip coprocessor extended operands */
+      break;
+
+    case '*':
+    case '~':
+    case '%':
+    case ';':
+    case '@':
+    case '!':
+    case '$':
+    case '?':
+    case '/':
+    case '&':
+
+      if (place == 'd')
+       {
+         val = fetch_arg (buffer, 'x', 6);
+         val = ((val & 7) << 3) + ((val >> 3) & 7);
+       }
+      else
+       val = fetch_arg (buffer, 's', 6);
+
+      /* Get register number assuming address register.  */
+      regno = (val & 7) + 8;
+      regname = reg_names[regno];
+      switch (val >> 3)
+       {
+       case 0:
+         fprintf (stream, "%s", reg_names[val]);
+         break;
+
+       case 1:
+         fprintf (stream, "%s", regname);
+         break;
+
+       case 2:
+         fprintf (stream, "%s@", regname);
+         break;
+
+       case 3:
+         fprintf (stream, "%s@+", regname);
+         break;
+
+       case 4:
+         fprintf (stream, "%s@-", regname);
+         break;
+
+       case 5:
+         val = NEXTWORD (p);
+         fprintf (stream, "%s@(%d)", regname, val);
+         break;
+
+       case 6:
+         p = print_indexed (regno, p, addr, stream);
+         break;
+
+       case 7:
+         switch (val & 7)
+           {
+           case 0:
+             val = NEXTWORD (p);
+             fprintf (stream, "@#");
+             print_address (val, stream);
+             break;
+
+           case 1:
+             val = NEXTLONG (p);
+             fprintf (stream, "@#");
+             print_address (val, stream);
+             break;
+
+           case 2:
+             val = NEXTWORD (p);
+             print_address (addr + val, stream);
+             break;
+
+           case 3:
+             p = print_indexed (-1, p, addr, stream);
+             break;
+
+           case 4:
+             flt_p = 1;        /* Assume it's a float... */
+             switch( place )
+             {
+               case 'b':
+                 val = NEXTBYTE (p);
+                 flt_p = 0;
+                 break;
+
+               case 'w':
+                 val = NEXTWORD (p);
+                 flt_p = 0;
+                 break;
+
+               case 'l':
+                 val = NEXTLONG (p);
+                 flt_p = 0;
+                 break;
+
+               case 'f':
+                 flval = NEXTSINGLE(p);
+                 break;
+
+               case 'F':
+                 flval = NEXTDOUBLE(p);
+                 break;
+
+               case 'x':
+                 flval = NEXTEXTEND(p);
+                 break;
+
+               case 'p':
+                 flval = NEXTPACKED(p);
+                 break;
+
+               default:
+                 fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+                      *d, place);
+             }
+             if ( flt_p )      /* Print a float? */
+               fprintf (stream, "#%g", flval);
+             else
+               fprintf (stream, "#%d", val);
+             break;
+
+           default:
+             fprintf (stream, "<invalid address mode 0%o>", (unsigned) val);
+           }
+       }
+      break;
+
+    case 'L':
+    case 'l':
+       if (place == 'w')
+         {
+           char doneany;
+           p1 = buffer + 2;
+           val = NEXTWORD (p1);
+           /* Move the pointer ahead if this point is farther ahead
+              than the last.  */
+           p = p1 > p ? p1 : p;
+           if (val == 0)
+             {
+               fputs ("#0", stream);
+               break;
+             }
+           if (*d == 'l')
+             {
+               register int newval = 0;
+               for (regno = 0; regno < 16; ++regno)
+                 if (val & (0x8000 >> regno))
+                   newval |= 1 << regno;
+               val = newval;
+             }
+           val &= 0xffff;
+           doneany = 0;
+           for (regno = 0; regno < 16; ++regno)
+             if (val & (1 << regno))
+               {
+                 int first_regno;
+                 if (doneany)
+                   fputs ("/", stream);
+                 doneany = 1;
+                 fprintf (stream, "%s", reg_names[regno]);
+                 first_regno = regno;
+                 while (val & (1 << (regno + 1)))
+                   ++regno;
+                 if (regno > first_regno)
+                   fprintf (stream, "-%s", reg_names[regno]);
+               }
+         }
+       else if (place == '3')
+         {
+           /* `fmovem' insn.  */
+           char doneany;
+           val = fetch_arg (buffer, place, 8);
+           if (val == 0)
+             {
+               fputs ("#0", stream);
+               break;
+             }
+           if (*d == 'l')
+             {
+               register int newval = 0;
+               for (regno = 0; regno < 8; ++regno)
+                 if (val & (0x80 >> regno))
+                   newval |= 1 << regno;
+               val = newval;
+             }
+           val &= 0xff;
+           doneany = 0;
+           for (regno = 0; regno < 8; ++regno)
+             if (val & (1 << regno))
+               {
+                 int first_regno;
+                 if (doneany)
+                   fputs ("/", stream);
+                 doneany = 1;
+                 fprintf (stream, "fp%d", regno);
+                 first_regno = regno;
+                 while (val & (1 << (regno + 1)))
+                   ++regno;
+                 if (regno > first_regno)
+                   fprintf (stream, "-fp%d", regno);
+               }
+         }
+       else
+         abort ();
+      break;
+
+    default:
+      fprintf(stderr, "Invalid arg format in opcode table: \"%c\".", *d);
+    }
+
+  return (unsigned char *) p;
+}
+
+/* Fetch BITS bits from a position in the instruction specified by CODE.
+   CODE is a "place to put an argument", or 'x' for a destination
+   that is a general address (mode and register).
+   BUFFER contains the instruction.  */
+
+static int
+fetch_arg (buffer, code, bits)
+     unsigned char *buffer;
+     char code;
+     int bits;
+{
+  register int val;
+  switch (code)
+    {
+    case 's':
+      val = buffer[1];
+      break;
+
+    case 'd':                  /* Destination, for register or quick.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 9;
+      break;
+
+    case 'x':                  /* Destination, for general arg */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 6;
+      break;
+
+    case 'k':
+      val = (buffer[3] >> 4);
+      break;
+
+    case 'C':
+      val = buffer[3];
+      break;
+
+    case '1':
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 12;
+      break;
+
+    case '2':
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 6;
+      break;
+
+    case '3':
+    case 'j':
+      val = (buffer[2] << 8) + buffer[3];
+      break;
+
+    case '4':
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 12;
+      break;
+
+    case '5':
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 6;
+      break;
+
+    case '6':
+      val = (buffer[4] << 8) + buffer[5];
+      break;
+
+    case '7':
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 7;
+      break;
+      
+    case '8':
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 10;
+      break;
+
+    default:
+      abort ();
+    }
+
+  switch (bits)
+    {
+    case 3:
+      return val & 7;
+    case 4:
+      return val & 017;
+    case 5:
+      return val & 037;
+    case 6:
+      return val & 077;
+    case 7:
+      return val & 0177;
+    case 8:
+      return val & 0377;
+    case 12:
+      return val & 07777;
+    default:
+      abort ();
+      return(0);
+    }
+} /* fetch_arg() */
+
+/* Print an indexed argument.  The base register is BASEREG (-1 for pc).
+   P points to extension word, in buffer.
+   ADDR is the nominal core address of that extension word.  */
+
+static unsigned char *
+print_indexed (basereg, p, addr, stream)
+     int basereg;
+     unsigned char *p;
+     FILE *stream;
+bfd_vma addr;
+{
+  register int word;
+  static char *scales[] = {"", "*2", "*4", "*8"};
+  register int base_disp;
+  register int outer_disp;
+  char buf[40];
+
+  word = NEXTWORD (p);
+
+  /* Generate the text for the index register.
+     Where this will be output is not yet determined.  */
+  sprintf (buf, "[%s.%c%s]",
+          reg_names[(word >> 12) & 0xf],
+          (word & 0x800) ? 'l' : 'w',
+          scales[(word >> 9) & 3]);
+
+  /* Handle the 68000 style of indexing.  */
+
+  if ((word & 0x100) == 0)
+    {
+      print_base (basereg,
+                 ((word & 0x80) ? word | 0xff00 : word & 0xff)
+                 + ((basereg == -1) ? addr : 0),
+                 stream);
+      fputs (buf, stream);
+      return p;
+    }
+
+  /* Handle the generalized kind.  */
+  /* First, compute the displacement to add to the base register.  */
+
+  if (word & 0200)
+    basereg = -2;
+  if (word & 0100)
+    buf[0] = 0;
+  base_disp = 0;
+  switch ((word >> 4) & 3)
+    {
+    case 2:
+      base_disp = NEXTWORD (p);
+      break;
+    case 3:
+      base_disp = NEXTLONG (p);
+    }
+  if (basereg == -1)
+    base_disp += addr;
+
+  /* Handle single-level case (not indirect) */
+
+  if ((word & 7) == 0)
+    {
+      print_base (basereg, base_disp, stream);
+      fputs (buf, stream);
+      return p;
+    }
+
+  /* Two level.  Compute displacement to add after indirection.  */
+
+  outer_disp = 0;
+  switch (word & 3)
+    {
+    case 2:
+      outer_disp = NEXTWORD (p);
+      break;
+    case 3:
+      outer_disp = NEXTLONG (p);
+    }
+
+  fprintf (stream, "%d(", outer_disp);
+  print_base (basereg, base_disp, stream);
+
+  /* If postindexed, print the closeparen before the index.  */
+  if (word & 4)
+    fprintf (stream, ")%s", buf);
+  /* If preindexed, print the closeparen after the index.  */
+  else
+    fprintf (stream, "%s)", buf);
+
+  return p;
+}
+
+/* Print a base register REGNO and displacement DISP, on STREAM.
+   REGNO = -1 for pc, -2 for none (suppressed).  */
+
+static void
+print_base (regno, disp, stream)
+     int regno;
+     int disp;
+     FILE *stream;
+{
+  if (regno == -2)
+    fprintf (stream, "%d", disp);
+  else if (regno == -1)
+    fprintf (stream, "0x%x", (unsigned) disp);
+  else
+    fprintf (stream, "%d(%s)", disp, reg_names[regno]);
+}
diff --git a/binutils/nm.c b/binutils/nm.c
new file mode 100644 (file)
index 0000000..ac490f7
--- /dev/null
@@ -0,0 +1,387 @@
+/*** nm.c -- Describe symbol table of a rel file. */
+#include "sysdep.h"
+#include "bfd.h"
+#include "getopt.h"
+#include "stab.gnu.h"
+#include <ranlib.h>
+
+
+
+PROTO(static boolean, display_file, (char *filename));
+PROTO(static boolean, do_one_rel_file, (bfd *file));
+PROTO(static unsigned int, filter_symbols, (bfd *file, asymbol **syms,
+                                        unsigned long symcount));
+
+PROTO(static void, print_symbols, (bfd *file, asymbol **syms,
+                                    unsigned long symcount));
+extern PROTO(int, (*sorters[2][2]), (char *x, char *y));
+PROTO(static void, print_symdef_entry, (bfd * abfd));
+
+/* Command options.  */
+
+int external_only = 0; /* print external symbols only */
+int file_on_each_line = 0; /* print file name on each line */
+int no_sort = 0;       /* don't sort; print syms in order found */
+int print_debug_syms = 0; /* print debugger-only symbols too */
+int print_armap = 0;   /* describe __.SYMDEF data in archive files.  */
+int reverse_sort = 0;  /* sort in downward(alpha or numeric) order */
+int sort_numerically = 0; /* sort in numeric rather than alpha order */
+int undefined_only = 0;        /* print undefined symbols only */
+
+boolean print_each_filename = false; /* Ick.  Used in archives. */
+
+/* IMPORT */
+extern char *program_name;
+extern char *program_version;
+extern char *target;
+
+struct option long_options[] = {
+       {"debug-syms",      0, &print_debug_syms,  1},
+       {"extern-only",     0, &external_only,     1},
+       {"no-sort",         0, &no_sort,           1},
+       {"numeric-sort",    0, &sort_numerically,  1},
+       {"print-armap",     0, &print_armap,       1},
+       {"print-file-name", 0, &file_on_each_line, 1},
+       {"reverse-sort",    0, &reverse_sort,      1},
+       {"target",          2, NULL,               NULL},
+       {"undefined-only",  0, &undefined_only,    1},
+       {0, 0, 0, 0}
+};
+\f
+/* Some error-reporting functions */
+
+void
+usage ()
+{
+  fprintf(stderr, "nm %s\nUsage: %s [-agnoprsu] filename...\n",
+         program_version, program_name);
+  exit(0);
+}
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c; /* sez which option char */
+  int ind = 0; /* used by getopt and ignored by us */
+  extern int optind; /* steps thru options */
+       
+  program_name = *argv;
+       
+  while ((c = getopt_long(argc, argv, "agnoprsu", long_options, &ind)) != EOF) {
+    switch (c) {
+    case 'a': print_debug_syms = 1; break;
+    case 'g': external_only = 1; break;
+    case 'n': sort_numerically = 1; break;
+    case 'o': file_on_each_line = 1; break;
+    case 'p': no_sort = 1; break;
+    case 'r': reverse_sort = 1; break;
+    case 's': print_armap = 1; break;
+    case 'u': undefined_only = 1; break;
+                       
+    case  0:
+      if (!strcmp("target",(long_options[option_index]).name)) {
+       target = optarg;
+      }
+                       
+      break; /* we've been given a long option */
+                       
+    default:
+      usage ();
+    }
+  }
+       
+  /* Strangely, for the shell you should return only a nonzero value
+     on sucess -- the inverse of the C sense. */
+  
+  /* OK, all options now parsed.  If no filename specified, do a.out. */
+  if (optind == argc) return !display_file ("a.out");
+  
+  /* We were given several filenames to do: */
+  while (optind < argc)
+    if (!display_file (argv[optind++])) return 1;
+
+  return 0;
+}
+\f
+/** Display a file's stats */
+
+/* goto here is marginally cleaner than the nested if syntax */
+
+static boolean
+display_file (filename)
+     char *filename;
+{
+  boolean retval = false;
+  bfd *file;
+  bfd *arfile = NULL;
+       
+  file = bfd_openr(filename, target);
+  if (file == NULL) {
+    bfd_fatal (filename);
+  }
+
+  if (bfd_check_format(file, bfd_object)) {
+    retval = do_one_rel_file (file);
+    goto closer;
+  }
+
+  if (!bfd_check_format (file, bfd_archive)) {
+    fprintf (stderr, "%s:  %s: unknown format.\n", program_name, filename);
+    retval = false;
+    goto closer;
+  }
+
+  printf("In archive %s:\n", filename);
+  if (print_armap) print_symdef_entry (file);
+  for (;;) {
+    arfile = bfd_openr_next_archived_file (file, arfile);
+
+    if (arfile == NULL) {
+      if (bfd_error != no_more_archived_files)
+       bfd_fatal (filename);
+      goto closer;
+    }
+                       
+    if (!bfd_check_format(arfile, bfd_object))
+      printf("%s: not an object file\n", arfile->filename);
+    else {
+      printf ("\n%s:\n", arfile->filename);
+      if (!do_one_rel_file (arfile)) return false;
+    }
+  }
+
+ closer:
+  if (bfd_close(file) == false)
+    bfd_fatal (filename);
+
+  return retval;
+}
+\f
+
+static boolean
+do_one_rel_file (abfd)
+     bfd *abfd;
+{
+  unsigned int storage;
+  asymbol **syms;
+  unsigned int symcount = 0;
+
+  if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
+    (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
+    return true;
+  }
+
+      
+  storage = get_symtab_upper_bound (abfd);
+  if (storage == 0) {
+  nosymz:
+    fprintf (stderr, "%s: Symflags set but there are none?\n",
+            bfd_get_filename (abfd));
+    exit (1);
+  }
+
+  syms = (asymbol **) xmalloc (storage);
+
+  symcount = bfd_canonicalize_symtab (abfd, syms);
+  if (symcount == 0) goto nosymz;
+
+  /* Discard the symbols we don't want to print.
+     It's OK to do this in place; we'll free the storage anyway
+     (after printing) */
+
+  symcount = filter_symbols (abfd, syms, symcount);
+       
+  if (!no_sort) 
+    qsort((char *) syms, symcount, sizeof (asymbol *),
+         sorters[sort_numerically][reverse_sort]);
+
+  if (print_each_filename && !file_on_each_line)
+    printf("\n%s:\n", bfd_get_filename(abfd));
+       
+  print_symbols (abfd, syms, symcount);
+  free (syms);
+  return true;
+}
+\f
+/* Symbol-sorting predicates */
+#define valueof(x)  ((x)->section ? (x)->section->vma + (x)->value : (x)->value)
+int
+numeric_forward (x, y)
+     char *x;
+     char *y;
+{
+
+  return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));;
+}
+
+int
+numeric_reverse (x, y)
+     char *x;
+     char *y;
+{
+  return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x));
+
+}
+
+int
+non_numeric_forward (x, y)
+     char *x;
+     char *y;
+{
+  char *xn = (*(asymbol **) x)->name;
+  char *yn = (*(asymbol **) y)->name;
+
+  return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) :
+         ((yn == NULL) ? 1 : strcmp (xn, yn)));
+}
+
+int
+non_numeric_reverse (x, y)
+     char *x;
+     char *y;
+{
+  return -(non_numeric_forward (x, y));
+}
+
+int (*sorters[2][2])() = {
+       {non_numeric_forward, non_numeric_reverse},
+       {numeric_forward, numeric_reverse},
+};
+\f
+
+/* Choose which symbol entries to print;
+   compact them downward to get rid of the rest.
+   Return the number of symbols to be printed.  */
+static unsigned int
+filter_symbols (abfd, syms, symcount)
+     bfd *abfd;
+     asymbol **syms;
+     unsigned long symcount;
+{
+  asymbol **from, **to;
+  unsigned int dst_count = 0;
+  unsigned int src_count;
+  for (from = to = syms, src_count = 0; src_count <symcount; src_count++) {
+    int keep = 0;
+    flagword flags = (from[src_count])->flags;
+
+    if (undefined_only) {
+      keep = (flags & BSF_UNDEFINED);
+    } else if (external_only) {
+      keep = ((flags & BSF_GLOBAL) || (flags & BSF_UNDEFINED) ||
+             (flags & BSF_FORT_COMM));
+    } else {
+      keep = 1;
+    }
+               
+    if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) {
+      keep = 0;
+    }
+
+    if (keep) {
+      to[dst_count++] = from[src_count];
+    }
+  }
+       
+  return dst_count;
+}
+\f
+
+/* Return a lower-case character corresponding to the symbol class of sym */
+char
+decode_symclass (sym)
+     asymbol *sym;
+{
+  flagword flags = sym->flags;
+  
+  if ((sym->value == 0) && (sym->section != NULL))
+    /* Huh?  All section names don't begin with "." */
+    return (sym->section->name)[1];
+
+  if (flags & BSF_FORT_COMM) return 'C';
+  if (flags & BSF_UNDEFINED) return 'U';
+  if (flags & BSF_ABSOLUTE)  return 'a';
+
+   if ( (flags & BSF_GLOBAL) || (flags & BSF_LOCAL) ){
+     if ( !strcmp(sym->section->name, ".text") ){
+       return 't';
+     } else if ( !strcmp(sym->section->name, ".data") ){
+       return 'd';
+     } else if ( !strcmp(sym->section->name, ".bss") ){
+       return 'b';
+     } else {
+       return 'o';
+     }
+    }
+
+  /* We don't have to handle these cases just yet, but we will soon:
+     N_SETV: 'v'; 
+     N_SETA: 'l'; 
+     N_SETT: 'x';
+     N_SETD: 'z';
+     N_SETB: 's';
+     N_INDR: 'i';
+     */
+  return '?';
+}
+
+static void
+print_symbols (abfd, syms, symcount)
+     bfd *abfd;
+     asymbol **syms;
+     unsigned long symcount;
+{
+  asymbol **sym = syms, **end = syms + symcount;
+  char class;
+
+  for (; sym < end; ++sym) {
+    if (file_on_each_line) printf("%s:", bfd_get_filename(abfd));
+
+    if (undefined_only) {
+      if ((*sym)->flags & BSF_UNDEFINED)
+       puts ((*sym)->name);
+    }
+    else {
+      asymbol *p = *sym;
+      if (p) {
+      class = decode_symclass (p);
+
+      if (p->flags & BSF_GLOBAL)
+       class = toupper (class);
+      
+      if (p->value || ((p->flags & BSF_UNDEFINED) !=  BSF_UNDEFINED))
+       printf ("%08lx ", (p->section ? p->value + p->section->vma : p->value));
+      else fputs ("         ", stdout);
+
+      printf ("%c %s\n", class, p->name);
+    }
+    }
+  }
+}
+
+static void
+print_symdef_entry (abfd)
+     bfd * abfd;
+{
+  symindex idx = BFD_NO_MORE_SYMBOLS;
+  carsym *thesym;
+  boolean everprinted = false;
+
+  for (idx = bfd_get_next_mapent (abfd, idx, &thesym);
+       idx != BFD_NO_MORE_SYMBOLS;
+       idx = bfd_get_next_mapent (abfd, idx, &thesym)) {
+    bfd *elt;
+    if (!everprinted) {
+      printf ("\nArchive index:\n");
+      everprinted = true;
+    }
+    elt = bfd_get_elt_at_index (abfd, idx);
+    if (thesym->name != (char *)NULL) {
+    printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
+}
+  }
+}
diff --git a/binutils/objdump.c b/binutils/objdump.c
new file mode 100644 (file)
index 0000000..352adc3
--- /dev/null
@@ -0,0 +1,714 @@
+/*** objdump.c -- dump information about an object file. */
+
+/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Diddler.
+
+BFD 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.
+
+BFD 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 BFD; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* 
+   $Id$
+   $Log$
+   Revision 1.1  1991/03/21 21:26:48  gumby
+   Initial revision
+
+ * Revision 1.2  1991/03/15  18:34:14  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:34:19  chrisb
+ * Initial revision
+ *
+ * Revision 1.9  1991/03/09  04:36:33  rich
+ *  Modified Files:
+ *     sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
+ *     binutils.h
+ *
+ * Pulled sysdep.h out of bfd.h.
+ *
+ * Revision 1.8  1991/03/09  03:42:01  rich
+ *  Modified Files:
+ *     Makefile alloca.c ar.c i960-pinsn.c nm.c objdump.c ostrip.c
+ *     strip.c
+ *
+ * Ports for intel960 group Portland.
+ *
+ * Revision 1.7  1991/03/08  21:54:47  rich
+ *  Modified Files:
+ *     Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
+ *     i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
+ *     sparc-pinsn.c strip.c
+ *
+ * Verifying Portland tree with steve's last changes.  Also, some partial
+ * porting.
+ *
+ * Revision 1.6  1991/03/08  07:46:26  sac
+ * Added -l option to disassembly - prints line numbers too.
+ *
+ * Revision 1.5  1991/03/07  21:50:24  sac
+ * More intelligent reloc printing
+ *
+ * Revision 1.4  1991/03/05  16:36:54  sac
+ * Fixed bug where empty symbols would print (null) on suns and crash elsewhere.
+ *
+*/
+/*
+ * Until there is other documentation, refer to the manual page dump(1) in
+ * the system 5 program's reference manual
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "getopt.h"
+#include <stdio.h>
+#include <ctype.h>
+
+char *malloc();
+char *realloc();
+char *xmalloc();
+
+char *default_target = NULL;   /* default at runtime */
+
+char *program_name = NULL;
+
+int dump_section_contents;     /* -s */
+int dump_section_headers;      /* -h */
+boolean dump_file_header;      /* -f */
+int dump_symtab;               /* -t */
+int dump_reloc_info;           /* -r */
+int dump_ar_hdrs;              /* -a */
+int with_line_numbers;          /* -l */
+boolean disassemble;             /* -d */
+char *only;
+
+PROTO (void, display_file, (char *filename, char *target));
+PROTO (void, dump_data, (bfd *abfd));
+PROTO (void, dump_relocs, (bfd *abfd));
+PROTO (void, dump_symbols, (bfd *abfd));
+PROTO (void, print_arelt_descr, (bfd *abfd, boolean verbose));
+
+
+
+
+
+
+\f
+char *machine = (char *)NULL;
+  asymbol **syms;
+  asymbol **syms2;
+
+
+unsigned int storage;
+
+unsigned int symcount = 0;
+
+void
+usage ()
+{
+  fprintf (stderr,
+          "usage: %s [-ahfdrtxsl] [-m machine] [-j section_name] obj ...\n",
+          program_name);
+  exit (1);
+}
+
+static struct option long_options[] = 
+       {{"syms",   0, &dump_symtab,          1},
+        {"reloc",  0, &dump_reloc_info,      1},
+        {"header", 0, &dump_section_headers, 1},
+        {0, 0, 0, 0}};
+
+
+
+static void
+dump_headers(abfd)
+bfd *abfd;
+{
+  asection *section;
+  for (section = abfd->sections;
+       section != (asection *) NULL;
+       section = section->next) 
+    {
+      char *comma = "";
+#define PF(x,y) \
+      if (section->flags & x) {  printf("%s%s",comma,y); comma = ", "; }
+
+      printf("SECTION %d [%s]\t: size %08x",
+            section->index,
+            section->name,
+(unsigned)     section->size);
+      printf(" vma %08lx align 2**%2u\n ",
+            section->vma,
+            section->alignment_power);
+      PF(SEC_ALLOC,"ALLOC");
+      PF(SEC_LOAD,"LOAD");
+      PF(SEC_RELOC,"RELOC");
+      PF(SEC_BALIGN,"BALIGN");
+      PF(SEC_READONLY,"READONLY");
+      PF(SEC_CODE,"CODE");
+      PF(SEC_DATA,"DATA");
+      PF(SEC_ROM,"ROM");
+      printf("\n");
+#undef PF
+    }
+}
+
+static asymbol **
+slurp_symtab(abfd)
+bfd *abfd;
+{
+  asymbol **sy;
+  if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
+    (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
+    return(NULL);
+  }
+
+  storage = get_symtab_upper_bound (abfd);
+  if (storage) {
+    sy = (asymbol **) malloc (storage);
+    if (sy == NULL) {
+      fprintf (stderr, "%s: out of memory.\n", program_name);
+      exit (1);
+    }
+  }
+  symcount = bfd_canonicalize_symtab (abfd, sy);
+return sy;
+}
+/* Sort symbols into value order */
+static int comp(ap,bp)
+asymbol **ap;
+asymbol **bp;
+{
+  asymbol *a = *ap;
+  asymbol *b = *bp;
+  int diff;
+
+  if ( a->name== (char *)NULL || (a->flags &( BSF_DEBUGGING| BSF_UNDEFINED) )) 
+    a->the_bfd = 0;
+  if  ( b->name== (char *)NULL || (b->flags &( BSF_DEBUGGING|BSF_UNDEFINED))) 
+    b->the_bfd =0;
+
+  diff = a->the_bfd - b->the_bfd;
+  if (diff) {
+    return -diff;
+  }
+  diff = a->value - b->value;
+  if (diff) {
+    return diff;
+  }
+  return   a->section - b->section;
+}
+
+/* Print the supplied address symbolically if possible */
+void
+print_address(vma, stream)
+bfd_vma vma;
+FILE *stream;
+{
+  /* Perform a binary search looking for the closest symbol to
+     the required value */
+
+  unsigned int min = 0;
+  unsigned int max = symcount;
+
+  unsigned int thisplace = 1;
+  unsigned int oldthisplace ;
+
+  int vardiff;
+  if (symcount == 0)
+    fprintf(stream,"%08lx", vma);
+  else {
+    while (true) {
+      oldthisplace = thisplace;
+      thisplace = (max + min )/2  ;
+      if (thisplace == oldthisplace) break;
+
+
+       vardiff = syms[thisplace]->value - vma;
+
+      if (vardiff) {
+       if (vardiff > 0) {
+         max = thisplace;
+       }
+       else {
+         min = thisplace;
+       }
+      }
+      else {
+       /* Totally awesome! the exact right symbol */
+       fprintf(stream,"%08lx (%s)", vma, syms[thisplace]->name);
+       return;
+      }
+    }
+    /* We've run out of places to look, print the symbol before this one */
+    /* see if this or the symbol before describes this location the best */
+
+    if (thisplace != 0) {
+      if (syms[thisplace-1]->value - vma >
+         syms[thisplace]->value-vma) {
+       /* Previous symbol is in correct section and is closer */
+       thisplace --;
+      }
+    }
+    
+    {
+      char *section_name;
+      asection *sec = syms[thisplace]->section;
+      if (sec) {
+       section_name = sec->name;
+      }
+      else {
+       section_name = "abs";
+      }
+    }
+    if (syms[thisplace]->value > vma) {
+      fprintf(stream,"%08lx (%s-%lx)", vma, syms[thisplace]->name,
+             syms[thisplace]->value - vma);
+
+    }
+    else {
+      fprintf(stream,"%08lx (%s+%lx)", vma, 
+             syms[thisplace]->name,
+             vma - syms[thisplace]->value);
+    }
+  }
+}
+
+void
+disassemble_data(abfd)
+bfd *abfd;
+{
+  bfd_byte *data = NULL;
+  unsigned int datasize = 0;
+  unsigned int i;
+  int (*print)() ;
+  int print_insn_m68k();
+  int print_insn_i960();
+  int print_insn_sparc();
+  enum bfd_architecture a;
+  unsigned long m;
+  asection *section;
+  /* Replace symbol section relative values with abs values */
+
+  
+  for (i = 0; i < symcount; i++) {
+    if (syms[i]->section != (asection *)NULL) {
+      syms[i]->value += syms[i]->section->vma;
+    }
+  }
+
+  /* We keep a copy of the symbols in the original order */
+  syms2 = slurp_symtab(abfd);
+
+  /* Sort the symbols into section and symbol order */
+  (void)   qsort(syms, symcount, sizeof(asymbol *), comp);
+
+  /* Find the first useless symbol */
+  { unsigned int i;
+    for (i =0; i < symcount; i++) {
+      if (syms[i]->the_bfd == 0) {
+       symcount =i;
+       break;
+      }
+    }
+  }
+
+
+  if (machine!= (char *)NULL) {
+    if (bfd_scan_arch_mach(machine, &a, &m) == false) {
+      fprintf(stderr,"%s: Can't use supplied machine %s\n",
+             program_name,
+             machine);
+      exit(1);
+    }
+  }
+  else {
+    a =   bfd_get_architecture(abfd);
+  }
+  switch (a) {
+
+  case bfd_arch_sparc:
+    print = print_insn_sparc;
+    break;
+  case bfd_arch_m68k:
+    print = print_insn_m68k;
+    break;
+  case bfd_arch_i960:
+    print = print_insn_i960;
+    break;
+  default:
+    fprintf(stderr,"%s: Can't disassemble for architecture %s\n",
+           program_name,
+           bfd_printable_arch_mach(bfd_get_architecture(abfd),0));
+    exit(1);
+  }
+
+
+  for (section = abfd->sections;
+       section != (asection *)NULL;
+       section =  section->next) {
+
+    if (only == (char *)NULL || strcmp(only,section->name) == 0){
+      printf("Disassembly of section %s:\n", section->name);
+
+      if (section->size == 0) continue;
+
+      data = (bfd_byte *)malloc(section->size);
+
+      if (data == (bfd_byte *)NULL) {
+       fprintf (stderr, "%s: memory exhausted.\n", program_name);
+       exit (1);
+      }
+      datasize = section->size;
+
+
+      bfd_get_section_contents (abfd, section, data, 0, section->size);
+
+      i = 0;
+      while ((size_t)i <section->size) {
+       if (with_line_numbers) {
+         static prevline;
+         char *filename;
+         char *functionname;
+         int line;
+         bfd_find_nearest_line(abfd,
+                               section,
+                               syms,
+                               section->vma + i,
+                               &filename,
+                               &functionname,
+                               &line);
+
+         if (filename && functionname && line && line != prevline) {
+           printf("%s:%d\n", filename, line);
+           prevline = line;
+         }
+       }
+       print_address(section->vma + i, stdout);
+       printf(" ");
+
+       i +=   print(section->vma + i, 
+                    data + i,
+                    stdout);
+       putchar ('\n')  ;  
+      }
+
+
+
+
+      free(data);
+    }
+  }
+}
+
+void
+display_bfd (abfd)
+     bfd *abfd;
+{
+
+  if (!bfd_check_format (abfd, bfd_object)) {
+    fprintf (stderr,"%s: %s not an object file\n", program_name,
+            abfd->filename);
+    return;
+  }
+  printf ("\n%s:     file format %s\n", abfd->filename, abfd->xvec->name);
+  if (dump_ar_hdrs) print_arelt_descr (abfd, true);
+
+  if (dump_file_header) {
+    char *comma = "";
+
+    printf("architecture: %s, ",
+          bfd_printable_arch_mach (bfd_get_architecture (abfd),
+                                   bfd_get_machine (abfd)));
+    printf("flags 0x%08x:\n", abfd->flags);
+    
+#define PF(x, y)    if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";}
+    PF(HAS_RELOC, "HAS_RELOC");
+    PF(EXEC_P, "EXEC_P");
+    PF(HAS_LINENO, "HAS_LINENO");
+    PF(HAS_DEBUG, "HAS_DEBUG");
+    PF(HAS_SYMS, "HAS_SYMS");
+    PF(HAS_LOCALS, "HAS_LOCALS");
+    PF(DYNAMIC, "DYNAMIC");
+    PF(WP_TEXT, "WP_TEXT");
+    PF(D_PAGED, "D_PAGED");
+    printf("\nstart address 0x%08lx", abfd->start_address);
+  }
+  printf("\n");
+
+  if (dump_section_headers)
+    dump_headers(abfd);
+  if (dump_symtab || dump_reloc_info || disassemble) {
+syms =  slurp_symtab(abfd);
+  }
+  if (dump_symtab) dump_symbols (abfd);
+  if (dump_reloc_info) dump_relocs(abfd);
+  if (dump_section_contents) dump_data (abfd);
+  if (disassemble) disassemble_data(abfd);
+}
+
+void
+display_file (filename, target)
+     char *filename;
+     char *target;
+{
+  bfd *file, *arfile = (bfd *) NULL;
+
+  file = bfd_openr (filename, target);
+  if (file == NULL) {
+    bfd_perror (filename);
+    return;
+  }
+
+  if (bfd_check_format (file, bfd_archive) == true) {
+    printf ("In archive %s:\n", bfd_get_filename (file));
+    for(;;) {
+      bfd_error = no_error;
+
+      arfile = bfd_openr_next_archived_file (file, arfile);
+      if (arfile == NULL) {
+       if (bfd_error != no_more_archived_files)
+         bfd_perror (bfd_get_filename(file));
+       return;
+      }
+
+      display_bfd (arfile);
+      /* Don't close the archive elements; we need them for next_archive */
+    }
+  }
+  else
+    display_bfd(file);
+
+  bfd_close(file);
+}
+\f
+/* Actually display the various requested regions */
+
+
+
+
+
+
+
+
+
+
+void
+dump_data (abfd)
+     bfd *abfd;
+{
+  asection *section;
+  bfd_byte  *data ;
+  unsigned int datasize = 0;
+  size_t i;
+
+  for (section = abfd->sections; section != NULL; section =
+       section->next) {
+    int onaline = 16;
+
+    if (only == (char *)NULL || 
+       strcmp(only,section->name) == 0){
+
+
+
+      printf("Contents of section %s:\n", section->name);
+
+      if (section->size == 0) continue;
+      data = (bfd_byte *)malloc(section->size);
+      if (data == (bfd_byte *)NULL) {
+       fprintf (stderr, "%s: memory exhausted.\n", program_name);
+       exit (1);
+      }
+      datasize = section->size;
+
+
+      bfd_get_section_contents (abfd, section, data, 0, section->size);
+
+      for (i= 0; i < section->size; i += onaline) {
+       size_t j;
+       printf(" %04lx ", i + section->vma);
+       for (j = i; j < i+ onaline; j++) {
+         if (j < section->size)
+           printf("%02x", (unsigned)(data[j]));
+         else 
+           printf("  ");
+         if ((j & 3 ) == 3) printf(" ");
+       }
+
+       printf(" ");
+       for (j = i; j < i+onaline ; j++) {
+         if (j >= section->size)
+           printf(" ");
+         else
+           printf("%c", isprint(data[j]) ?data[j] : '.');
+       }
+       putchar ('\n');
+      }
+    }
+
+    free (data);
+  }
+}
+
+
+
+/* Should perhaps share code and display with nm? */
+void
+dump_symbols (abfd)
+     bfd *abfd;
+{
+
+  unsigned int count;
+  asymbol **current = syms;
+  printf("SYMBOL TABLE:\n");
+
+  for (count = 0; count < symcount; count++) {
+    if ((*current)->the_bfd) {
+      bfd_print_symbol((*current)->the_bfd,
+                      stdout,
+                      *current, bfd_print_symbol_all_enum);
+
+      printf("\n");
+    }
+    current++;
+  }
+  printf("\n");
+  printf("\n");
+}
+
+
+void
+dump_relocs(abfd)
+bfd *abfd;
+{
+  arelent **relpp;
+  unsigned int relcount;
+  asection *a;
+  for (a = abfd->sections; a != (asection *)NULL; a = a->next) {
+    printf("RELOCATION RECORDS FOR [%s]:",a->name);
+    
+    if (get_reloc_upper_bound(abfd, a) == 0) {
+      printf(" (none)\n\n");
+    }
+    else {
+      arelent **p;
+
+      relpp = (arelent **) xmalloc( get_reloc_upper_bound(abfd,a) );
+      relcount = bfd_canonicalize_reloc(abfd,a,relpp, syms);
+      if (relcount == 0) {
+       printf(" (none)\n\n");
+      }
+      else {
+       printf("\n");
+       printf("OFFSET   TYPE      VALUE \n");
+
+       for (p =relpp; *p != (arelent *)NULL; p++) {
+         arelent *q = *p;
+         char *sym_name;
+         char *section_name =      q->section == (asection *)NULL ? "*abs" :
+         q->section->name;
+         if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
+           sym_name =  (*(q->sym_ptr_ptr))->name ;
+         }
+         else {
+           sym_name = 0;
+         }
+         if (sym_name) {
+           printf("%08lx %-8s  %s",
+                  q->address,
+                  q->howto->name,
+                  sym_name);
+         }
+         else {
+           printf("%08lx %-8s  [%s]",
+                  q->address,
+                  q->howto->name,
+                  section_name);
+         }
+         if (q->addend) {
+           printf("+0x%lx(%ld)", q->addend, (long) q->addend);
+         }
+         printf("\n");
+       }
+       printf("\n\n");
+       free(relpp);
+      }
+    }
+
+  }
+}
+
+
+/** main and like trivia */
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  extern int optind;
+  extern char *optarg;
+  char *target = default_target;
+  boolean seenflag = false;
+  int ind = 0;
+
+  program_name = *argv;
+
+  while ((c = getopt_long (argc, argv, "b:m:dlfahrtxsj:", long_options, &ind))
+        != EOF) {
+    seenflag = true;
+    switch (c) {
+    case 'm':
+      machine = optarg;
+      break;
+    case 'j':
+      only = optarg;
+      break;
+    case 'l':
+      with_line_numbers = 1;
+      break;
+    case 'b':
+      target = optarg;
+      break;
+    case 'f':
+      dump_file_header = true;
+      break;
+    case 'x':
+      dump_symtab = 1; 
+      dump_reloc_info = 1;
+      dump_file_header = true;
+      dump_ar_hdrs = 1;
+      dump_section_headers = 1;
+      break;
+    case  0 : break;           /* we've been given a long option */
+    case 't': dump_symtab = 1; break;
+    case 'd': disassemble = true ; break;
+    case 's': dump_section_contents = 1; break;
+    case 'r': dump_reloc_info = 1; break;
+    case 'a': dump_ar_hdrs = 1; break;
+    case 'h': dump_section_headers = 1; break;
+    default:
+      usage ();
+    }
+  }
+
+  if (seenflag == false)
+    usage ();
+
+  if (optind == argc)
+    display_file ("a.out", target);
+  else
+    for (; optind < argc;)
+      display_file (argv[optind++], target);
+  return 0;
+}
diff --git a/binutils/size.c b/binutils/size.c
new file mode 100644 (file)
index 0000000..9f6800c
--- /dev/null
@@ -0,0 +1,320 @@
+/*** size.c -- report size of various sections of an executable file */
+/* Extensions/incompatibilities:
+   o - BSD output has filenames at the end.
+   o - BSD output can appear in different radicies.
+   o - SysV output has less redundant whitespace.  Filename comes at end.
+   o - SysV output doesn't show VMA which is always the same as the PMA.
+   o - We also handle core files.
+   o - We also handle archives.
+   If you write shell scripts which manipulate this info then you may be
+   out of luck; there's no +predantic switch.
+*/
+#include "sysdep.h"
+#include "bfd.h"
+#include "getopt.h"
+
+
+#ifndef BSD_DEFAULT
+#define BSD_DEFAULT 1
+#endif
+
+PROTO(void, display_file, (char *filename));
+PROTO(void, print_sizes,  (bfd *file));
+
+/* Various program options */
+
+enum {decimal, octal, hex} radix = decimal;
+int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output */
+int show_version = 0;
+int show_help = 0;
+
+/* IMPORTS */
+extern char *program_version;
+extern char *program_name;
+extern char *target;
+\f
+/** main and like trivia */
+
+void
+usage ()
+{
+  fprintf (stderr, "size %s\nUsage: %s -{dox}{AB}V files ...\n",
+        program_version, program_name);
+  fputs("\t+radix={8|10|16} -- select appropriate output radix.\n\
+\t-d -- output in decimal\n\
+\t-o -- output in octal\n\
+\t-x -- output in hex", stderr);
+  fputs("\t+format={Berkeley|SysV} -- select display format.\n\
+\t-A -- SysV(AT&T) format\n\
+\t-B -- BSD format", stderr);
+#if BSD_DEFAULT
+  fputs("\t  (Default is +format=Berkeley)", stderr);
+#else
+  fputs("\t  (Default is +format=SysV)", stderr);
+#endif
+  fputs("\t-V, +version -- display program version, etc.\n\
+\t+help -- this message\n", stderr);
+  exit(1);
+}
+
+struct option long_options[] = {{"radix",   1, 0, 0},
+                               {"format",  1, 0, 0},
+                               {"version", 0, &show_version, 1},
+                               {"target",  2, NULL, NULL},
+                               {"help",    0, &show_help, 1},
+                               {0, 0, 0, 0}};
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int temp;
+  int c;                       /* sez which option char */
+  int option_index = 0;
+  extern int optind;           /* steps thru options */
+  program_name = *argv;
+
+  while ((c = getopt_long(argc, argv, "ABVdox", long_options,
+                         &option_index)) != EOF)
+    switch(c) {
+    case 0:
+      if (!strcmp("format",(long_options[option_index]).name)) {
+       switch(*optarg) {
+       case 'B': case 'b': berkeley_format = 1; break;
+       case 'S': case 's': berkeley_format = 0; break;
+       default: printf("Unknown option to +format: %s\n", optarg);
+         usage();
+       }
+       break;
+      }
+
+      if (!strcmp("target",(long_options[option_index]).name)) {
+       target = optarg;
+       break;
+      }
+
+      if (!strcmp("radix",(long_options[option_index]).name)) {
+#ifdef ANSI_LIBRARIES
+       temp = strtol(optarg, NULL, 10);
+#else
+       temp = atol(optarg);
+#endif
+       switch(temp) {
+       case 10: radix = decimal; break;
+       case 8:  radix = octal; break;
+       case 16: radix = hex; break;
+       default: printf("Unknown radix: %s\n", optarg);
+         usage();
+       }
+      }
+      break;
+    case 'A': berkeley_format = 0; break;
+    case 'B': berkeley_format = 1; break;
+    case 'V': show_version = 1; break;
+    case 'd': radix = decimal; break;
+    case 'x': radix = hex; break;
+    case 'o': radix = octal; break;
+    case '?': usage();
+    }
+
+  if (show_version) printf("%s version %s\n", program_name, program_version);
+  if (show_help) usage();
+       
+  if (berkeley_format)
+#if 0  /* intel doesn't like bss/stk b/c they don't gave core files */
+    puts((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" :
+        "text\tdata\tbss/stk\tdec\thex\tfilename");
+#else
+    puts((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" :
+        "text\tdata\tbss\tdec\thex\tfilename");
+#endif
+  if (optind == argc)
+    display_file ("a.out");
+  else
+    for (; optind < argc;)
+      display_file (argv[optind++]);
+
+  return 0;
+}
+\f
+/** Display a file's stats */
+
+void
+display_bfd (abfd)
+     bfd *abfd;
+{
+  char *core_cmd;
+
+  if (bfd_check_format(abfd, bfd_archive)) return;
+
+  if (bfd_check_format(abfd, bfd_object)) {
+    print_sizes(abfd);
+    goto done;
+  }
+
+  if (bfd_check_format(abfd, bfd_core)) {
+    print_sizes(abfd);
+    fputs(" (core file", stdout);
+
+    core_cmd = bfd_core_file_failing_command(abfd);
+    if (core_cmd) printf(" invoked as %s", core_cmd);
+
+    puts(")");
+    goto done;
+  }
+  
+  printf("Unknown file format: %s.", bfd_get_filename(abfd));
+
+ done:
+
+
+  printf("\n");
+  return;
+}
+
+void
+display_file(filename)
+     char *filename;
+{
+  bfd *file, *arfile = (bfd *) NULL;
+
+  file = bfd_openr (filename, target);
+  if (file == NULL) {
+    bfd_perror (filename);
+    return;
+  }
+
+  if (bfd_check_format(file, bfd_archive) == true) {
+    for(;;) {
+      
+      bfd_error = no_error;
+
+       arfile = bfd_openr_next_archived_file (file, arfile);
+      if (arfile == NULL) {
+       if (bfd_error != no_more_archived_files)
+         bfd_perror (bfd_get_filename (file));
+       return;
+      }
+
+      display_bfd (arfile);
+      /* Don't close the archive elements; we need them for next_archive */
+    }
+  }
+  else
+    display_bfd (file);
+
+  bfd_close (file);
+}
+\f
+/* This is what lexical functions are for */
+void
+lprint_number (width, num)
+     int width, num;
+{
+  printf ((radix == decimal ? "%-*d\t" :
+          ((radix == octal) ? "%-*o\t" : "%-*x\t")), width, num);
+}
+
+void
+rprint_number(width, num)
+     int width, num;
+{
+  printf ((radix == decimal ? "%*d\t" :
+          ((radix == octal) ? "%*o\t" : "%*x\t")), width, num);
+}
+
+static char *bss_section_name = ".bss";
+static char *data_section_name = ".data";
+static char *stack_section_name = ".stack";
+static char *text_section_name = ".text";
+
+void print_berkeley_format(abfd)
+bfd *abfd;
+{
+  sec_ptr bsssection = NULL;
+  sec_ptr datasection = NULL;
+  sec_ptr textsection = NULL;
+  unsigned long bsssize = 0;
+  unsigned long datasize = 0;
+  unsigned long textsize = 0;
+  unsigned long total = 0;
+
+  
+  if ((textsection = bfd_get_section_by_name (abfd, text_section_name))
+      != NULL) {
+    textsize = bfd_section_size (abfd, textsection);
+  }
+
+  if ((datasection = bfd_get_section_by_name (abfd, data_section_name))
+      != NULL) {
+    datasize = bfd_section_size(abfd, datasection);
+  }
+       
+  if (bfd_get_format (abfd) == bfd_object) {
+    if ((bsssection = bfd_get_section_by_name (abfd, bss_section_name))
+       != NULL) {
+      bsssize = bfd_section_size(abfd, bsssection);
+    }
+  } else {
+    if ((bsssection = bfd_get_section_by_name (abfd, stack_section_name))
+       != NULL) {
+      bsssize = bfd_section_size(abfd, bsssection);
+    }
+  }
+       
+  total = textsize + datasize + bsssize;
+       
+  lprint_number (7, textsize);
+  lprint_number (7, datasize);
+  lprint_number (7, bsssize);
+  printf (((radix == octal) ? "%-7o\t%-7x\t" : "%-7d\t%-7x\t"), total, total);
+
+  fputs(bfd_get_filename(abfd), stdout);
+  if (abfd->my_archive) printf (" (ex %s)", abfd->my_archive->filename);
+}
+
+/* I REALLY miss lexical functions! */
+int svi_total = 0;
+
+void
+sysv_internal_printer(file, sec)
+     bfd *file;
+     sec_ptr sec;
+{
+  int size = bfd_section_size (file, sec);
+
+  svi_total += size;
+       
+  printf ("%-12s", bfd_section_name(file, sec));
+  rprint_number (8, size);
+  printf(" ");
+  rprint_number (8, bfd_section_vma(file, sec));
+  printf ("\n");
+}
+
+void
+print_sysv_format(file)
+     bfd *file;
+{
+  svi_total = 0;
+
+  printf ("%s  ", bfd_get_filename (file));
+  if (file->my_archive) printf (" (ex %s)", file->my_archive->filename);
+
+  puts(":\nsection\t\tsize\t     addr");
+  bfd_map_over_sections (file, sysv_internal_printer, NULL);
+
+  printf("Total       ");
+  rprint_number(8, svi_total);
+  printf("\n");  printf("\n");
+}
+
+void
+print_sizes(file)
+     bfd *file;
+{
+  if (berkeley_format)
+    print_berkeley_format(file);
+  else print_sysv_format(file);
+}
diff --git a/binutils/sparc-pinsn.c b/binutils/sparc-pinsn.c
new file mode 100644 (file)
index 0000000..550722b
--- /dev/null
@@ -0,0 +1,490 @@
+/* disassemble sparc instructions for objdump
+   Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+
+This file is part of the binutils.
+
+The binutils are 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 binutils are distributed in the hope that they 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 binutils; see the file COPYING.  If not, write to
+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  1991/03/13  00:34:40  chrisb
+ * Initial revision
+ *
+ * Revision 1.3  1991/03/09  04:36:31  rich
+ *  Modified Files:
+ *     sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
+ *     binutils.h
+ *
+ * Pulled sysdep.h out of bfd.h.
+ *
+ * Revision 1.2  1991/03/08  21:54:53  rich
+ *  Modified Files:
+ *     Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
+ *     i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
+ *     sparc-pinsn.c strip.c
+ *
+ * Verifying Portland tree with steve's last changes.  Also, some partial
+ * porting.
+ *
+ * Revision 1.1  1991/02/22  16:48:04  sac
+ * Initial revision
+ *
+*/
+
+#include <stdio.h>
+#include "sysdep.h"
+#include "bfd.h"
+#include "sparc-opcode.h"
+
+extern int fputs();
+extern int print_address();
+
+static  char *reg_names[] =
+ { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",     
+  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",      
+  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",      
+  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",      
+  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",      
+  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",        
+  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+  "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" };
+
+#define        freg_names      (&reg_names[4 * 8])
+
+union sparc_insn
+  {
+    unsigned long int code;
+    struct
+      {
+       unsigned int OP:2;
+#define        op      ldst.OP
+       unsigned int RD:5;
+#define        rd      ldst.RD
+       unsigned int op3:6;
+       unsigned int RS1:5;
+#define        rs1     ldst.RS1
+       unsigned int i:1;
+       unsigned int ASI:8;
+#define        asi     ldst.ASI
+       unsigned int RS2:5;
+#define        rs2     ldst.RS2
+#define        shcnt   rs2
+      } ldst;
+    struct
+      {
+       unsigned int OP:2, RD:5, op3:6, RS1:5, i:1;
+       unsigned int IMM13:13;
+#define        imm13   IMM13.IMM13
+      } IMM13;
+    struct
+      {
+       unsigned int OP:2;
+       unsigned int a:1;
+       unsigned int cond:4;
+       unsigned int op2:3;
+       unsigned int DISP22:22;
+#define        disp22  branch.DISP22
+      } branch;
+#define        imm22   disp22
+    struct
+      {
+       unsigned int OP:2;
+       unsigned int DISP30:30;
+#define        disp30  call.DISP30
+      } call;
+  };
+
+/* Nonzero if INSN is the opcode for a delayed branch.  */
+static int
+is_delayed_branch (insn)
+     union sparc_insn insn;
+{
+  unsigned int i;
+
+  for (i = 0; i < NUMOPCODES; ++i)
+    {
+      const struct sparc_opcode *opcode = &sparc_opcodes[i];
+      if ((opcode->match & insn.code) == opcode->match
+         && (opcode->lose & insn.code) == 0
+         && (opcode->delayed))
+       return 1;
+    }
+  return 0;
+}
+
+static int opcodes_sorted = 0;
+
+/* Print one instruction from MEMADDR on STREAM.  */
+int
+print_insn_sparc (memaddr, buffer,  stream)
+     bfd_vma memaddr;
+    bfd_byte  *buffer;
+     FILE *stream;
+     
+{
+  union sparc_insn insn;
+
+  register unsigned int i;
+
+  if (!opcodes_sorted)
+    {
+      static int compare_opcodes ();
+      qsort ((char *) sparc_opcodes, NUMOPCODES,
+            sizeof (sparc_opcodes[0]), compare_opcodes);
+      opcodes_sorted = 1;
+    }
+
+memcpy(&insn,buffer, sizeof (insn));
+
+  for (i = 0; i < NUMOPCODES; ++i)
+    {
+      const struct sparc_opcode *opcode = &sparc_opcodes[i];
+      if ((opcode->match & insn.code) == opcode->match
+         && (opcode->lose & insn.code) == 0)
+       {
+         /* Nonzero means that we have found an instruction which has
+            the effect of adding or or'ing the imm13 field to rs1.  */
+         int imm_added_to_rs1 = 0;
+
+         /* Nonzero means that we have found a plus sign in the args
+            field of the opcode table.  */
+         int found_plus = 0;
+         
+         /* Do we have an 'or' instruction where rs1 is the same
+            as rsd, and which has the i bit set?  */
+         if (opcode->match == 0x80102000
+             && insn.rs1 == insn.rd)
+           imm_added_to_rs1 = 1;
+
+         if (index (opcode->args, 'S') != 0)
+           /* Reject the special case for `set'.
+              The real `sethi' will match.  */
+           continue;
+         if (insn.rs1 != insn.rd
+             && index (opcode->args, 'r') != 0)
+             /* Can't do simple format if source and dest are different.  */
+             continue;
+
+         fputs (opcode->name, stream);
+
+         {
+           register const char *s;
+
+           if (opcode->args[0] != ',')
+             fputs (" ", stream);
+           for (s = opcode->args; *s != '\0'; ++s)
+             {
+               if (*s == ',')
+                 {
+                   fputs (",", stream);
+                   ++s;
+                   if (*s == 'a')
+                     {
+                       fputs ("a", stream);
+                       ++s;
+                     }
+                   fputs (" ", stream);
+                 }
+
+               switch (*s)
+                 {
+                 case '+':
+                   found_plus = 1;
+
+                   /* note fall-through */
+                 default:
+                   fprintf (stream, "%c", *s);
+                   break;
+
+                 case '#':
+                   fputs ("0", stream);
+                   break;
+
+#define        reg(n)  fprintf (stream, "%%%s", reg_names[n])
+                 case '1':
+                 case 'r':
+                   reg (insn.rs1);
+                   break;
+
+                 case '2':
+                   reg (insn.rs2);
+                   break;
+
+                 case 'd':
+                   reg (insn.rd);
+                   break;
+#undef reg
+
+#define        freg(n) fprintf (stream, "%%%s", freg_names[n])
+                 case 'e':
+                   freg (insn.rs1);
+                   break;
+
+                 case 'f':
+                   freg (insn.rs2);
+                   break;
+
+                 case 'g':
+                   freg (insn.rd);
+                   break;
+#undef freg
+
+#define        creg(n) fprintf (stream, "%%c%u", (unsigned int) (n))
+                 case 'b':
+                   creg (insn.rs1);
+                   break;
+
+                 case 'c':
+                   creg (insn.rs2);
+                   break;
+
+                 case 'D':
+                   creg (insn.rd);
+                   break;
+#undef creg
+
+                 case 'h':
+                   fprintf (stream, "%%hi(%#x)",
+                                     (unsigned int) insn.imm22 << 10);
+                   break;
+
+                 case 'i':
+                   {
+                     /* We cannot trust the compiler to sign-extend
+                        when extracting the bitfield, hence the shifts.  */
+                     int imm = ((int) insn.imm13 << 19) >> 19;
+
+                     /* Check to see whether we have a 1+i, and take
+                        note of that fact.
+
+                        Note: because of the way we sort the table,
+                        we will be matching 1+i rather than i+1,
+                        so it is OK to assume that i is after +,
+                        not before it.  */
+                     if (found_plus)
+                       imm_added_to_rs1 = 1;
+                     
+                     if (imm <= 9)
+                       fprintf (stream, "%d", imm);
+                     else
+                       fprintf (stream, "%#x", (unsigned) imm);
+                   }
+                   break;
+
+                 case 'L':
+                   print_address ((bfd_vma) memaddr + insn.disp30 * 4,
+                                  stream);
+                   break;
+
+                 case 'l':
+                   if ((insn.code >> 22) == 0)
+                     /* Special case for `unimp'.  Don't try to turn
+                        it's operand into a function offset.  */
+                     fprintf (stream, "%#x",
+                                       (unsigned) (((int) insn.disp22 << 10) >> 10));
+                   else
+                     /* We cannot trust the compiler to sign-extend
+                        when extracting the bitfield, hence the shifts.  */
+                     print_address ((bfd_vma)
+                                    (memaddr
+                                     + (((int) insn.disp22 << 10) >> 10) * 4),
+                                    stream);
+                   break;
+
+                 case 'A':
+                   fprintf (stream, "(%d)", (int) insn.asi);
+                   break;
+
+                 case 'C':
+                   fputs ("%csr", stream);
+                   break;
+
+                 case 'F':
+                   fputs ("%fsr", stream);
+                   break;
+
+                 case 'p':
+                   fputs ("%psr", stream);
+                   break;
+
+                 case 'q':
+                   fputs ("%fq", stream);
+                   break;
+
+                 case 'Q':
+                   fputs ("%cq", stream);
+                   break;
+
+                 case 't':
+                   fputs ("%tbr", stream);
+                   break;
+
+                 case 'w':
+                   fputs ("%wim", stream);
+                   break;
+
+                 case 'y':
+                   fputs ("%y", stream);
+                   break;
+                 }
+             }
+         }
+
+         /* If we are adding or or'ing something to rs1, then
+            check to see whether the previous instruction was
+            a sethi to the same register as in the sethi.
+            If so, attempt to print the result of the add or
+            or (in this context add and or do the same thing)
+            and its symbolic value.  */
+         if (imm_added_to_rs1)
+           {
+             union sparc_insn prev_insn;
+             int errcode;
+
+             memcpy(&prev_insn, buffer -4,  sizeof (prev_insn));
+
+             if (errcode == 0)
+               {
+                 /* If it is a delayed branch, we need to look at the
+                    instruction before the delayed branch.  This handles
+                    sequences such as
+
+                    sethi %o1, %hi(_foo), %o1
+                    call _printf
+                    or %o1, %lo(_foo), %o1
+                    */
+
+                 if (is_delayed_branch (prev_insn))
+                   memcpy(&prev_insn, buffer - 8, sizeof(prev_insn));
+
+               }
+
+             /* If there was a problem reading memory, then assume
+                the previous instruction was not sethi.  */
+             if (errcode == 0)
+               {
+                 /* Is it sethi to the same register?  */
+                 if ((prev_insn.code & 0xc1c00000) == 0x01000000
+                     && prev_insn.rd == insn.rs1)
+                   {
+                     fprintf (stream, "\t! ");
+                     /* We cannot trust the compiler to sign-extend
+                        when extracting the bitfield, hence the shifts.  */
+                     print_address (((int) prev_insn.imm22 << 10)
+                                    | (insn.imm13 << 19) >> 19, stream);
+                   }
+               }
+           }
+
+         return sizeof (insn);
+       }
+    }
+
+  fprintf ("%#8x", insn.code);
+  return sizeof (insn);
+}
+
+
+/* Compare opcodes A and B.  */
+
+static int
+compare_opcodes (a, b)
+     char *a, *b;
+{
+  struct sparc_opcode *op0 = (struct sparc_opcode *) a;
+  struct sparc_opcode *op1 = (struct sparc_opcode *) b;
+  unsigned long int match0 = op0->match, match1 = op1->match;
+  unsigned long int lose0 = op0->lose, lose1 = op1->lose;
+  register unsigned int i;
+
+  /* If a bit is set in both match and lose, there is something
+     wrong with the opcode table.  */
+  if (match0 & lose0)
+    {
+      fprintf (stderr, "Internal error:  bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+              op0->name, match0, lose0);
+      op0->lose &= ~op0->match;
+      lose0 = op0->lose;
+    }
+
+  if (match1 & lose1)
+    {
+      fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+              op1->name, match1, lose1);
+      op1->lose &= ~op1->match;
+      lose1 = op1->lose;
+    }
+
+  /* Because the bits that are variable in one opcode are constant in
+     another, it is important to order the opcodes in the right order.  */
+  for (i = 0; i < 32; ++i)
+    {
+      unsigned long int x = 1 << i;
+      int x0 = (match0 & x) != 0;
+      int x1 = (match1 & x) != 0;
+
+      if (x0 != x1)
+       return x1 - x0;
+    }
+
+  for (i = 0; i < 32; ++i)
+    {
+      unsigned long int x = 1 << i;
+      int x0 = (lose0 & x) != 0;
+      int x1 = (lose1 & x) != 0;
+
+      if (x0 != x1)
+       return x1 - x0;
+    }
+
+  /* They are functionally equal.  So as long as the opcode table is
+     valid, we can put whichever one first we want, on aesthetic grounds.  */
+  {
+    int length_diff = strlen (op0->args) - strlen (op1->args);
+    if (length_diff != 0)
+      /* Put the one with fewer arguments first.  */
+      return length_diff;
+  }
+
+  /* Put 1+i before i+1.  */
+  {
+    char *p0 = (char *) index(op0->args, '+');
+    char *p1 = (char *) index(op1->args, '+');
+
+    if (p0 && p1)
+      {
+       /* There is a plus in both operands.  Note that a plus
+          sign cannot be the first character in args,
+          so the following [-1]'s are valid.  */
+       if (p0[-1] == 'i' && p1[1] == 'i')
+         /* op0 is i+1 and op1 is 1+i, so op1 goes first.  */
+         return 1;
+       if (p0[1] == 'i' && p1[-1] == 'i')
+         /* op0 is 1+i and op1 is i+1, so op0 goes first.  */
+         return -1;
+      }
+  }
+
+  /* They are, as far as we can tell, identical.
+     Since qsort may have rearranged the table partially, there is
+     no way to tell which one was first in the opcode table as
+     written, so just say there are equal.  */
+  return 0;
+}
diff --git a/binutils/version.c b/binutils/version.c
new file mode 100644 (file)
index 0000000..d3e5a13
--- /dev/null
@@ -0,0 +1,5 @@
+/*** version.c -- version number for binutils.
+     They all change in lockstep -- it's easier that way
+*/
+
+char *program_version = "1.10 (Cygnus BFD)";
diff --git a/ld/Makefile b/ld/Makefile
new file mode 100755 (executable)
index 0000000..014b17f
--- /dev/null
@@ -0,0 +1,182 @@
+#
+# Makefile for ld version 2
+#
+# $Id$
+#
+srcdir = .
+BASEDIR        = ../..
+
+INCLUDE        = $(srcdir)/$(BASEDIR)/include-cygnus
+INCLUDES = -I$(srcdir)  -I$(INCLUDE) 
+DEBUG  = -g
+CFLAGS = $(INCLUDES) $(DEBUG) 
+
+# go directly to ld.new in case this ld isn't capable of
+# linking native object on this host.  It can be renamed on
+# install.
+PROGS  = ld.new
+
+# for self hosting
+GNUTARGET=a.out-generic-big
+LDEMULATION=gld
+bfdlib=$(srcdir)/$(BASEDIR)/bfd/$(HOST)/libbfd.a
+
+OBJS= ldgram.o ldlex.o ldlang.o ldmain.o ldwrite.o ldexp.o ld-lnk960.o \
+       ld-gld.o ld-gld960.o ld-emul.o ldversion.o ldmisc.o ldsym.o ldfile.o
+
+HEADERS=config.h ldmain.h ldmain.h ldmisc.h ldsym.h ldlang.h ldexp.h \
+       ldlex.h ldwrite.h ldversion.h ld-emul.h ldfile.h ldgram.h ld.h
+
+MANSOURCES=ld.tex
+
+LDCSOURCES=ldlang.c ldmain.c ldwrite.c ld-lnk960.c ld-gld.c \
+       ld-gld960.c ld-emul.c ldversion.c ldmisc.c ldexp.c ldsym.c ldfile.c
+
+GENERATED_SOURCES=ldgram.tab.c ldlex.c
+GENERATED_HEADERS=ldgram.tab.h
+
+LDSOURCES=$(LDCSOURCES) ldgram.y ldlex.l
+
+#BFDSOURCES=../bfd/libbfd.c ../bfd/bfd.c  ../bfd/sunos.c ../bfd/icoff.c ../bfd/b.out.c   ../bfd/archive.c  ../bfd/srec.c
+
+SOURCES= $(LDSOURCES) $(BFDSOURCES)
+LINTSOURCES=   $(LDCSOURCES) $(BFDSOURCES) $(GENERATED_SOURCES)
+
+all: $(PROGS)
+
+$(PROGS): $(OBJS)
+#      (cd ../bfd; make)
+#      LDEMULATION=gld; export LDEMULATION;  GNUTARGET=a.out-generic-big;./ldok -format a.out-generic-big  -o ld /lib/crt0.o   $(OBJS) $(bfdlib) -lc /usr/local/lib/gcc/sparc/1.91/gnulib
+#      gld -o ld /lib/crt0.o   $(OBJS) $(bfdlib) -lc /usr/local/lib/gcc/sparc/1.91/gnulib
+       $(CC) -Bstatic -o ld.new $(OBJS) $(bfdlib)
+
+
+ld1: ld
+       gcc -v  -B./ -o ld1  $(OBJS) $(bfdlib)
+
+ld2: ld1
+       mv ld1 ld
+       gcc -v  -B./ -o ld2  $(OBJS) $(bfdlib)
+
+ld3: ld2
+       mv ld2 ld
+       gcc -v  -B./ -o ld3  $(OBJS) $(bfdlib)
+
+ld.dvi:ld.tex
+       tex ld.tex
+
+ldgram.o:ldgram.y
+       yacc -d ldgram.y
+       mv y.tab.c ldgram.tab.c
+       $(CC) -c $(CFLAGS) ldgram.tab.c
+       mv ldgram.tab.o ldgram.o
+
+ldgram.tab.h:ldgram.o 
+       cp y.tab.h ldgram.tab.h
+       
+ldlex.c: ldlex.l ldgram.tab.h
+ldlex.o: ldlex.c ldgram.tab.h
+
+ldmain.o: ldmain.c
+ldversion.o: ldversion.c
+ldfile.o: ldfile.c
+ldwrite.o: ldwrite.c
+ldlang.o: ldlang.c ldgram.tab.h
+ld-gld.o: ld-gld.c
+ld-gld960.o: ld-gld960.c
+ld-emul.o:ld-emul.c
+ld-lnk960.o:ld-lnk960.c
+ldexp.o:ldexp.c ldgram.tab.h
+ldmisc.o:ldmisc.c 
+ldsym.o:ldsym.c 
+
+clean:
+       - rm -f $(OBJS) $(GENERATED_SOURCES) $(GENERATED_HEADERS)
+       - rm -f ld ld1 ld2
+
+lintlog:$(SOURCES) Makefile
+       $(LINT) -abhxzn  $(CFLAGS)  $(LINTSOURCES) \
+| grep -v "pointer casts may be troublesome" \
+| grep -v "possible pointer alignment problem" \
+| grep -v "ignore" \
+| grep -v "conversion from long may lose accuracy" \
+| grep -v "warning: constant argument to NOT" \
+| grep -v "enumeration type clash, operator CAST" \
+| grep -v "warning: constant in conditional context"\
+| grep -v "archive\.c"
+
+
+tags TAGS:$(SOURCES) $(HEADERS)
+       etags -t $(SOURCES) $(HEADERS)
+
+release:
+       (cd /4/steve/ld; tar cf -  $(LDSOURCES) $(HEADERS) $(MANSOURCES)) | tar xf - 
+
+objdump:objdump.c 
+
+install: $(PROGS)
+       rm -f $G960BASE/bin/$(PROGS)
+       cp $(PROGS) $$G960BASE/bin/gld960c
+
+#-----------------------------------------------------------------------------
+#              'STANDARD' GNU/960 TARGETS BELOW THIS POINT
+#
+# 'VERSION' file must be present and contain a string of the form "x.y"
+#-----------------------------------------------------------------------------
+
+ver960.c: FORCE
+       rm -f ver960.c
+       echo "char ${TARG}_ver[]= \"${TARG} `cat VERSION`, `date`\";" > ver960.c
+
+
+# This target should be invoked before building a new release.
+# 'VERSION' file must be present and contain a string of the form "x.y"
+#
+roll:
+       @V=`cat VERSION`                ; \
+       MAJ=`sed 's/\..*//' VERSION`    ; \
+       MIN=`sed 's/.*\.//' VERSION`    ; \
+       V=$$MAJ.`expr $$MIN + 1`        ; \
+       rm -f VERSION                   ; \
+       echo $$V >VERSION               ; \
+       echo Version $$V
+
+# Dummy target to force execution of dependent targets.
+#
+.force:
+FORCE:
+
+# Target to uncomment host-specific lines in this makefile.  Such lines must
+# have the following string beginning in column 1: #__<hostname>__#
+# Original Makefile is backed up as 'Makefile.old'.
+#
+# Invoke with:  make make HOST=xxx
+#
+make:
+       -@if test $(HOST)x = x ; then \
+               echo '\aSpecify "make make HOST=???"'; \
+               exit 1; \
+       fi ; \
+       grep -s "^#The next line was generated by 'make make'" Makefile; \
+       if test $$? = 0 ; then  \
+               echo "\aMakefile has already been processed with 'make make'";\
+               exit 1; \
+       fi ; \
+       mv -f Makefile Makefile.old; \
+       echo "#The next line was generated by 'make make'"       >Makefile ; \
+       echo "HOST=$(HOST)"                                     >>Makefile ; \
+       echo                                                    >>Makefile ; \
+       sed "s/^#__$(HOST)__#//" < Makefile.old                 >>Makefile
+
+#\f
+
+Makefile: ../common/Makefile
+       mv Makefile Makefile.backup
+       cp ../common/Makefile .
+       $(MAKE) "HOST=$(HOST)" make
+
+### Local Variables: ***
+### mode:fundamental ***
+### page-delimiter: "^#\f" ***
+### End: ***
+### end of file
diff --git a/ld/ld-emul.c b/ld/ld-emul.c
new file mode 100755 (executable)
index 0000000..7eb23d4
--- /dev/null
@@ -0,0 +1,144 @@
+
+
+/* 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.  */
+
+/*
+   $Id$ 
+
+   $Log$
+   Revision 1.1  1991/03/21 21:28:19  gumby
+   Initial revision
+
+ * Revision 1.1  1991/03/13  00:48:09  chrisb
+ * Initial revision
+ *
+ * Revision 1.4  1991/03/10  09:31:16  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.3  1991/02/22  17:14:55  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+/*
+ * clearing house for ld emulation states 
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "config.h"
+#include "ld.h"
+#include "ld-emul.h"
+#include "ldmisc.h"
+
+extern ld_emulation_xfer_type ld_lnk960_emulation;
+extern ld_emulation_xfer_type ld_gld_emulation;
+extern ld_emulation_xfer_type ld_gld960_emulation;
+
+
+
+ld_emulation_xfer_type *ld_emulation;
+
+void
+ldemul_hll(name)
+char *name;
+{
+  ld_emulation->hll(name);
+}
+
+
+void ldemul_syslib(name)
+char *name;
+{
+  ld_emulation->syslib(name);
+}
+
+void
+ldemul_after_parse()
+{
+  ld_emulation->after_parse();
+}
+
+void
+ldemul_before_parse()
+{
+  ld_emulation->before_parse();
+}
+
+void 
+ldemul_after_allocation()
+{
+  ld_emulation->after_allocation();
+}
+
+void 
+ldemul_before_allocation()
+{
+  if (ld_emulation->before_allocation) {
+    ld_emulation->before_allocation();
+  }
+}
+
+
+void
+ldemul_set_output_arch()
+{
+  ld_emulation->set_output_arch();
+}
+
+char *
+ldemul_choose_target()
+{
+  return ld_emulation->choose_target();
+}
+
+char *
+ldemul_get_script()
+{
+  return ld_emulation->get_script();
+}
+
+void
+ldemul_choose_mode(target)
+char *target;
+{
+  if (strcmp(target,LNK960_EMULATION_NAME)==0) {
+    ld_emulation = &ld_lnk960_emulation;
+  }
+  else if (strcmp(target,GLD_EMULATION_NAME)==0) {
+    ld_emulation = &ld_gld_emulation;
+  }
+  else if (strcmp(target,GLD960_EMULATION_NAME)==0) {
+    ld_emulation = &ld_gld960_emulation;
+  }
+  else {
+    info("%P%F unrecognised emulation mode: %s",target);
+  }
+}
+
+
+
diff --git a/ld/ld-gld.c b/ld/ld-gld.c
new file mode 100755 (executable)
index 0000000..4c3df1a
--- /dev/null
@@ -0,0 +1,258 @@
+/* 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.  */
+
+/*
+ *  $Id$ 
+ *
+ *  $Log$
+ *  Revision 1.1  1991/03/21 21:28:24  gumby
+ *  Initial revision
+ *
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:11  chrisb
+ * Initial revision
+ *
+ * Revision 1.7  1991/03/10  09:31:18  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.6  1991/03/09  03:23:12  sac
+ * Added -Ur loader script.
+ *
+ * Revision 1.5  1991/03/06  21:59:29  sac
+ * Completed G++ support
+ *
+ * Revision 1.4  1991/03/06  02:23:34  sac
+ * Added support for partial linking.
+ *
+ * Revision 1.3  1991/02/22  17:14:56  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/* 
+ * emulate the original gld
+ *
+ *  Written by Steve Chamberlain steve@cygnus.com
+ */
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+
+#include "ld.h"
+#include "config.h"
+#include "ld-emul.h"
+#include "ldfile.h"
+#include "ldmisc.h"
+
+extern  boolean lang_float_flag;
+
+
+extern enum bfd_architecture ldfile_output_architecture;
+extern unsigned long ldfile_output_machine;
+extern char *ldfile_output_machine_name;
+
+extern bfd *output_bfd;
+
+
+
+static void gld_before_parse()
+{
+  ldfile_add_library_path("/lib");
+  ldfile_add_library_path("/usr/lib");
+  ldfile_add_library_path("/usr/local/lib/lib");
+  ldfile_output_architecture = bfd_arch_sparc;
+}
+
+
+static void 
+gld_after_parse()
+{
+
+}
+
+static void
+gld_after_allocation()
+{
+
+}
+
+static void
+gld_before_allocation()
+{
+
+}
+
+
+static void
+gld_set_output_arch()
+{
+  /* Set the output architecture and machine if possible */
+  unsigned long  machine = 0;
+  bfd_set_arch_mach(output_bfd, ldfile_output_architecture, machine);
+}
+
+static char *
+gld_choose_target()
+{
+  char *from_outside = getenv(TARGET_ENVIRON);
+  if (from_outside != (char *)NULL)
+    return from_outside;
+  return GLD_TARGET;
+}
+
+static void
+gld_syslib()
+{
+  info("%S SYSLIB ignored\n");
+}
+
+static void
+gld_hll(ignore)
+char  *ignore;
+{
+  info("%S HLL ignored\n");
+}
+
+static char *gld_script = "  \
+SEARCH_DIR(/lib)                       \
+SEARCH_DIR(/usr/lib)                   \
+SEARCH_DIR(/usr/local/lib)             \
+__DYNAMIC = 0;                                 \
+SECTIONS                               \
+{                                      \
+  .text 0x2020 BLOCK(0x2000):          \
+  {                                    \
+   CREATE_OBJECT_SYMBOLS               \
+    *(.text)                           \
+    _etext = ALIGN( 0x2000);           \
+    }                                          \
+  .data  ALIGN(0x2000)  :              \
+  {                                    \
+    *(.data)                           \
+    ___DTOR_LIST__=. ;                 \
+    LONG((___CTOR_LIST__ - .)/4 -2)    \
+    *(___DTOR_LIST__)                   \
+    LONG(0)                             \
+    ___CTOR_LIST__=. ;                 \
+    LONG((_edata  - .)/4 -2)            \
+    *(___CTOR_LIST__)                   \
+    LONG(0)                             \
+      _edata = .;                      \
+  }                                    \
+  .bss   SIZEOF(.data) + ADDR(.data) : \
+  {                                    \
+   *(.bss)                             \
+   [COMMON]                            \
+     _end=.;                           \
+    }                                  \
+}";
+
+
+static char *gld_script_option_Ur = "\
+SEARCH_DIR(/lib)                       \
+SEARCH_DIR(/usr/lib)                   \
+SEARCH_DIR(/usr/local/lib)             \
+SECTIONS                               \
+{                                      \
+  .text 0:                             \
+  {                                    \
+   CREATE_OBJECT_SYMBOLS                \
+    *(.text)                           \
+    }                                  \
+  .data SIZEOF(.text) + ADDR(.text) :  \
+  {                                    \
+    *(.data)                           \
+    ___DTOR_LIST__=. ;                 \
+    LONG((___CTOR_LIST__ - .)/4 -2)    \
+    *(___DTOR_LIST__)                   \
+    LONG(0)                             \
+    ___CTOR_LIST__=. ;                 \
+    LONG((___end_list__  - .)/4 -2)     \
+    *(___CTOR_LIST__)                   \
+    LONG(0)                             \
+    ___end_list__ = . ;                        \
+    }                                  \
+  .bss SIZEOF(.data) + ADDR(.data) :   \
+  {                                    \
+    *(.bss)                            \
+   [COMMON]                            \
+    }                                  \
+}                                      \
+";                          
+
+static char *gld_script_option_r = "\
+SEARCH_DIR(/lib)                       \
+SEARCH_DIR(/usr/lib)                   \
+SEARCH_DIR(/usr/local/lib)             \
+SECTIONS                               \
+{                                      \
+  .text 0:                             \
+  {                                    \
+   CREATE_OBJECT_SYMBOLS                \
+    *(.text)                           \
+    }                                  \
+  .data SIZEOF(.text) + ADDR(.text) :  \
+  {                                    \
+    *(.data)                           \
+    }                                  \
+  .bss SIZEOF(.data) + ADDR(.data) :   \
+  {                                    \
+    *(.bss)                            \
+   [COMMON]                            \
+    }                                  \
+}                                      \
+";                          
+                            
+static char *gld_get_script()
+{                           
+  extern ld_config_type config;
+  if (config.relocateable_output == true &&
+      config.build_constructors == true) {
+    return gld_script_option_Ur;
+  }
+  if (config.relocateable_output) {
+    return gld_script_option_r;
+  }
+       
+  return gld_script;
+}
+struct ld_emulation_xfer_struct ld_gld_emulation = 
+{
+  gld_before_parse,
+  gld_syslib,
+  gld_hll,
+  gld_after_parse,
+  gld_after_allocation,
+  gld_set_output_arch,
+  gld_choose_target,
+  gld_before_allocation,
+  gld_get_script,
+};
+
diff --git a/ld/ld-gld960.c b/ld/ld-gld960.c
new file mode 100755 (executable)
index 0000000..5e0c1a2
--- /dev/null
@@ -0,0 +1,189 @@
+/* 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.  */
+
+/*
+   $Id$ 
+
+   $Log$
+   Revision 1.1  1991/03/21 21:28:26  gumby
+   Initial revision
+
+ * Revision 1.3  1991/03/16  22:27:24  rich
+ * fish
+ *
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:12  chrisb
+ * Initial revision
+ *
+ * Revision 1.4  1991/03/10  09:31:19  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.3  1991/02/22  17:14:57  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/* 
+ * emulate the Intels port of  gld
+ */
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+
+#include "ld.h"
+#include "config.h"
+#include "ld-emul.h"
+#include "ldfile.h"
+#include "ldmisc.h"
+
+
+/* IMPORTS */
+extern char *output_filename;
+extern  boolean lang_float_flag;
+
+
+extern enum bfd_architecture ldfile_output_architecture;
+extern unsigned long ldfile_output_machine;
+extern char *ldfile_output_machine_name;
+
+extern bfd *output_bfd;
+
+
+
+static void gld960_before_parse()
+{
+  char *env ;
+  env =  getenv("G960LIB");
+  if (env) {
+    ldfile_add_library_path(env);
+  }
+  env = getenv("G960BASE");
+  if (env) {
+    ldfile_add_library_path(concat(env,"/lib",""));
+  }
+  ldfile_output_architecture = bfd_arch_i960;
+}
+
+
+static void 
+gld960_after_parse()
+{
+
+}
+
+static void
+gld960_after_allocation()
+{
+
+}
+
+static void
+gld960_before_allocation()
+{
+
+}
+
+
+static void
+gld960_set_output_arch()
+{
+  /* Set the output architecture and machine if possible */
+  unsigned long  machine = 0;
+  bfd_set_arch_mach(output_bfd, ldfile_output_architecture, machine);
+}
+
+static char *
+gld960_choose_target()
+{
+  char *from_outside = getenv(TARGET_ENVIRON);
+  output_filename = "b.out";
+
+  if (from_outside != (char *)NULL)
+    return from_outside;
+  return GLD960_TARGET;
+}
+
+static void
+gld960_syslib()
+{
+  info("%S SYSLIB ignored\n");
+}
+
+static void
+gld960_hll()
+{
+  info("%S HLL ignored\n");
+}
+
+
+static char *script = "\
+ \
+SECTIONS \
+{ \
+  .text : \
+  { \
+   CREATE_OBJECT_SYMBOLS \
+    *(.text) \
+      _etext =.;\
+    }  \
+ \
+  .data  SIZEOF(.text) + ADDR(.text):\
+  { \
+ \
+    *(.data) \
+      _edata = .; \
+    }  \
+  .bss   SIZEOF(.data) + ADDR(.data) :    \
+  { _bss_start = .;\
+      *(.bss)   \
+       [COMMON] \
+      _end = . ; \
+    } \
+} \
+";
+
+static char *
+gld960_get_script()
+{
+return script;
+}
+
+struct ld_emulation_xfer_struct ld_gld960_emulation = 
+{
+  gld960_before_parse,
+  gld960_syslib,
+  gld960_hll,
+  gld960_after_parse,
+  gld960_after_allocation,
+  gld960_set_output_arch,
+  gld960_choose_target,
+  gld960_before_allocation,
+  gld960_get_script,
+};
diff --git a/ld/ld-lnk960.c b/ld/ld-lnk960.c
new file mode 100755 (executable)
index 0000000..0f82ebe
--- /dev/null
@@ -0,0 +1,321 @@
+/* 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.  */
+
+/*
+   $Id$ 
+
+   $Log$
+   Revision 1.1  1991/03/21 21:28:28  gumby
+   Initial revision
+
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:13  chrisb
+ * Initial revision
+ *
+ * Revision 1.6  1991/03/10  09:31:20  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.5  1991/03/09  03:23:47  sac
+ * Now looks in G960BASE if I960BASE isn't defined.
+ *
+ * Revision 1.4  1991/03/06  02:23:35  sac
+ * Added support for partial linking.
+ *
+ * Revision 1.3  1991/02/22  17:14:58  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/* 
+
+   Written by Steve Chamberlain steve@cygnus.com
+
+ * intel coff loader emulation specific stuff
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+/*#include "archures.h"*/
+#include "ld.h"
+#include "config.h"
+#include "ld-emul.h"
+#include "ldmisc.h"
+#include "ldlang.h"
+#include "ldfile.h"
+
+extern  boolean lang_float_flag;
+extern bfd *output_bfd;
+
+
+
+extern enum bfd_architecture ldfile_output_architecture;
+extern unsigned long ldfile_output_machine;
+extern char *ldfile_output_machine_name;
+
+
+typedef struct lib_list {
+  char *name;
+  struct lib_list *next;
+} lib_list_type;
+
+static lib_list_type *hll_list;
+static lib_list_type **hll_list_tail = &hll_list;
+
+static lib_list_type *syslib_list;
+static lib_list_type **syslib_list_tail = &syslib_list;
+
+
+static void
+append(list, name)
+lib_list_type ***list;
+char *name;
+{
+  lib_list_type *element = 
+    (lib_list_type *)(ldmalloc(sizeof(lib_list_type)));
+
+  element->name = name;
+  element->next = (lib_list_type *)NULL;
+  **list = element;
+  *list = &element->next;
+
+}
+
+static boolean had_hll = false;
+static boolean had_hll_name = false;
+static void
+lnk960_hll(name)
+char *name;
+{
+  had_hll = true;
+  if (name != (char *)NULL) {
+    had_hll_name = true;
+    append(&hll_list_tail, name);
+  }
+}
+
+static void 
+lnk960_syslib(name)
+char *name;
+{
+  append(&syslib_list_tail,name);
+}
+
+
+
+static void 
+lnk960_before_parse()
+{
+  char *name = getenv("I960BASE");
+
+  if (name == (char *)NULL) {
+    name = getenv("G960BASE");
+    if (name == (char *)NULL) {
+      info("%P%F I960BASE and G960BASE not set\n");
+    }
+  }
+
+
+  ldfile_add_library_path(concat(name,"/lib",""));
+  ldfile_output_architecture = bfd_arch_i960;
+  ldfile_output_machine = bfd_mach_i960_core;
+}
+
+static void
+add_on(list, search)
+lib_list_type *list;
+lang_input_file_enum_type search;
+{
+  while (list) {
+    lang_add_input_file(list->name,
+                       search,
+                       (char *)NULL);
+    list = list->next;
+  }
+}
+static void lnk960_after_parse()
+{
+
+  /* If there has been no arch, default to -KB */
+  if (ldfile_output_machine_name[0] ==0) {
+    ldfile_add_arch("kb");
+  }
+
+  /* if there has been no hll list then add our own */
+
+  if(had_hll && !had_hll_name) {
+    append(&hll_list_tail,"c");
+    if (lang_float_flag == true) {
+      append(&hll_list_tail,"m");
+    }
+    else {
+      append(&hll_list_tail,"mstub");
+    }
+    if (ldfile_output_machine == bfd_mach_i960_ka_sa ||
+       ldfile_output_machine == bfd_mach_i960_ca) {
+      {
+       append(&hll_list_tail,"f");
+      }
+    }
+  }
+
+
+
+  add_on(hll_list, lang_input_file_is_l_enum);
+  add_on(syslib_list, lang_input_file_is_search_file_enum);
+
+
+}
+
+static void
+lnk960_before_allocation()
+{
+}
+static void
+lnk960_after_allocation()
+{
+  lang_abs_symbol_at_end_of(".text","_etext");
+  lang_abs_symbol_at_end_of(".data","_edata");
+  lang_abs_symbol_at_end_of(".bss","_end");
+}
+
+static struct
+ {
+   unsigned  long number;
+   char *name; 
+ }
+machine_table[] = {
+       bfd_mach_i960_core      ,"CORE",
+       bfd_mach_i960_kb_sb     ,"KB",
+       bfd_mach_i960_kb_sb     ,"SB",
+       bfd_mach_i960_mc        ,"MC",
+       bfd_mach_i960_xa        ,"XA",
+       bfd_mach_i960_ca        ,"CA",
+       bfd_mach_i960_ka_sa     ,"KA",
+       bfd_mach_i960_ka_sa     ,"SA",
+
+       bfd_mach_i960_core      ,"core",
+       bfd_mach_i960_kb_sb     ,"kb",
+       bfd_mach_i960_kb_sb     ,"sb",
+       bfd_mach_i960_mc        ,"mc",
+       bfd_mach_i960_xa        ,"xa",
+       bfd_mach_i960_ca        ,"ca",
+       bfd_mach_i960_ka_sa     ,"ka",
+       bfd_mach_i960_ka_sa     ,"sa",
+       0,(char *)NULL
+};
+
+static void
+lnk960_set_output_arch()
+{
+  /* Set the output architecture and machine if possible */
+  unsigned int i;
+  ldfile_output_machine = bfd_mach_i960_core;
+  for (i= 0; machine_table[i].name != (char*)NULL; i++) {
+    if (strcmp(ldfile_output_machine_name,machine_table[i].name)==0) {
+      ldfile_output_machine = machine_table[i].number;
+      break;
+    }
+  }
+  bfd_set_arch_mach(output_bfd, ldfile_output_architecture, ldfile_output_machine);
+}
+
+static char *
+lnk960_choose_target()
+{
+  char *from_outside = getenv(TARGET_ENVIRON);
+  if (from_outside != (char *)NULL)
+    return from_outside;
+  return LNK960_TARGET;
+}
+
+/* The default script if none is offered */
+static char *lnk960_script = "\
+SECTIONS \
+{ \
+  .text : \
+  { \
+    *(.text) \
+    }  \
+_etext = .;\
+  .data  SIZEOF(.text) + ADDR(.text):\
+  { \
+    *(.data) \
+    }  \
+_edata = .; \
+  .bss   SIZEOF(.data) + ADDR(.data) :    \
+  { \
+   _bss_start = . ;\
+   *(.bss)  \
+   [COMMON] \
+    } \
+_end = . ; \
+} \
+";
+
+static char *lnk960_script_relocateable = "\
+SECTIONS \
+{ \
+  .text 0x40000000: \
+  { \
+    *(.text) \
+    }  \
+  .data  0:\
+  { \
+    *(.data) \
+    }  \
+  .bss   SIZEOF(.data) + ADDR(.data) :    \
+  { \
+   *(.bss)  \
+   [COMMON] \
+    } \
+} \
+";
+
+static char *lnk960_get_script()
+{
+extern ld_config_type config;
+if (config.relocateable_output) {
+  return lnk960_script_relocateable;
+}
+return lnk960_script;
+
+
+}
+struct ld_emulation_xfer_struct ld_lnk960_emulation = 
+{
+  lnk960_before_parse,
+  lnk960_syslib,
+  lnk960_hll,
+  lnk960_after_parse,
+  lnk960_after_allocation,
+  lnk960_set_output_arch,
+  lnk960_choose_target,
+  lnk960_before_allocation,
+  lnk960_get_script,
+};
diff --git a/ld/ld.h b/ld/ld.h
new file mode 100644 (file)
index 0000000..fb2b62a
--- /dev/null
+++ b/ld/ld.h
@@ -0,0 +1,132 @@
+/* ld.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.  */
+
+
+#define flag_is_not_at_end(x) ((x) & BSF_NOT_AT_END)
+#define flag_is_ordinary_local(x) (((x) & (BSF_LOCAL))&!((x) & (BSF_DEBUGGING)))
+#define flag_is_debugger(x) ((x) & BSF_DEBUGGING)
+#define flag_is_undefined_or_global(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL))
+#define flag_is_defined(x) (!((x) & (BSF_UNDEFINED)))
+#define flag_is_global_or_common(x) ((x) & (BSF_GLOBAL | BSF_FORT_COMM))
+#define flag_is_undefined_or_global_or_common(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL | BSF_FORT_COMM))
+#define flag_is_common(x) ((x) & BSF_FORT_COMM)
+#define flag_is_global(x) ((x) & (BSF_GLOBAL))
+#define flag_is_undefined(x) ((x) & BSF_UNDEFINED)
+#define flag_set(x,y) (x = y)
+#define flag_is_fort_comm(x) ((x) & BSF_FORT_COMM)
+#define flag_is_absolute(x) ((x) & BSF_ABSOLUTE)
+/* Extra information we hold on sections */
+typedef struct  user_section_struct {
+  /* Pointer to the section where this data will go */
+  struct lang_input_statement_struct *file;
+} section_userdata_type;
+
+
+#define get_userdata(x) ((x)->userdata)
+#define as_output_section_statement(x) ((x)->otheruserdata)
+
+#if 0
+/*
+ * Structure for communication between do_file_warnings and it's
+ * helper routines.  Will in practice be an array of three of these:
+ * 0) Current line, 1) Next line, 2) Source file info.
+ */
+struct line_debug_entry
+{
+  int line;
+  char *filename;
+  struct nlist *sym;
+};
+
+#endif
+
+
+/* Which symbols should be stripped (omitted from the output):
+   none, all, or debugger symbols.  */
+enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols;
+
+
+
+
+/* Which local symbols should be omitted:
+   none, all, or those starting with L.
+   This is irrelevant if STRIP_NONE.  */
+enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals;
+
+
+
+
+
+
+#define ALIGN(this, boundary)  ((( (this) + ((boundary) -1)) & (~((boundary)-1))))
+#if 0
+#define FOREACHGLOBALSYMBOL(x)   ldsym_type *x; for (x = symbol_head; x; x=x->next)
+
+
+
+
+#define SECTIONLOOP(abfd, ptr) \
+  asection *ptr; for(ptr = abfd->sections; ptr;ptr=ptr->next)
+
+
+#endif
+typedef struct {
+
+  /* 1 => assign space to common symbols even if `relocatable_output'.  */
+  boolean force_common_definition;
+
+} args_type;
+
+typedef int token_code_type;
+
+typedef struct 
+{
+  unsigned int specified_data_size;
+  boolean magic_demand_paged;
+  boolean make_executable;
+  /* 1 => write relocation into output file so can re-input it later.  */
+  boolean relocateable_output;
+
+  /* Will we build contstructors, or leave alone ? */
+  boolean build_constructors;
+  /* 1 => write relocation such that a UNIX linker can understand it.
+     This is used mainly to finish of sets that were built.  */
+  boolean unix_relocate;
+
+
+} ld_config_type;
+#define set_asymbol_chain(x,y) ((x)->udata = (void *)y)
+#define get_asymbol_chain(x) ((asymbol **)((x)->udata))
+#define get_loader_symbol(x) ((loader_global_asymbol *)((x)->udata))
+#define set_loader_symbol(x,y) ((x)->udata = (void *)y)
+
+
+
+
+
+
+typedef enum {
+  lang_first_phase_enum,
+  lang_allocating_phase_enum,
+  lang_final_phase_enum } lang_phase_type;
+
+
+
+
diff --git a/ld/ldexp.c b/ld/ldexp.c
new file mode 100644 (file)
index 0000000..5b8581f
--- /dev/null
@@ -0,0 +1,770 @@
+/* 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.  */
+
+/*
+   $Id$ 
+
+   $Log$
+   Revision 1.1  1991/03/21 21:28:34  gumby
+   Initial revision
+
+ * Revision 1.1  1991/03/13  00:48:16  chrisb
+ * Initial revision
+ *
+ * Revision 1.6  1991/03/10  09:31:22  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.5  1991/03/09  03:25:04  sac
+ * Added support for LONG, SHORT and BYTE keywords in scripts
+ *
+ * Revision 1.4  1991/03/06  02:27:15  sac
+ * Added LONG, SHORT and BYTE keywords
+ *
+ * Revision 1.3  1991/02/22  17:14:59  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/*
+ * Written by Steve Chamberlain
+ * steve@cygnus.com
+ *
+ * This module handles expression trees.
+ */
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldmisc.h"
+#include "ldexp.h"
+#include "ldgram.tab.h"
+#include "ldsym.h"
+#include "ldlang.h"
+
+extern char *output_filename;
+extern unsigned int undefined_global_sym_count;
+extern unsigned int defined_global_sym_count;
+extern bfd *output_bfd;
+extern size_t largest_section;
+extern lang_statement_list_type file_chain;
+extern args_type command_line;
+extern ld_config_type config;
+
+extern lang_input_statement_type *script_file;
+extern unsigned int defined_global_sym_count;
+
+extern bfd_vma print_dot;
+
+
+static void
+exp_print_token(outfile, code)
+FILE *outfile;
+token_code_type code;
+{
+  static struct  {
+    token_code_type code;
+    char *name;
+  } table[] =
+    {
+      INT,     "int",
+      CHAR,"char",
+      NAME,"NAME",
+      PLUSEQ,"+=",
+      MINUSEQ,"-=",
+      MULTEQ,"*=",
+      DIVEQ,"/=",
+      LSHIFTEQ,"<<=",
+      RSHIFTEQ,">>=",
+      ANDEQ,"&=",
+      OREQ,"|=",
+      OROR,"||",
+      ANDAND,"&&",
+      EQ,"==",
+      NE,"!=",
+      LE,"<=",
+      GE,">=",
+      LSHIFT,"<<",
+      RSHIFT,">>=",
+      ALIGN_K,"ALIGN",
+      BLOCK,"BLOCK",
+      SECTIONS,"SECTIONS",
+      ALIGNMENT,"ALIGNMENT",
+      SIZEOF_HEADERS,"SIZEOF_HEADERS",
+      NEXT,"NEXT",
+      SIZEOF,"SIZEOF",
+      ADDR,"ADDR",
+      MEMORY,"MEMORY",
+      DSECT,"DSECT",
+      NOLOAD,"NOLOAD",
+      COPY,"COPY",
+      INFO,"INFO",
+      OVERLAY,"OVERLAY",
+      DEFINED,"DEFINED",
+      TARGET_K,"TARGET",
+      SEARCH_DIR,"SEARCH_DIR",
+      MAP,"MAP",
+      LONG,"LONG",
+      SHORT,"SHORT",
+      BYTE,"BYTE",
+      ENTRY,"ENTRY",
+    0,(char *)NULL} ;
+
+
+
+  unsigned int idx;
+  for (idx = 0; table[idx].name != (char*)NULL; idx++) {
+    if (table[idx].code == code) {
+      fprintf(outfile, "%s", table[idx].name);
+      return;
+    }
+  }
+  /* Not in table, just print it alone */
+  fprintf(outfile, "%c",code);
+}
+
+static void 
+make_abs(ptr)
+etree_value_type *ptr;
+{
+  if (ptr->section != (lang_output_section_statement_type *)NULL) {
+    asection *s = ptr->section->bfd_section;
+    ptr->value += s->vma;
+    ptr->section = (lang_output_section_statement_type *)NULL;
+  }
+
+}
+static
+etree_value_type new_abs(value)
+bfd_vma value;
+{
+  etree_value_type new;
+  new.valid = true;
+  new.section = (lang_output_section_statement_type *)NULL;
+  new.value = value;
+  return new;
+}
+
+static void check(os)
+lang_output_section_statement_type *os;
+{
+  if (os == (lang_output_section_statement_type *)NULL) {
+    info("%F%P undefined section");
+  }
+  if (os->processed == false) {
+    info("%F%P forward reference of section");
+  }
+}
+
+etree_type *exp_intop(value)
+bfd_vma value;
+{
+  etree_type *new = (etree_type *)ldmalloc(sizeof(new->value));
+  new->type.node_code = INT;
+  new->value.value = value;
+  new->type.node_class = etree_value;
+  return new;
+
+}
+
+
+static
+etree_value_type new_rel(value, section)
+bfd_vma value;
+lang_output_section_statement_type *section;
+{
+  etree_value_type new;
+  new.valid = true;
+  new.value = value;
+  new.section = section;
+  return new;
+}
+
+static
+etree_value_type new_rel_from_section(value, section)
+bfd_vma value;
+lang_output_section_statement_type *section;
+{
+  etree_value_type new;
+  new.valid = true;
+  new.value = value;
+  new.section = section;
+  if (new.section != (lang_output_section_statement_type *)NULL) {
+    new.value -= section->bfd_section->vma;
+  }
+  return new;
+}
+
+static etree_value_type 
+fold_binary(tree, current_section, allocation_done, dot, dotp)
+etree_type *tree;
+lang_output_section_statement_type *current_section;
+lang_phase_type  allocation_done;
+bfd_vma dot;
+bfd_vma *dotp;
+{
+  etree_value_type result;
+
+  result =  exp_fold_tree(tree->binary.lhs,  current_section,
+                         allocation_done, dot, dotp);
+  if (result.valid) {
+    etree_value_type other;
+    other = exp_fold_tree(tree->binary.rhs,
+                         current_section,
+                         allocation_done, dot,dotp) ;
+    if (other.valid) {
+       /* If values are from different sections, or this is an */
+       /* absolute expression, make both source args absolute */
+      if (result.section !=  other.section ||
+         current_section == (lang_output_section_statement_type *)NULL) {
+
+       make_abs(&result);
+       make_abs(&other);
+      }
+         
+      switch (tree->type.node_code) 
+       {
+       case '%':
+         /* Mod,  both absolule*/
+
+         if (other.value == 0) {
+           info("%F%S % by zero\n");
+         }
+         result.value %= other.value;
+         break;
+       case '/':
+         if (other.value == 0) {
+           info("%F%S / by zero\n");
+         }
+         result.value /= other.value;
+         break;
+#define BOP(x,y) case x : result.value = result.value y other.value;break;
+         BOP('+',+);
+         BOP('*',*);
+         BOP('-',-);
+         BOP(LSHIFT,<<);
+         BOP(RSHIFT,>>);
+         BOP(EQ,==);
+         BOP(NE,!=);
+         BOP('<',<);
+         BOP('>',>);
+         BOP(LE,<=);
+         BOP(GE,>=);
+         BOP('&',&);
+         BOP('^',^);
+         BOP('|',|);
+         BOP(ANDAND,&&);
+         BOP(OROR,||);
+       default:
+         FAIL();
+       }
+    }
+  }
+  return result;
+}
+etree_value_type invalid()
+{
+  etree_value_type new;
+  new.valid = false;
+  return new;
+}
+
+etree_value_type fold_name(tree, current_section, allocation_done, dot)
+etree_type *tree;
+lang_output_section_statement_type *current_section;
+lang_phase_type  allocation_done;
+bfd_vma dot;
+
+{
+  etree_value_type result;
+  switch (tree->type.node_code) 
+    {
+    case DEFINED:
+      result.value =
+       ldsym_get_soft(tree->name.name) != (ldsym_type *)NULL;
+      result.section = 0;
+      result.valid = true;
+      break;
+    case NAME:
+      result.valid = false;
+      if (tree->name.name[0] == '.' && tree->name.name[1] == 0) {
+
+       if (allocation_done != lang_first_phase_enum) {
+         result = new_rel_from_section(dot, current_section);
+       }
+       else {
+         result = invalid();
+       }
+      }
+      else {
+       if (allocation_done == lang_final_phase_enum) {
+         ldsym_type *sy = ldsym_get_soft(tree->name.name);
+         
+         if (sy) {
+           asymbol **sdefp = sy->sdefs_chain;
+
+           if (sdefp) {
+             asymbol *sdef = *sdefp;
+             if (sdef->section == (asection *)NULL) {
+               /* This is an absolute symbol */
+               result = new_abs(sdef->value);
+             }
+             else {
+               lang_output_section_statement_type *os =
+                 lang_output_section_statement_lookup( sdef->section->output_section->name);
+               result = new_rel(sdef->value, os);
+             }
+           }
+         }
+         if (result.valid == false) {
+           info("%F%S: undefined symbol `%s' referenced in expression.\n",
+                  tree->name.name);
+         }
+
+       }
+      }
+
+      break;
+
+    case ADDR:
+
+      if (allocation_done != lang_first_phase_enum) {
+       lang_output_section_statement_type *os =
+         lang_output_section_find(tree->name.name);
+       check(os);
+       result =    new_rel((bfd_vma)0,  os);
+      }
+      else {
+       result = invalid();
+      }
+      break;
+    case SIZEOF:
+      if(allocation_done != lang_first_phase_enum) {
+       lang_output_section_statement_type *os = 
+         lang_output_section_find(tree->name.name);
+       check(os);
+       result = new_abs((bfd_vma)(os->bfd_section->size));
+      }
+      else {
+       result = invalid();
+      }
+      break;
+
+    default:
+      FAIL();
+      break;
+    }
+
+  return result;
+}
+etree_value_type exp_fold_tree(tree, current_section, allocation_done,
+                              dot, dotp)
+etree_type *tree;
+lang_output_section_statement_type *current_section;
+lang_phase_type  allocation_done;
+bfd_vma dot;
+bfd_vma *dotp;
+{
+  etree_value_type result;
+
+  if (tree == (etree_type *)NULL) {
+    result.valid = false;
+  }
+  else {
+    switch (tree->type.node_class) 
+      {
+      case etree_value:
+       result = new_rel(tree->value.value, current_section);
+       break;
+      case etree_unary:
+       result = exp_fold_tree(tree->unary.child,
+                              current_section,
+                              allocation_done, dot, dotp);
+       if (result.valid == true)
+         {
+           switch(tree->type.node_code) 
+             {
+             case ALIGN_K:
+               if (allocation_done != lang_first_phase_enum) {
+                 result = new_rel_from_section(ALIGN(dot,
+                                                     result.value) ,
+                                               current_section);
+
+               }
+               else {
+                 result.valid = false;
+               }
+               break;
+             case '-':
+               result.value = -result.value;
+               break;
+             case NEXT:
+               result.valid = false;
+               break;
+             default:
+               FAIL();
+             }
+         }
+
+       break;
+      case etree_trinary:
+
+       result = exp_fold_tree(tree->trinary.cond,
+                              current_section,
+                              allocation_done, dot, dotp);
+       if (result.valid) {
+         result = exp_fold_tree(result.value ?
+                                tree->trinary.lhs:tree->trinary.rhs,
+                                current_section,
+                                allocation_done, dot, dotp);
+       }
+
+       break;
+      case etree_binary:
+       result = fold_binary(tree, current_section, allocation_done,
+                            dot, dotp);
+       break;
+      case etree_assign:
+       if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) {
+         /* Assignment to dot can only be done during allocation */
+         if (allocation_done == lang_allocating_phase_enum) {
+           result = exp_fold_tree(tree->assign.src,
+                                  current_section,
+                                  lang_allocating_phase_enum, dot, dotp);
+           if (result.valid == false) {
+             info("%F%S invalid assignment to location counter\n");
+           }
+           else {
+             if (current_section ==
+                 (lang_output_section_statement_type  *)NULL) {
+               info("%F%S assignment to location counter invalid outside of SECTION\n");
+             }
+             else {
+               unsigned long nextdot =result.value +
+                 current_section->bfd_section->vma;
+               if (nextdot < dot) {
+                 info("%F%S cannot move location counter backwards");
+               }
+               else {
+                *dotp = nextdot; 
+               }
+             }
+           }
+         }
+       }
+       else {
+         ldsym_type *sy = ldsym_get(tree->assign.dst);
+
+         /* If this symbol has just been created then we'll place it into 
+          * a section of our choice
+          */
+         result = exp_fold_tree(tree->assign.src,
+                                current_section, allocation_done,
+                                dot, dotp);
+         if (result.valid)
+           {
+             asymbol *def;
+             asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **));
+             /* Add this definition to script file */
+             def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd);
+             *def_ptr = def;
+
+
+             def->value = result.value;
+             if (result.section !=
+                 (lang_output_section_statement_type  *)NULL) {
+               if (current_section !=
+                   (lang_output_section_statement_type *)NULL) {
+                 
+                 def->section = result.section->bfd_section;
+                 def->flags = BSF_GLOBAL | BSF_EXPORT;
+               }
+               else {
+                 /* Force to absolute */
+                 def->value += result.section->bfd_section->vma;
+                 def->section = (asection *)NULL;
+                 def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE;
+               }
+
+
+             }
+             else {
+               def->section = (asection *)NULL;
+               def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE;
+             }
+
+
+             def->udata = (void *)NULL;
+             def->name = sy->name;
+             Q_enter_global_ref(def_ptr);
+           }
+
+       }
+
+  
+       break;
+      case etree_name:
+       result = fold_name(tree, current_section, allocation_done, dot);
+       break;
+      default:
+       info("%F%S Need more of these %d",tree->type.node_class );
+
+      }
+  }
+
+  return result;
+}
+
+
+etree_value_type exp_fold_tree_no_dot(tree, current_section, allocation_done)
+etree_type *tree;
+lang_output_section_statement_type *current_section;
+lang_phase_type  allocation_done;
+{
+return exp_fold_tree(tree, current_section, allocation_done, (bfd_vma)
+                    0, (bfd_vma *)NULL);
+}
+
+etree_type *
+exp_binop(code, lhs, rhs)
+int code;
+etree_type *lhs;
+etree_type *rhs;
+{
+  etree_type value, *new;
+  etree_value_type r;
+
+  value.type.node_code = code;
+  value.binary.lhs = lhs;
+  value.binary.rhs = rhs;
+  value.type.node_class = etree_binary;
+  r = exp_fold_tree_no_dot(&value,  (lang_output_section_statement_type *)NULL,
+                          lang_first_phase_enum );
+  if (r.valid)
+    {
+      return exp_intop(r.value);
+    }
+  new = (etree_type *)ldmalloc(sizeof(new->binary));
+  memcpy((char *)new, (char *)&value, sizeof(new->binary));
+  return new;
+}
+
+etree_type *
+exp_trinop(code, cond, lhs, rhs)
+int code;
+etree_type *cond;
+etree_type *lhs;
+etree_type *rhs;
+{
+  etree_type value, *new;
+  etree_value_type r;
+  value.type.node_code = code;
+  value.trinary.lhs = lhs;
+  value.trinary.cond = cond;
+  value.trinary.rhs = rhs;
+  value.type.node_class = etree_trinary;
+  r= exp_fold_tree_no_dot(&value,  (lang_output_section_statement_type
+                                   *)NULL,lang_first_phase_enum);
+  if (r.valid) {
+    return exp_intop(r.value);
+  }
+  new = (etree_type *)ldmalloc(sizeof(new->trinary));
+  memcpy((char *)new,(char *) &value, sizeof(new->trinary));
+  return new;
+}
+
+
+etree_type *
+exp_unop(code, child)
+int code;
+etree_type *child;
+{
+  etree_type value, *new;
+
+  etree_value_type r;
+  value.unary.type.node_code = code;
+  value.unary.child = child;
+  value.unary.type.node_class = etree_unary;
+r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL,
+             lang_first_phase_enum);
+if (r.valid) {
+    return exp_intop(r.value);
+  }
+  new = (etree_type *)ldmalloc(sizeof(new->unary));
+  memcpy((char *)new, (char *)&value, sizeof(new->unary));
+  return new;
+}
+
+
+etree_type *
+exp_nameop(code, name)
+int code;
+char *name;
+{
+
+  etree_type value, *new;
+
+  etree_value_type r;
+  value.name.type.node_code = code;
+  value.name.name = name;
+  value.name.type.node_class = etree_name;
+
+
+  r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL,
+               lang_first_phase_enum);
+  if (r.valid) {
+    return exp_intop(r.value);
+  }
+  new = (etree_type *)ldmalloc(sizeof(new->name));
+  memcpy((char *)new, (char *)&value, sizeof(new->name));
+  return new;
+
+}
+
+
+
+
+etree_type *
+exp_assop(code, dst, src)
+int code;
+char *dst;
+etree_type *src;
+{
+  etree_type value, *new;
+
+  value.assign.type.node_code = code;
+
+
+  value.assign.src = src;
+  value.assign.dst = dst;
+  value.assign.type.node_class = etree_assign;
+
+#if 0
+  if (exp_fold_tree_no_dot(&value, &result)) {
+    return exp_intop(result);
+  }
+#endif
+  new = (etree_type*)ldmalloc(sizeof(new->assign));
+  memcpy((char *)new, (char *)&value, sizeof(new->assign));
+  return new;
+}
+
+void 
+exp_print_tree(outfile, tree)
+FILE *outfile;
+etree_type *tree;
+{
+  switch (tree->type.node_class) {
+  case etree_value:
+    fprintf(outfile,"0x%08lx",(bfd_vma)(tree->value.value));
+    return;
+  case etree_assign:
+#if 0
+    if (tree->assign.dst->sdefs != (asymbol *)NULL){
+      fprintf(outfile,"%s (%x) ",tree->assign.dst->name,
+             tree->assign.dst->sdefs->value);
+    }
+    else {
+      fprintf(outfile,"%s (UNDEFINED)",tree->assign.dst->name);
+    }
+#endif
+    fprintf(outfile,"%s ",tree->assign.dst);
+    exp_print_token(outfile,tree->type.node_code);
+    exp_print_tree(outfile,tree->assign.src);
+    break;
+  case etree_binary:
+    exp_print_tree(outfile,tree->binary.lhs);
+    exp_print_token(outfile,tree->type.node_code);
+    exp_print_tree(outfile,tree->binary.rhs);
+    break;
+  case etree_trinary:
+    exp_print_tree(outfile,tree->trinary.cond);
+    fprintf(outfile,"?");
+    exp_print_tree(outfile,tree->trinary.lhs);
+    fprintf(outfile,":");
+    exp_print_tree(outfile,tree->trinary.rhs);
+    break;
+  case etree_unary:
+    exp_print_token(outfile,tree->unary.type.node_code);
+    fprintf(outfile,"(");
+    exp_print_tree(outfile,tree->unary.child);
+    fprintf(outfile,")");
+    break;
+  case etree_undef:
+    fprintf(outfile,"????????");
+    break;
+  case etree_name:
+    if (tree->type.node_code == NAME) {
+      fprintf(outfile,"%s", tree->name.name);
+    }
+    else {
+      exp_print_token(outfile,tree->type.node_code);
+      fprintf(outfile,"(%s)", tree->name.name);
+    }
+    break;
+  default:
+    FAIL();
+    break;
+  }
+}
+
+
+
+
+bfd_vma
+exp_get_vma(tree, def, name, allocation_done)
+etree_type *tree;
+bfd_vma def;
+char *name;
+lang_phase_type allocation_done;
+{
+  etree_value_type r;
+
+  if (tree != (etree_type *)NULL) {
+    r = exp_fold_tree_no_dot(tree,
+                     (lang_output_section_statement_type *)NULL,
+                     allocation_done);
+    if (r.valid == false && name) {
+      info("%F%S Nonconstant expression for %s\n",name);
+    }
+    return r.value;
+  }
+  else {
+    return def;
+  }
+}
+
+int 
+exp_get_value_int(tree,def,name, allocation_done)
+etree_type *tree;
+int def;
+char *name;
+lang_phase_type allocation_done;
+{
+  return (int)exp_get_vma(tree,(bfd_vma)def,name, allocation_done);
+}
diff --git a/ld/ldexp.h b/ld/ldexp.h
new file mode 100644 (file)
index 0000000..f7e1321
--- /dev/null
@@ -0,0 +1,99 @@
+/* ldexp.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.  */
+
+
+
+
+/* The result of an expression tree */
+typedef struct 
+{
+  bfd_vma value;
+  struct lang_output_section_statement_struct *section;
+  boolean valid;
+} etree_value_type;
+
+
+
+typedef struct 
+{
+  int node_code;
+  enum { etree_binary,
+          etree_trinary,
+          etree_unary,
+          etree_name,
+          etree_assign,
+          etree_undef,
+          etree_unspec,
+          etree_value } node_class;
+} node_type;
+
+
+
+typedef union etree_union 
+{
+  node_type type;
+  struct {
+    node_type type;
+    union etree_union *lhs;
+    union etree_union *rhs;
+  } binary;
+  struct {
+    node_type type;
+    union etree_union *cond;
+    union etree_union *lhs;
+    union etree_union *rhs;
+  } trinary;
+  struct {
+    node_type type;
+    char *dst;
+    union etree_union *src;
+  } assign;
+
+  struct {
+    node_type type;
+    union   etree_union *child;
+  } unary;
+  struct {
+    node_type type;
+    char *name;
+  } name;
+  struct {
+    node_type type;
+    bfd_vma value;
+  } value;
+
+} etree_type;
+
+
+PROTO(etree_type *,exp_intop,(bfd_vma));
+
+PROTO(etree_value_type, invalid,(void));
+PROTO(etree_value_type, exp_fold_tree,(etree_type *, struct
+                                   lang_output_section_statement_struct *, lang_phase_type,
+                                       bfd_vma, bfd_vma *));
+
+PROTO(etree_type *, exp_binop,(int, etree_type *, etree_type *));
+PROTO(etree_type *,exp_trinop,(int,etree_type *, etree_type *, etree_type *));
+PROTO(etree_type *,exp_unop,(int, etree_type *));
+PROTO(etree_type *,exp_nameop,(int, char *));
+PROTO(etree_type *,exp_assop,(int, char *, etree_type *));
+PROTO(void, exp_print_tree,(struct _iobuf *, etree_type *));
+PROTO(bfd_vma, exp_get_vma,(etree_type *, bfd_vma, char *, enum boolean));
+PROTO(int, exp_get_value_int,(etree_type *, int, char *, enum boolean));
diff --git a/ld/ldfile.c b/ld/ldfile.c
new file mode 100644 (file)
index 0000000..bc55f04
--- /dev/null
@@ -0,0 +1,284 @@
+
+/* 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.  */
+
+/*
+   $Id$ 
+
+   $Log$
+   Revision 1.1  1991/03/21 21:28:37  gumby
+   Initial revision
+
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:18  chrisb
+ * Initial revision
+ *
+ * Revision 1.4  1991/03/10  09:31:24  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.3  1991/02/22  17:15:00  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/*
+ ldfile.c
+
+ look after all the file stuff
+
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "ldmisc.h"
+#include "ldlang.h"
+#include "ldfile.h"
+
+#include <ctype.h>
+
+/* EXPORT */
+char *ldfile_input_filename;
+char *ldfile_output_machine_name;
+unsigned long ldfile_output_machine;
+enum bfd_architecture ldfile_output_architecture;
+boolean had_script;
+
+/* IMPORT */
+
+extern boolean option_v;
+
+
+
+
+
+/* LOACL */
+typedef struct search_dirs_struct 
+{
+  char *name;
+  struct search_dirs_struct *next;
+} search_dirs_type;
+
+static search_dirs_type *search_head;
+static search_dirs_type **search_tail_ptr = &search_head;
+
+typedef struct search_arch_struct 
+{
+  char *name; 
+  struct search_arch_struct *next;
+} search_arch_type;
+
+static search_arch_type *search_arch_head;
+static search_arch_type **search_arch_tail_ptr = &search_arch_head;
+void
+ldfile_add_library_path(name)
+char *name;
+{
+  search_dirs_type *new =
+    (search_dirs_type *)ldmalloc(sizeof(search_dirs_type));
+  new->name = name;
+  new->next = (search_dirs_type*)NULL;
+  *search_tail_ptr = new;
+  search_tail_ptr = &new->next;
+}
+
+
+static bfd*
+cached_bfd_openr(attempt,entry)
+char *attempt;
+lang_input_statement_type  *entry;
+{
+  entry->the_bfd = bfd_openr(attempt, entry->target);
+
+
+  return entry->the_bfd;
+}
+
+static bfd *
+open_a(arch, entry, lib, suffix)
+char *arch;
+lang_input_statement_type *entry;
+char *lib;
+char *suffix;
+{
+  bfd*desc;
+  search_dirs_type *search ;
+  for (search = search_head;
+       search != (search_dirs_type *)NULL;
+       search = search->next) 
+    {
+      char buffer[1000];
+      char *string;
+      if (entry->is_archive == true) {
+       sprintf(buffer,
+               "%s/%s%s%s%s",
+               search->name,
+               lib,
+               entry->filename, arch, suffix);
+      }
+      else {
+             if (entry->filename[0] == '/') {
+                     strcpy(buffer, entry->filename);
+             } else {
+                     sprintf(buffer,"%s/%s",search->name, entry->filename);
+             }                 /*  */
+      }
+      string = buystring(buffer);      
+      desc = cached_bfd_openr (string, entry);
+      if (desc)
+       {
+         entry->filename = string;
+         entry->search_dirs_flag = false;
+         entry->the_bfd =  desc;
+         return desc;
+       }
+      free(string);
+    }
+  return (bfd *)NULL;
+}
+
+/* Open the input file specified by 'entry', and return a descriptor.
+   The open file is remembered; if the same file is opened twice in a row,
+   a new open is not actually done.  */
+
+void
+ldfile_open_file (entry)
+lang_input_statement_type *entry;
+{
+
+  if (entry->superfile)
+    ldfile_open_file (entry->superfile);
+
+  if (entry->search_dirs_flag)
+    {
+      search_arch_type *arch;
+      for (arch = search_arch_head;
+          arch != (search_arch_type *)NULL;
+          arch = arch->next) {
+       if (open_a(arch->name,entry,"","") != (bfd *)NULL) {
+         return;
+       }
+       if (open_a(arch->name,entry,"lib",".a") != (bfd *)NULL) {
+         return;
+       }
+
+      }
+
+
+    }
+  else {
+    entry->the_bfd = cached_bfd_openr (entry->filename, entry);
+
+  }
+  if (!entry->the_bfd)  info("%F%P: %E %I\n", entry);
+
+}
+
+
+
+
+
+
+static FILE *
+try_open(name, exten)
+char *name;
+char *exten;
+{
+  FILE *result;
+  char buff[1000];
+  result = fopen(name, "r");
+  if (result && option_v == true) {
+    info("%s\n",name);
+    return result;
+  }
+  sprintf(buff, "%s%s", name, exten);
+  result = fopen(buff, "r");
+
+  if (result && option_v == true) {
+    info("%s\n", buff);
+  }
+  return result;
+}
+static FILE *
+find_a_name(name, extend)
+char *name;
+char *extend;
+{
+  search_dirs_type *search;
+  FILE *result;
+  char buffer[1000];
+  /* First try raw name */
+  result = try_open(name,"");
+  if (result == (FILE *)NULL) {
+    /* Try now prefixes */
+    for (search = search_head;
+        search != (search_dirs_type *)NULL;
+        search = search->next) {
+      sprintf(buffer,"%s/%s", search->name, name);
+      result = try_open(buffer, extend);
+      if (result)break;
+    }
+  }
+  return result;
+}
+
+void ldfile_open_command_file(name)
+char *name;
+{
+  extern FILE *ldlex_input_stack;
+  ldlex_input_stack = find_a_name(name, ".ld");
+
+  if (ldlex_input_stack == (FILE *)NULL) {
+    info("%P%F cannot open load script file %s\n",name);
+  }
+  ldfile_input_filename = name;
+  had_script = true;
+}
+
+
+
+
+void
+ldfile_add_arch(name)
+char *name;
+{
+  search_arch_type *new =
+    (search_arch_type *)ldmalloc(sizeof(search_arch_type));
+  ldfile_output_machine_name = name;
+
+  new->name = name;
+  new->next = (search_arch_type*)NULL;
+  while (*name) {
+    if (isupper(*name)) *name = tolower(*name);
+    name++;
+  }
+  *search_arch_tail_ptr = new;
+  search_arch_tail_ptr = &new->next;
+
+}
diff --git a/ld/ldfile.h b/ld/ldfile.h
new file mode 100644 (file)
index 0000000..876d47f
--- /dev/null
@@ -0,0 +1,27 @@
+/* ldfile.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.  */
+
+
+PROTO(void,ldfile_add_arch,(char *));
+PROTO(void,ldfile_add_library_path,(char *));
+PROTO(void,ldfile_open_command_file,(char *name));
+PROTO(void,ldfile_open_file,(struct lang_input_statement_struct *));
+
diff --git a/ld/ldgram.y b/ld/ldgram.y
new file mode 100644 (file)
index 0000000..aa0f325
--- /dev/null
@@ -0,0 +1,693 @@
+%{
+/* 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.  */
+
+/*
+ * $Id$ 
+ *
+ * $Log$
+ * Revision 1.1  1991/03/21 21:28:41  gumby
+ * Initial revision
+ *
+ * Revision 1.2  1991/03/16  22:27:24  rich
+ * fish
+ *
+ * Revision 1.1  1991/03/13  00:48:21  chrisb
+ * Initial revision
+ *
+ * Revision 1.6  1991/03/10  09:31:26  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.5  1991/03/09  03:25:48  sac
+ * Can now parse the -Ur flag
+ *
+ * Revision 1.4  1991/03/06  02:26:01  sac
+ * Added support for constructor sections.
+ * Remove parsing ambiguity.
+ * Lint
+ *
+ * Revision 1.3  1991/02/22  17:15:13  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/* 
+   This is a YACC grammer intended to parse a superset of the AT&T
+   linker scripting languaue.
+
+
+   Written by Steve Chamberlain steve@cygnus.com
+*/
+
+
+/*SUPPRESS 166*/
+/*SUPPRESS 112*/
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "ld.h"    
+#include "ldexp.h"
+#include "ldversion.h"
+#include "ldlang.h"
+#include "ld-emul.h"
+#include "ldfile.h"
+#include "ldmisc.h"
+#define YYDEBUG 1
+
+boolean option_v;
+
+
+extern unsigned int lineno;
+extern boolean trace_files;
+extern boolean write_map;
+
+boolean hex_mode;
+
+
+
+
+lang_memory_region_type *region;
+
+
+lang_memory_region_type *lang_memory_region_lookup();
+lang_output_section_statement_type *lang_output_section_statement_lookup();
+
+#ifdef __STDC__
+
+void lang_add_data(int type, union etree_union *exp);
+void lang_enter_output_section_statement(char *output_section_statement_name, etree_type *address_exp, bfd_vma block_value);
+
+#else
+
+void lang_add_data();
+void lang_enter_output_section_statement();
+
+#endif /* __STDC__ */
+
+extern args_type command_line;
+char *current_file;
+boolean ldgram_want_filename = true;
+boolean had_script = false;
+boolean force_make_executable = false;
+boolean ldgram_mustbe_filename = false;
+boolean ldgram_mustbe_symbolname = false;
+boolean ldgram_has_inputfile = false;
+
+/* LOCALS */
+
+
+
+
+%}
+%union {
+  bfd_vma integer;
+  int voidval;
+  char *name;
+  int token;
+  union etree_union *etree;
+  asection *section;
+  struct lang_output_section_statement_struct *output_section_statement;
+  union  lang_statement_union **statement_ptr;
+  int lineno;
+  struct {
+    FILE *file;
+    char *name;
+    unsigned int lineno;
+  } state;
+
+  
+}
+
+%type <etree> exp  opt_exp  exp_head
+%type <integer> fill_opt opt_block
+%type <name> memspec_opt
+%token <integer> INT CHAR 
+%token <name> NAME
+%type  <integer> length
+
+%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ  '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
+%right <token> '?' ':'
+%left <token> OROR
+%left <token>  ANDAND
+%left <token> '|'
+%left <token>  '^'
+%left  <token> '&'
+%left <token>  EQ NE
+%left  <token> '<' '>' LE GE
+%left  <token> LSHIFT RSHIFT
+%left  <token> '+' '-'
+%left  <token> '*' '/' '%'
+%right UNARY
+%left <token> '('
+%token <token> ALIGN_K BLOCK LONG SHORT BYTE
+%token SECTIONS  
+%token '{' '}'
+%token ALIGNMENT SIZEOF_HEADERS
+%token NEXT SIZEOF ADDR 
+%token MEMORY 
+%token DSECT NOLOAD COPY INFO OVERLAY 
+%token NAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY 
+%token OPTION_e OPTION_c OPTION_noinhibit_exec OPTION_s OPTION_S OPTION_format
+%token OPTION_d OPTION_dc OPTION_dp OPTION_x OPTION_X
+%token OPTION_v OPTION_M OPTION_t STARTUP HLL SYSLIB FLOAT NOFLOAT OPTION_defsym
+%token OPTION_n OPTION_r OPTION_o OPTION_b  OPTION_A
+%token <name> OPTION_l OPTION_L  OPTION_T OPTION_Aarch OPTION_Tfile  OPTION_Texp
+%token OPTION_Ur 
+%token ORIGIN FILL OPTION_g
+%token LENGTH  BIND SUBSECTION_ALIGN   CREATE_OBJECT_SYMBOLS INPUT OUTPUT
+%type <token> assign_op SIZEOF NEXT ADDR 
+%type <etree> assignment
+%type <name>  filename
+
+%{
+ld_config_type config;
+%}
+
+%%
+
+
+
+file:  command_line  { lang_final(); };
+
+
+filename:
+       {
+       ldgram_mustbe_filename =true;
+       }
+       NAME
+       {
+       ldgram_mustbe_filename = false;
+       $$ = $2;
+       }
+
+command_line:
+               command_line command_line_option
+       |
+       ;
+
+command_line_option:
+               OPTION_v
+                       {       
+                       ldversion();
+                       option_v = true;
+                       }
+       |       OPTION_t {
+                       trace_files = true;
+                       }
+       |       OPTION_M {
+                       write_map = true;
+                       }
+       |       OPTION_n {
+                       config.magic_demand_paged = false;
+                       config.make_executable = false;
+                       }
+        |       OPTION_s {
+                       strip_symbols = STRIP_ALL;
+                       }
+       |       OPTION_S {
+                       strip_symbols = STRIP_DEBUGGER;
+                       }
+                       
+       |       OPTION_r {
+                       config.relocateable_output = true;
+                       config.build_constructors = false;
+                       config.magic_demand_paged = false;
+                       }
+        |       OPTION_Ur {
+                       config.relocateable_output = true;
+                       config.build_constructors = true;
+                       config.magic_demand_paged = false;
+                     }             
+       |       OPTION_o filename
+                       {
+                       lang_add_output($2); 
+                       }
+       |       OPTION_e NAME
+                       { lang_add_entry($2); 
+                       }
+       |       OPTION_X {
+                       discard_locals = DISCARD_L;
+               }
+       |       OPTION_x {
+                       discard_locals = DISCARD_ALL;
+               }
+
+       |       OPTION_noinhibit_exec
+                       {
+                       force_make_executable = true;
+                       }
+        |      OPTION_d {
+                         command_line.force_common_definition = true;
+                       }
+        |      OPTION_dc
+                        {
+                         command_line.force_common_definition = true;
+                       }
+       |       OPTION_g
+                       {
+                       /* Ignored */
+                       }
+        |      OPTION_dp
+                        {
+                         command_line.force_common_definition = true;
+                       }
+        | OPTION_format NAME
+           {
+            lang_add_target($2);
+           }
+
+       | OPTION_Texp { hex_mode  =true; } 
+                 exp_head
+               { lang_section_start($1, $3);
+                 hex_mode = false; }
+       
+       | OPTION_Aarch 
+               { ldfile_add_arch($1); }
+       | OPTION_b NAME
+                       {
+                       lang_add_target($2);
+                       }
+       |       OPTION_L
+                       {
+                       ldfile_add_library_path($1);
+               }
+       |       ifile_p1
+       |       input_list
+       |       OPTION_c filename
+                       { ldfile_open_command_file($2); }
+       |       OPTION_Tfile
+                       { ldfile_open_command_file($1); }
+
+       |       OPTION_T filename
+                       { ldfile_open_command_file($2); }
+
+       |       OPTION_l
+                       {
+                         lang_add_input_file($1,
+                                        lang_input_file_is_l_enum,
+                                        (char *)NULL);
+                       }
+       |       OPTION_A filename
+                       {
+                       lang_add_input_file($2,
+                               lang_input_file_is_symbols_only_enum,
+                               (char *)NULL);
+                       }
+       |       OPTION_defsym assignment_with_nospaces
+       ;
+
+
+input_section_spec:
+               NAME
+               {
+               lang_add_wild((char *)NULL, $1);
+               }
+        |      '[' 
+                       {
+                       current_file = (char *)NULL;
+                       }
+                       file_NAME_list  
+               ']' 
+       |       NAME
+                       {
+                       current_file  =$1;
+                       } 
+               '(' file_NAME_list ')'
+       |       '*' 
+                       {       
+                       current_file = (char *)NULL;
+                       } 
+               '(' file_NAME_list ')'
+       ;
+
+
+
+file_NAME_list:
+               NAME
+                       { lang_add_wild($1, current_file); }
+       |       file_NAME_list opt_comma NAME 
+                       { lang_add_wild($3, current_file); }
+       ;
+
+
+
+ifile_p1:
+               memory
+       |       sections
+       |       startup
+       |       high_level_library
+       |       low_level_library
+       |       floating_point_support
+       |       assignment end
+       |       TARGET_K '(' NAME ')'
+               { lang_add_target($3); }
+       |       SEARCH_DIR '(' filename ')'
+               { ldfile_add_library_path($3); }
+       |       OUTPUT '(' filename ')'
+               { lang_add_output($3); }
+       |       INPUT '(' input_list ')'
+       |       MAP '(' filename ')'
+               { lang_add_map($3); }
+       ;
+
+input_list:
+               NAME
+               { lang_add_input_file($1,lang_input_file_is_file_enum,
+                                (char *)NULL); }
+       |       input_list ',' NAME
+               { lang_add_input_file($3,lang_input_file_is_file_enum,
+                                (char *)NULL); }
+       |       input_list   NAME
+               { lang_add_input_file($2, lang_input_file_is_file_enum,
+                                (char *)NULL); }
+       ;
+
+sections:
+               SECTIONS '{'sec_or_group_p1  '}' 
+       ;
+
+sec_or_group_p1:
+               sec_or_group_p1 section
+       |       sec_or_group_p1 statement_anywhere
+       |
+       ;
+
+statement_anywhere:
+               ENTRY '(' NAME ')'
+               { lang_add_entry($3); }
+       |       assignment end
+       ;
+
+statement:
+               statement assignment end
+       |       statement CREATE_OBJECT_SYMBOLS
+               { lang_add_attribute(lang_object_symbols_statement_enum); }
+       |       statement input_section_spec
+        |       statement length '(' exp_head ')'
+                       {
+                       lang_add_data($2,$4);
+                       }
+  
+       |       statement FILL '(' exp_head ')'
+                       {
+                         lang_add_fill
+                           (exp_get_value_int($4,
+                                              0,
+                                              "fill value",
+                                              lang_first_phase_enum));
+                       }
+       |
+       ;
+
+length:
+               LONG  
+                       { $$ = $1; }
+       |       SHORT 
+                       { $$ = $1; }
+       |       BYTE 
+                       { $$ = $1; }
+       ;
+
+fill_opt:
+          '=' exp_head
+               {
+                 $$ =   exp_get_value_int($2,
+                                          0,
+                                          "fill value",
+                                          lang_first_phase_enum); 
+               }
+       |       {  $$ = 0; }
+       ;
+
+               
+
+assign_op:
+               PLUSEQ
+                       { $$ = '+'; }
+       |       MINUSEQ 
+                       { $$ = '-'; }
+       |       MULTEQ
+                       { $$ = '*'; }
+       |       DIVEQ
+                       { $$ = '/'; }
+       |       LSHIFTEQ
+                       { $$ = LSHIFT; }
+       |       RSHIFTEQ
+                       { $$ = RSHIFT; }
+       |       ANDEQ
+                       { $$ = '&'; }
+       |       OREQ
+                       { $$ = '|'; }
+
+       ;
+
+end:   ';' | ','
+       ;
+
+assignment_with_nospaces:
+       { ldgram_want_filename = false; }
+               assignment
+       { ldgram_want_filename = true; }
+       ;
+
+assignment:
+       
+               NAME '=' exp_head 
+               {
+                 lang_add_assignment(exp_assop($2,$1,$3));
+               }
+       |       NAME assign_op exp_head 
+               {
+                 lang_add_assignment(exp_assop('=',$1,exp_binop($2,exp_nameop(NAME,$1),$3)));
+               }
+               
+       ;
+
+
+opt_comma:
+               ','     |       ;
+
+
+memory:
+               MEMORY '{' memory_spec memory_spec_list '}'
+       ;
+
+memory_spec_list:
+               memory_spec_list memory_spec 
+       |       memory_spec_list ',' memory_spec
+       |
+       ;
+
+
+memory_spec:
+               NAME 
+                       { region = lang_memory_region_lookup($1); }
+               attributes_opt  ':' origin_spec opt_comma length_spec
+
+               {
+                
+
+               }
+       ;
+origin_spec:
+       ORIGIN '=' exp
+               { region->current =
+                region->origin =
+                exp_get_vma($3, 0L,"origin", lang_first_phase_enum); }
+       ;
+length_spec:
+             LENGTH '=' exp            
+               {  region->length = exp_get_vma($3,
+                                              ~((bfd_vma)0),
+                                              "length",
+                                              lang_first_phase_enum);
+               }
+       
+
+attributes_opt:
+                 '(' NAME ')'
+                       {
+                       lang_set_flags(&region->flags, $2);
+                       }
+       |
+  
+       ;
+
+startup:
+       STARTUP '(' filename ')'
+               { lang_startup($3); }
+       ;
+
+high_level_library:
+               HLL '('  high_level_library_NAME_list ')'
+       |       HLL '('  ')'
+                       { ldemul_hll((char *)NULL); }
+       ;
+
+high_level_library_NAME_list:
+               high_level_library_NAME_list  opt_comma filename
+                       { ldemul_hll($3); }
+       |       filename
+                       { ldemul_hll($1); }
+
+       ;
+
+low_level_library:
+       SYSLIB '(' low_level_library_NAME_list ')'
+       ;
+low_level_library_NAME_list:
+               low_level_library_NAME_list opt_comma filename
+                       { ldemul_syslib($3); }                          
+       |
+       ;
+
+floating_point_support:
+               FLOAT
+                       { lang_float(true); }
+       |       NOFLOAT
+                       { lang_float(false); }  
+       ;
+               
+
+       
+
+exp    :
+               '-' exp    %prec UNARY
+                       { $$ = exp_unop('-', $2); }
+       |       '(' exp ')'
+                       { $$ = $2; }
+       |       NEXT '(' exp ')' %prec UNARY
+                       { $$ = exp_unop($1,$3); }
+       |       '!' exp    %prec UNARY
+                       { $$ = exp_unop('!', $2); }
+       |       '+' exp    %prec UNARY
+                       { $$ = $2; }
+       |       '~' exp    %prec UNARY
+                       { $$ = exp_unop('~', $2);}
+
+       |       exp '*' exp
+                       { $$ = exp_binop('*', $1, $3); }
+       |       exp '/' exp
+                       { $$ = exp_binop('/', $1, $3); }
+       |       exp '%' exp
+                       { $$ = exp_binop('%', $1, $3); }
+       |       exp '+' exp
+                       { $$ = exp_binop('+', $1, $3); }
+       |       exp '-' exp
+                       { $$ = exp_binop('-' , $1, $3); }                       
+       |       exp LSHIFT exp
+                       { $$ = exp_binop(LSHIFT , $1, $3); }
+       |       exp RSHIFT exp
+                       { $$ = exp_binop(RSHIFT , $1, $3); }
+       |       exp EQ exp
+                       { $$ = exp_binop(EQ , $1, $3); }
+       |       exp NE exp
+                       { $$ = exp_binop(NE , $1, $3); }
+       |       exp LE exp
+                       { $$ = exp_binop(LE , $1, $3); }
+       |       exp GE exp
+                       { $$ = exp_binop(GE , $1, $3); }
+       |       exp '<' exp
+                       { $$ = exp_binop('<' , $1, $3); }
+       |       exp '>' exp
+                       { $$ = exp_binop('>' , $1, $3); }
+       |       exp '&' exp
+                       { $$ = exp_binop('&' , $1, $3); }
+       |       exp '^' exp
+                       { $$ = exp_binop('^' , $1, $3); }
+       |       exp '|' exp
+                       { $$ = exp_binop('|' , $1, $3); }
+       |       exp '?' exp ':' exp
+                       { $$ = exp_trinop('?' , $1, $3, $5); }
+       |       exp ANDAND exp
+                       { $$ = exp_binop(ANDAND , $1, $3); }
+       |       exp OROR exp
+                       { $$ = exp_binop(OROR , $1, $3); }
+       |       DEFINED '(' NAME ')'
+                       { $$ = exp_nameop(DEFINED, $3); }
+       |       INT
+                       { $$ = exp_intop($1); }
+
+       |       SIZEOF  '('  NAME ')'
+                       { $$ = exp_nameop($1,$3); }
+       |       ADDR '(' NAME ')'
+                       { $$ = exp_nameop($1,$3); }
+       |       ALIGN_K '(' exp ')'
+                       { $$ = exp_unop($1,$3); }
+       |       NAME
+                       { $$ = exp_nameop(NAME,$1); }
+       ;
+
+
+
+
+section:       NAME opt_exp opt_block ':' opt_things'{' 
+               {
+               lang_enter_output_section_statement($1,$2,$3);
+               }
+              statement        '}'     fill_opt memspec_opt
+               {
+                 lang_leave_output_section_statement($10, $11);
+               }
+
+       ;
+
+opt_things: 
+       {
+
+       }
+       ;
+
+exp_head:
+       { ldgram_mustbe_symbolname = true; }
+       exp
+       { ldgram_mustbe_symbolname = false; 
+       $$ = $2;
+       }
+
+opt_exp:
+               exp
+                       { $$ = $1; }
+       |               { $$= (etree_type *)NULL; }
+       ;
+
+opt_block:
+               BLOCK '(' exp_head ')'
+               { $$ = exp_get_value_int($3,
+                                        1L,
+                                        "block",
+                                        lang_first_phase_enum); 
+               }
+       |       { $$  = 1; }
+       ;
+  
+memspec_opt:
+               '>' NAME
+               { $$ = $2; }
+       |       { $$ = "*default*"; }
+       ;
+
diff --git a/ld/ldlang.c b/ld/ldlang.c
new file mode 100644 (file)
index 0000000..1fccbc2
--- /dev/null
@@ -0,0 +1,2231 @@
+/* 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.  */
+
+/* $Id$ 
+ *
+ * $Log$
+ * Revision 1.1  1991/03/21 21:28:45  gumby
+ * Initial revision
+ *
+ * Revision 1.3  1991/03/16  22:19:21  rich
+ * pop
+ *
+ * Revision 1.2  1991/03/15  18:52:42  rich
+ * pop
+ *
+ * Revision 1.1  1991/03/13  00:48:23  chrisb
+ * Initial revision
+ *
+ * Revision 1.8  1991/03/10  09:31:28  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.7  1991/03/09  03:31:03  sac
+ * After a fatal info message, the output file is deleted.
+ *
+ * Revision 1.6  1991/03/09  03:25:06  sac
+ * Added support for LONG, SHORT and BYTE keywords in scripts
+ *
+ * Revision 1.5  1991/03/06  21:59:31  sac
+ * Completed G++ support
+ *
+ * Revision 1.4  1991/03/06  02:26:02  sac
+ * Added support for constructor sections.
+ * Remove parsing ambiguity.
+ * Lint
+ *
+ * Revision 1.3  1991/02/22  17:15:01  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+
+
+#include "sysdep.h" 
+#include "bfd.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldsym.h"
+#include "ldgram.tab.h"
+#include "ldmisc.h"
+#include "ldlang.h"
+#include "ldexp.h"
+#include "ld-emul.h"
+#include "ldlex.h"
+
+/* EXPORTS */
+
+
+
+extern unsigned int undefined_global_sym_count;
+
+static char *startup_file;
+static lang_input_statement_type *first_file;
+lang_statement_list_type statement_list;
+lang_statement_list_type *stat_ptr = &statement_list;
+lang_statement_list_type lang_output_section_statement;
+lang_statement_list_type input_file_chain;
+lang_statement_list_type file_chain;
+extern char *current_file;
+static boolean placed_commons = false;
+
+boolean lang_float_flag;
+
+static lang_output_section_statement_type *default_common_section;
+
+
+/* FORWARDS */
+PROTO(static void, print_statements,(void));
+PROTO(static void, print_statement,(lang_statement_union_type *,
+                                    lang_output_section_statement_type *));
+
+
+
+/* EXPORTS */
+boolean lang_has_input_file = false;
+
+
+extern bfd *output_bfd;
+size_t largest_section;
+
+
+extern enum bfd_architecture ldfile_output_architecture;
+extern unsigned long ldfile_output_machine;
+extern char *ldfile_output_machine_name;
+
+
+extern ldsym_type *symbol_head;
+
+bfd_vma print_dot;
+unsigned int commons_pending;
+
+
+
+
+extern args_type command_line;
+extern ld_config_type config;
+
+char *entry_symbol;
+
+
+
+lang_output_section_statement_type *create_object_symbols;
+
+extern boolean had_script;
+static boolean map_option_f;
+
+
+boolean had_output_filename = false;
+extern boolean write_map;
+
+
+
+
+
+
+size_t longest_section_name = 8;
+
+
+lang_input_statement_type *script_file;
+
+section_userdata_type common_section_userdata;
+asection common_section;
+
+#ifdef __STDC__
+#define cat(a,b) a##b
+#else
+#define cat(a,b) a/**/b
+#endif
+
+#define new_stat(x,y) (cat(x,_type)*) new_statement(cat(x,_enum), sizeof(cat(x,_type)),y)
+
+#define outside_section_address(q) ( (q)->output_offset + (q)->output_section->vma)
+
+#define outside_symbol_address(q) ((q)->value +   outside_section_address(q->section))
+
+boolean option_longmap = false;
+
+static void lang_list_init(list)
+lang_statement_list_type *list;
+{
+list->head = (lang_statement_union_type *)NULL;
+list->tail = &list->head;
+}
+
+static void 
+print_section(name)
+char *name;
+{
+  printf("%*s", -longest_section_name, name);
+}
+static void 
+print_space()
+{
+  printf(" ");
+}
+static void 
+print_nl()
+{
+  printf("\n");
+}
+static void 
+print_address(value)
+bfd_vma value;
+{
+  printf("%8lx", value);
+}
+static void 
+print_size(value)
+size_t value;
+{
+  printf("%5x", (unsigned)value);
+}
+static void 
+print_alignment(value)
+unsigned int value;
+{
+  printf("2**%2u",value);
+}
+static void 
+print_fill(value)
+fill_type value;
+{
+  printf("%04x",(unsigned)value);
+}
+
+
+static
+lang_statement_union_type *new_statement(type, size, list)
+enum statement_enum type;
+size_t size;
+lang_statement_list_type *list;
+{
+  lang_statement_union_type *new = (lang_statement_union_type *)
+    ldmalloc(size);
+  new->header.type = type;
+  new->header.next = (lang_statement_union_type *)NULL;
+ lang_statement_append(list, new, &new->header.next);
+  return new;
+}
+
+static lang_input_statement_type *
+new_afile(name, file_type, target)
+char *name;
+lang_input_file_enum_type file_type;
+char *target;
+{
+  lang_input_statement_type *p = new_stat(lang_input_statement, 
+                                         stat_ptr);
+  lang_has_input_file = true;
+  p->target = target;
+  switch (file_type) {
+  case  lang_input_file_is_symbols_only_enum:
+    p->filename = name;
+    p->is_archive =false;
+    p->real = true;
+    p->local_sym_name= name;
+    p->just_syms_flag = true;
+    p->search_dirs_flag = false;
+    break;
+  case lang_input_file_is_fake_enum:
+    p->filename = name;
+    p->is_archive =false;
+    p->real = false;
+    p->local_sym_name= name;
+    p->just_syms_flag = false;
+    p->search_dirs_flag =false;
+
+    break;
+  case lang_input_file_is_l_enum:
+    p->is_archive = true;
+    p->filename = name;
+    p->real = true;
+    p->local_sym_name = concat("-l",name,"");
+    p->just_syms_flag = false;
+    p->search_dirs_flag = true;
+    break;
+
+  case lang_input_file_is_search_file_enum:
+  case lang_input_file_is_marker_enum:
+    p->filename = name;
+    p->is_archive =false;
+    p->real = true;
+    p->local_sym_name= name;
+    p->just_syms_flag = false;
+    p->search_dirs_flag =true;
+    break;
+
+
+
+  case lang_input_file_is_file_enum:
+    p->filename = name;
+    p->is_archive =false;
+    p->real = true;
+    p->local_sym_name= name;
+    p->just_syms_flag = false;
+    p->search_dirs_flag =false;
+    break;
+
+
+  default:
+    FAIL();
+  }
+  p->asymbols = (asymbol **)NULL;
+  p->superfile = (lang_input_statement_type *)NULL;
+
+  p->next_real_file = (lang_statement_union_type*)NULL;
+  p->next = (lang_statement_union_type*)NULL;
+  p->symbol_count = 0;
+  p->common_output_section = (asection *)NULL;
+
+  lang_statement_append(&input_file_chain,
+                       (lang_statement_union_type *)p,
+                       &p->next_real_file);
+  return p;
+}
+
+lang_input_statement_type *
+lang_add_input_file(name,
+                   file_type, 
+                   target)
+char *name;
+lang_input_file_enum_type file_type;
+char *target;
+{
+  /* Look it up or build a new one */
+
+  lang_input_statement_type *p;
+
+  for (p = (lang_input_statement_type *)input_file_chain.head;
+       p != (lang_input_statement_type *)NULL;
+       p = (lang_input_statement_type *)(p->next_real_file))
+    {
+      /* Sometimes we have incomplete entries in here */
+      if (p->filename != (char *)NULL) {
+       if(strcmp(name,p->filename) == 0)  return p;
+      }
+    }
+
+  return  new_afile(name, file_type, target);
+}
+
+
+
+void
+lang_init()
+{
+
+  stat_ptr= &statement_list;
+  lang_list_init(stat_ptr);
+
+  lang_list_init(&input_file_chain);
+  lang_list_init(&lang_output_section_statement);
+  lang_list_init(&file_chain);
+  first_file = lang_add_input_file((char *)NULL, 
+                                  lang_input_file_is_marker_enum,
+                                  (char *)NULL);
+
+}
+
+static void 
+lang_init2()
+{
+  script_file = lang_add_input_file("script file",
+                                   lang_input_file_is_fake_enum,
+                                   (char *)NULL);
+  script_file->the_bfd = bfd_create("script file", output_bfd);
+  script_file->symbol_count = 0;
+
+  common_section.userdata = &common_section_userdata;
+
+}
+
+
+
+/*  this function mainains a dictionary of regions. If the *default*
+    region is asked for then a pointer to the first region is
+    returned. If there is no first pointer then one is created 
+*/
+
+static lang_memory_region_type *lang_memory_region_list;
+static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list;
+
+lang_memory_region_type *
+lang_memory_region_lookup(name)
+char *name;
+{
+
+    lang_memory_region_type *p  = lang_memory_region_list;
+    for (p = lang_memory_region_list;
+        p != ( lang_memory_region_type *)NULL;
+        p = p->next) {
+       if (strcmp(p->name, name) == 0) {
+           return p;
+       }
+    }
+    if (strcmp(name,"*default*")==0) {
+       /* This is the default region, dig out first one on the list */
+       if (lang_memory_region_list != (lang_memory_region_type*)NULL){
+           return lang_memory_region_list;
+       }
+    }
+    {
+       lang_memory_region_type *new =
+           (lang_memory_region_type *)ldmalloc(sizeof(lang_memory_region_type));
+       new->name = name;
+       new->next = (lang_memory_region_type *)NULL;
+
+       *lang_memory_region_list_tail = new;
+       lang_memory_region_list_tail = &new->next;
+       new->origin = 0;
+       new->length = ~0;
+       new->current = 0;
+       return new;
+    }
+}
+
+
+
+lang_output_section_statement_type *
+lang_output_section_find(name)
+char *name;
+{
+  lang_statement_union_type *u;
+  lang_output_section_statement_type *lookup;
+
+  for (u = lang_output_section_statement.head;
+       u != (lang_statement_union_type *)NULL;
+       u = lookup->next)
+    {
+      lookup = &u->output_section_statement;
+      if (strcmp(name, lookup->name)==0) {
+       return lookup;
+      }
+    }
+  return (lang_output_section_statement_type *)NULL;
+}
+
+lang_output_section_statement_type *
+lang_output_section_statement_lookup(name)
+char *name;
+
+{
+  lang_output_section_statement_type *lookup;
+  lookup =lang_output_section_find(name);
+  if (lookup == (lang_output_section_statement_type *)NULL) {
+    
+    lookup =(lang_output_section_statement_type *)
+      new_stat(lang_output_section_statement, stat_ptr);
+    lookup->region = (lang_memory_region_type *)NULL;
+    lookup->fill = 0;
+    lookup->block_value = 1;
+    lookup->name = name;
+
+    lookup->next = (lang_statement_union_type*)NULL;  
+    lookup->bfd_section = (asection *)NULL;
+    lookup->processed = false;
+    lookup->addr_tree = (etree_type *)NULL;
+    lang_list_init(&lookup->children);
+
+    lang_statement_append(&lang_output_section_statement,
+                         (lang_statement_union_type *)lookup,
+                         &lookup->next);
+  }
+  return lookup;
+}
+
+
+
+
+
+static void
+  print_flags(outfile, ignore_flags)
+FILE *outfile;
+lang_section_flags_type *ignore_flags;
+{
+  fprintf(outfile,"(");
+#if 0
+  if (flags->flag_read) fprintf(outfile,"R");
+  if (flags->flag_write) fprintf(outfile,"W");
+  if (flags->flag_executable) fprintf(outfile,"X");
+  if (flags->flag_loadable) fprintf(outfile,"L");
+#endif
+  fprintf(outfile,")");
+}
+
+void
+lang_map(outfile)
+     FILE *outfile;
+{
+  lang_memory_region_type *m;
+  fprintf(outfile,"**MEMORY CONFIGURATION**\n\n");
+
+  fprintf(outfile,"name\t\torigin\t\tlength\t\tattributes\n");
+  for (m = lang_memory_region_list;
+       m != (lang_memory_region_type *)NULL;
+       m = m->next) 
+    {
+      fprintf(outfile,"%-16s", m->name);
+
+      fprintf(outfile,"%08lx\t%08lx\t", m->origin, m->length);
+      print_flags(outfile, &m->flags);
+      fprintf(outfile,"\n");
+    }
+  fprintf(outfile,"\n\n**LINK EDITOR MEMORY MAP**\n\n");
+  fprintf(outfile,"output\t\tinput\t\tvirtual\n");
+  fprintf(outfile,"section\t\tsection\t\taddress\tsize\n\n");
+
+  print_statements();
+
+}
+
+/*
+ *
+ */
+static void init_os(s) 
+lang_output_section_statement_type *s;
+{
+  section_userdata_type *new =
+    (section_userdata_type *)
+      ldmalloc(sizeof(section_userdata_type));
+
+  s->bfd_section = bfd_make_section(output_bfd, s->name);
+  s->bfd_section->output_section = s->bfd_section;
+  s->bfd_section->flags = SEC_NO_FLAGS;
+  /* We initialize an output sections output offset to minus its own */
+  /* vma to allow us to output a section through itself */
+  s->bfd_section->output_offset = 0;
+  get_userdata( s->bfd_section) = new;
+}
+
+static void
+wild_doit(ptr, section,output, file)
+lang_statement_list_type *ptr;
+asection *section;
+lang_output_section_statement_type *output;
+lang_input_statement_type *file;
+{
+  if(output->bfd_section == (asection *)NULL)
+    {
+      init_os(output);
+    }
+
+  if (section != (asection *)NULL 
+      && section->output_section == (asection *)NULL) {
+    /* Add a section reference to the list */
+    lang_input_section_type *new = new_stat(lang_input_section, ptr);
+
+    new->section = section;
+    new->ifile = file;
+    section->output_section = output->bfd_section;
+    section->output_section->flags |= section->flags;
+    if (section->alignment_power > output->bfd_section->alignment_power) {
+       output->bfd_section->alignment_power = section->alignment_power;
+      }
+      
+  }
+}
+
+static asection *
+our_bfd_get_section_by_name(abfd, section)
+bfd *abfd;
+char *section;
+{
+  return bfd_get_section_by_name(abfd, section);
+
+}
+static void 
+wild_section(ptr, section, file , output)
+lang_wild_statement_type *ptr;
+char *section;
+lang_input_statement_type *file;
+lang_output_section_statement_type *output;
+{
+  asection *s;
+  if (section == (char *)NULL) {
+    /* Do the creation to all sections in the file */
+    for (s = file->the_bfd->sections; s != (asection *)NULL; s=s->next)  {
+      wild_doit(&ptr->children, s, output, file);
+    }
+  }
+  else {
+    /* Do the creation to the named section only */
+    wild_doit(&ptr->children,
+             our_bfd_get_section_by_name(file->the_bfd, section),
+             output, file);
+  }
+
+
+
+}
+
+
+
+static
+lang_input_statement_type *lookup_name(name, target)
+char *name;
+char *target;
+{
+  lang_input_statement_type *search;
+  for(search = (lang_input_statement_type *)input_file_chain.head;
+      search != (lang_input_statement_type *)NULL;
+      search = (lang_input_statement_type *)search->next_real_file)
+    {
+      if (search->filename == (char *)NULL && name == (char *)NULL) {
+       return search;
+      }
+      if (search->filename != (char *)NULL && name != (char *)NULL) {
+       if (strcmp(search->filename, name) == 0)  {
+         Q_read_file_symbols(search);
+         return search;
+       }
+      }
+    }
+
+  /* There isn't an afile entry for this file yet, this must be */
+  /* because the name has only appeared inside a load script and not */
+  /* on the command line */
+  search = new_afile(name, lang_input_file_is_file_enum, target);
+  Q_read_file_symbols(search);
+  return search;
+}
+
+static void
+
+wild(s, section, file, target, output)
+lang_wild_statement_type *s;
+char *section;
+char *file;
+char *target;
+lang_output_section_statement_type *output;
+{
+  lang_input_statement_type *f;
+  if (file == (char *)NULL) {
+    /* Perform the iteration over all files in the list */
+    for (f = (lang_input_statement_type *)file_chain.head;
+        f != (lang_input_statement_type *)NULL;
+        f = (lang_input_statement_type *)f->next) {
+      wild_section(s,  section, f, output);
+    }
+  }
+  else {
+    /* Perform the iteration over a single file */
+    wild_section( s, section, lookup_name(file, target), output);
+  }
+}
+
+/*
+  read in all the files 
+  */
+static bfd *   
+open_output(name, target)
+char *name;
+char *target;
+{
+  extern char *output_filename;
+  bfd * output = bfd_openw(name, target);
+  output_filename = name;          
+  if (output == (bfd *)NULL) 
+    {
+      if (bfd_error == invalid_target) {
+       info("%P%F target %s not found\n", target);
+      }
+      info("%P%F problem opening output file %s, %E", name);
+    }
+  
+  output->flags |= D_PAGED;
+  bfd_set_format(output, bfd_object);
+  return output;
+}
+extern char  *default_target;
+static void
+lang_phase_0(sh,target)
+lang_statement_union_type *sh;
+char *target;
+{
+  lang_statement_union_type *s = (lang_statement_union_type *)sh;
+  for (; s != (lang_statement_union_type *)NULL ; s = s->next) 
+    {
+      switch (s->header.type) {
+      case lang_output_section_statement_enum:
+       lang_phase_0(s->output_section_statement.children.head,
+                    target);
+       break;
+      case lang_output_statement_enum:
+#if 1
+       output_bfd = open_output(s->output_statement.name,
+                                target == (char *)NULL ?
+                                default_target : target);
+       ldemul_set_output_arch();
+#endif
+       break;
+      case lang_target_statement_enum:
+       target = s->target_statement.target;
+       break;
+      case lang_wild_statement_enum:
+       /* Maybe we should load the file's symbols */
+       if (s->wild_statement.filename) {
+         (void)  lookup_name(s->wild_statement.filename, target);
+       }
+       break;
+       /* Attatch this to the current output section */
+      case lang_common_statement_enum:
+      case lang_fill_statement_enum:
+      case lang_input_section_enum:
+      case lang_object_symbols_statement_enum:
+      case lang_address_statement_enum:
+      case lang_data_statement_enum:
+       break;
+      case lang_afile_asection_pair_statement_enum:
+
+       FAIL();
+       break;
+          
+      case lang_input_statement_enum:
+       if (s->input_statement.real == true) {
+         s->input_statement.target = target;
+         lookup_name(s->input_statement.filename, target);
+       }
+       break;
+      case lang_assignment_statement_enum:
+#if 0
+       (void)    exp_fold_tree(s->assignment_statement.exp,
+                               output_section,
+                               false);
+#endif
+       break;
+
+      case lang_padding_statement_enum:
+       
+       break;
+      }
+    }
+
+}
+
+/* If there are [COMMONS] statements, put a wild one into the bss section */
+
+static void
+lang_reasonable_defaults()
+{
+  default_common_section = 
+    lang_output_section_statement_lookup(".bss");
+  if (placed_commons == false) {
+    lang_wild_statement_type *new =
+      new_stat(lang_wild_statement,
+              &default_common_section->children);
+    new->section_name = "COMMON";
+    new->filename = (char *)NULL;
+    lang_list_init(&new->children);
+  }
+}
+
+static void lang()
+{
+  if (had_script == false) {
+    parse_line(ldemul_get_script());
+  }
+
+  lang_reasonable_defaults();
+  lang_phase_0(statement_list.head,default_target);
+}
+
+
+/* Open input files and attatch to output sections */
+static void
+lang_open_input(s, target, output_section_statement)
+lang_statement_union_type *s;
+char *target;
+lang_output_section_statement_type *output_section_statement;
+{
+  for (; s != (lang_statement_union_type *)NULL ; s = s->next) 
+    {
+      switch (s->header.type) {
+      case lang_wild_statement_enum:
+       wild(&s->wild_statement, s->wild_statement.section_name,
+            s->wild_statement.filename, target,
+            output_section_statement);
+
+       break;
+
+      case lang_output_section_statement_enum:
+       lang_open_input(s->output_section_statement.children.head,
+                       target,
+                       &s->output_section_statement);
+       break;
+      case lang_output_statement_enum:
+       break;
+      case lang_target_statement_enum:
+       target = s->target_statement.target;
+       break;
+      case lang_common_statement_enum:
+      case lang_fill_statement_enum:
+      case lang_input_section_enum:
+      case lang_object_symbols_statement_enum:
+      case lang_data_statement_enum:
+       break;
+      case lang_afile_asection_pair_statement_enum:
+       FAIL();
+       break;
+
+      case lang_assignment_statement_enum:
+      case lang_padding_statement_enum:
+
+       break;
+      case lang_address_statement_enum:
+       /* Mark the specified section with the supplied address */
+       {
+         lang_output_section_statement_type *os =
+           lang_output_section_statement_lookup
+             (s->address_statement.section_name);
+         os->addr_tree = s->address_statement.address;
+       }
+       break;
+      case lang_input_statement_enum:
+       /* A standard input statement, has no wildcards */
+       /*      Q_read_file_symbols(&s->input_statement);*/
+       break;
+      }
+    }
+}
+
+
+
+
+
+static void 
+print_output_section_statement(output_section_statement)
+lang_output_section_statement_type *output_section_statement;
+{
+  asection *section = output_section_statement->bfd_section;
+  print_nl();
+  print_section(output_section_statement->name);
+
+  if (section) {
+    print_dot = section->vma;
+    print_space();
+    print_section("");
+    print_space();
+    print_address(section->vma);
+    print_space();
+    print_size(section->size);
+    print_space();
+    print_alignment(section->alignment_power);
+    print_space();
+#if 0
+    printf("%s flags", output_section_statement->region->name);
+    print_flags(stdout, &output_section_statement->flags);
+#endif
+
+  }
+  else {
+    printf("No attached output section");
+  }
+  print_nl();
+  print_statement(output_section_statement->children.head,
+                 output_section_statement);
+
+}
+
+static void 
+print_assignment(assignment, output_section)
+lang_assignment_statement_type *assignment;
+lang_output_section_statement_type *output_section;
+{
+  etree_value_type result;
+  print_section("");
+  print_space();
+  print_section("");
+  print_space();
+  print_address(print_dot);
+  print_space();
+  result = exp_fold_tree(assignment->exp->assign.src,
+                        output_section,
+                        lang_final_phase_enum,
+                        print_dot,
+                        &print_dot);
+                        
+  if (result.valid) {
+    print_address(result.value);
+  }
+  else 
+    {
+      printf("*undefined*");
+    }
+  print_space();
+  exp_print_tree(stdout, assignment->exp);
+  printf("\n");
+}
+
+static void
+print_input_statement(statm)
+lang_input_statement_type *statm;
+{
+  printf("LOAD %s\n",statm->filename);
+}
+
+static void print_symbol(q)
+asymbol *q;
+{
+  print_section("");
+  printf(" ");
+  print_section("");
+  printf(" ");
+  print_address(outside_symbol_address(q));
+  printf("              %s", q->name ? q->name : " ");
+  print_nl();
+}
+static void 
+print_input_section(in)
+lang_input_section_type *in;
+{
+  asection *i = in->section;
+
+  if(i->size != 0) {
+    print_section("");
+    printf(" ");
+    print_section(i->name);
+    printf(" ");
+    if (i->output_section) {
+      print_address(i->output_section->vma + i->output_offset);
+      printf(" ");
+      print_size(i->size);
+      printf(" ");
+      print_alignment(i->alignment_power);
+      printf(" ");
+      if (in->ifile) {
+       bfd *abfd = in->ifile->the_bfd;
+       printf(" %s ",abfd->xvec->name);
+       if(abfd->my_archive != (bfd *)NULL) {
+         printf("[%s]%s", abfd->my_archive->filename,
+                abfd->filename);
+       }
+       else {
+         printf("%s", abfd->filename);
+       }
+       print_nl();
+
+       /* Find all the symbols in this file defined in this section */
+       {
+         asymbol **p;
+         for (p = in->ifile->asymbols; *p; p++) {
+           asymbol *q = *p;
+       
+           if (bfd_get_section(q) == i && q->flags & BSF_GLOBAL) {
+             print_symbol(q);
+           }
+         }
+       }
+      }
+      else {
+       print_nl();
+      }
+
+
+      print_dot = outside_section_address(i) + i->size;
+    }
+    else {
+      printf("No output section allocated\n");
+    }
+  }
+}
+static void
+print_common_statement()
+{
+  ldsym_type *lgs;
+  print_section("");
+  print_space();
+  print_section(common_section.output_section->name);
+  print_space();
+  print_address(common_section.output_offset +
+               common_section.output_section->vma);
+  print_space();
+  print_size(common_section.size);
+  print_space();
+  printf("(common)");
+  print_nl();
+  /* Print out all the global symbols */
+
+
+  for (lgs = symbol_head; lgs != (ldsym_type *)NULL; lgs =
+       lgs->next) {
+    if (lgs->sdefs_chain) {
+      asymbol *def = *(lgs->sdefs_chain);
+      if (def->section == &common_section) {
+       print_symbol(def);
+      }
+    }
+
+  }
+  print_dot = common_section.output_offset +
+    common_section.output_section->vma + common_section.size;
+
+
+}
+static void
+print_fill_statement(fill)
+lang_fill_statement_type *fill;
+{
+  printf("FILL mask ");
+  print_fill( fill->fill);
+}
+
+static void
+print_data_statement(data)
+lang_data_statement_type *data;
+{
+/*  bfd_vma value; */
+  print_section("");
+  print_space();
+  print_section("");
+  print_space();
+  ASSERT(print_dot == data->output_vma);
+
+  print_address(data->output_vma);
+  print_space();
+  print_address(data->value);
+  print_space();
+  switch (data->type) {
+  case BYTE :
+    printf("BYTE ");
+    print_dot += BYTE_SIZE;
+    break;
+  case SHORT:
+    printf("SHORT ");
+    print_dot += SHORT_SIZE;
+    break;  
+  case LONG:
+    printf("LONG ");
+    print_dot += LONG_SIZE;
+    break;
+  }
+
+  exp_print_tree(stdout, data->exp);
+  
+  printf("\n");
+}
+
+
+static void
+print_padding_statement(s)
+lang_padding_statement_type *s;
+{
+  print_section("");
+  print_space();
+  print_section("*fill*");
+  print_space();
+  print_address(s->output_offset + s->output_section->vma);
+  print_space();
+  print_size(s->size);
+  print_space();
+  print_fill(s->fill);
+  print_nl();
+}
+
+static void print_wild_statement(w,os)
+lang_wild_statement_type *w;
+lang_output_section_statement_type *os;
+{
+  if (w->filename != (char *)NULL) {
+    printf("%s",w->filename);
+  }
+  else {
+    printf("*");
+  }
+  if (w->section_name != (char *)NULL) {
+    printf("(%s)",w->section_name);
+  }
+  else {
+    printf("(*)");
+  }
+  print_nl();
+  print_statement(w->children.head, os);
+
+}
+static void
+print_statement(s, os)
+lang_statement_union_type *s;
+lang_output_section_statement_type *os;
+{
+  while (s) {
+    switch (s->header.type) {
+    case lang_wild_statement_enum:
+     print_wild_statement(&s->wild_statement, os);
+     break;
+    default:
+     printf("Fail with %d\n",s->header.type);
+      FAIL();
+      break;
+   case lang_address_statement_enum:
+     printf("address\n");
+     break;
+    case lang_common_statement_enum:
+      print_common_statement();
+      break;
+    case lang_object_symbols_statement_enum:
+      printf("object symbols\n");
+      break;
+    case lang_fill_statement_enum:
+      print_fill_statement(&s->fill_statement);
+      break;
+    case lang_data_statement_enum:
+      print_data_statement(&s->data_statement);
+      break;
+
+
+    case lang_input_section_enum:
+      print_input_section(&s->input_section);
+      break;
+    case lang_padding_statement_enum:
+      print_padding_statement(&s->padding_statement);
+      break;
+    case lang_output_section_statement_enum:
+      print_output_section_statement(&s->output_section_statement);
+      break;
+    case lang_assignment_statement_enum:
+      print_assignment(&s->assignment_statement,
+                    os);
+      break;
+
+
+    case lang_target_statement_enum:
+      printf("TARGET(%s)\n", s->target_statement.target);
+      break;
+    case lang_output_statement_enum:
+      printf("OUTPUT(%s)\n", s->output_statement.name);
+      break;
+    case lang_input_statement_enum:
+      print_input_statement(&s->input_statement);
+      break;
+    case lang_afile_asection_pair_statement_enum:
+      FAIL();
+      break;
+    }
+    s = s->next;
+  }
+}
+
+
+static void
+print_statements()
+{
+  print_statement(statement_list.head,
+                 (lang_output_section_statement_type *)NULL);
+}
+
+static bfd_vma
+insert_pad(this_ptr, fill, power, output_section_statement, dot)
+lang_statement_union_type **this_ptr;
+fill_type fill;
+unsigned int power;
+asection * output_section_statement;
+bfd_vma dot;
+{
+  /* Align this section first to the 
+     input sections requirement, then
+     to the output section's requirement.
+     If this alignment is > than any seen before, 
+     then record it too. Perform the alignment by
+     inserting a magic 'padding' statement.
+     */
+
+  unsigned int alignment_needed =  align_power(dot, power) - dot;
+
+  if (alignment_needed != 0) 
+    {
+      lang_statement_union_type *new = 
+       (lang_statement_union_type *)
+         ldmalloc(sizeof(lang_padding_statement_type));
+      /* Link into existing chain */
+      new->header.next = *this_ptr;
+      *this_ptr = new;
+      new->header.type = lang_padding_statement_enum;
+      new->padding_statement.output_section = output_section_statement;
+      new->padding_statement.output_offset =
+       dot - output_section_statement->vma;
+      new->padding_statement.fill = fill;
+      new->padding_statement.size = alignment_needed;
+    }
+
+
+  /* Remember the most restrictive alignment */
+  if (power > output_section_statement->alignment_power) {
+    output_section_statement->alignment_power = power;
+  }
+  output_section_statement->size += alignment_needed;
+  return alignment_needed + dot;
+
+}
+
+/*
+ size_common runs run though each global symboxl, and works
+ out how big the common section will be.
+ */
+
+static bfd_vma 
+size_common(output_section_statement, this_ptr, dot)
+lang_output_section_statement_type *output_section_statement;
+lang_statement_union_type **this_ptr;
+bfd_vma dot;
+{
+  extern ldsym_type *symbol_head;
+  ldsym_type *sp;
+  /* Make sure that each symbol is only defined once.
+     Allocate common symbols
+     Make the ref chain point to the defining asymbol.
+     */
+  /* Now, for each symbol, verify that it is defined globally at most once.
+     Put the global value into the symbol entry.
+     Common symbols are allocated here, in the BSS section.
+     Each defined symbol is given a '->defined' field
+     which is the correct N_ code for its definition,
+     except in the case of common symbols with -r.
+     Then make all the references point at the symbol entry
+     instead of being chained together. */
+  
+
+  common_section.name = output_section_statement->bfd_section->name;
+  common_section.output_section = output_section_statement->bfd_section;
+  common_section.output_offset =
+    dot - output_section_statement->bfd_section->vma;
+  if (config.relocateable_output == false ||
+      command_line.force_common_definition== true) {
+    dot = insert_pad(this_ptr,
+                    0x0, 4, output_section_statement->bfd_section, dot);
+
+    for (sp = symbol_head; sp != (ldsym_type *)NULL; sp = sp->next)  
+      {
+       /* Attatch this symbol to the correct output section*/
+
+       /* Allocate as common if wanted */
+
+       if (sp->scoms_chain )
+
+         {
+           unsigned long com = (*(sp->scoms_chain))->value;
+           /* Work out what alignment this common item s
+              hould be put on. Anything < int is int aligned,
+              anything bigger is  self aligned,
+              up to the restriction of the machine */
+
+           unsigned int align = sizeof(int);
+
+           /* Round up size of object to nearest int */
+           com = ALIGN(com, sizeof(int));
+           /* See what alignment is necessary -*/
+           if (com) {          
+             while ((com & align)==0) align <<=1;
+             /* FIXME */
+             if (align > 8)  {
+               align = 8;
+             }
+           }
+           dot =  ALIGN(dot, align);
+               
+
+           /* Transmogrify this from a common symbol
+              into a definition of a symbol in common
+              */
+           sp->sdefs_chain = sp->scoms_chain;
+
+           {
+             asymbol *com_ptr = *(sp->sdefs_chain);
+
+             sp->scoms_chain = (asymbol **)NULL;
+             commons_pending--;
+             /* Assign address, but keep section relative */
+
+             /* Force the symbol to belong in the bss section */
+             com_ptr->flags = BSF_EXPORT | BSF_GLOBAL ;
+             com_ptr->section = &common_section;
+             common_section.size += com;
+             if (write_map) 
+               {
+                 printf ("Allocating common %s: %lx at %lx\n",
+                         sp->name, 
+                         com,
+                         com_ptr->value);
+               }
+             com_ptr->value = common_section.size;
+           }
+         }
+      }
+  }
+  if (dot >
+      (common_section.output_section->vma +
+       common_section.output_section->size)) {
+    common_section.output_section->size =
+      dot - common_section.output_section->vma;
+  }
+  return dot + common_section.size;
+}
+
+static bfd_vma 
+size_input_section( this_ptr, output_section_statement, fill,  dot)
+lang_statement_union_type **this_ptr;
+lang_output_section_statement_type*output_section_statement;
+unsigned short fill;
+bfd_vma dot;
+{
+  lang_input_section_type *is = &((*this_ptr)->input_section);
+  asection *i = is->section;
+           
+  dot =  insert_pad(this_ptr, fill, i->alignment_power,
+                   output_section_statement->bfd_section, dot);
+
+  /* remember the largest size so we can malloc the largest area */
+  /* needed for the output stage */
+  if (i->size > largest_section) {
+    largest_section = i->size;
+  }
+
+  /* Remember where in the output section this input section goes */
+  i->output_offset = dot - output_section_statement->bfd_section->vma;
+
+  /* Mark how big the output section must be to contain this now */
+  dot += i->size;
+  output_section_statement->bfd_section->size =
+    dot - output_section_statement->bfd_section->vma;
+
+
+  return dot ;
+}
+
+
+/* Work out the size of the output sections 
+ from the sizes of the input sections */
+static bfd_vma
+lang_size_sections(s, output_section_statement, prev, fill, dot)
+lang_statement_union_type *s;
+lang_output_section_statement_type * output_section_statement;
+lang_statement_union_type **prev;
+unsigned short fill;
+bfd_vma dot;
+{
+  /* Size up the sections from their constituent parts */
+  for (; s != (lang_statement_union_type *)NULL ; s = s->next) 
+    {
+      switch (s->header.type) {
+      case lang_output_section_statement_enum:
+       {
+         bfd_vma after;
+         lang_output_section_statement_type *os =
+           &(s->output_section_statement);
+         /* The start of a section */
+         
+         if (os->addr_tree == (etree_type *)NULL) {
+           /* No address specified for this section, get one
+              from the region specification
+              */
+             if (os->region == (lang_memory_region_type *)NULL) {
+                 os->region = lang_memory_region_lookup("*default*");
+             }
+             dot = os->region->current;
+         }
+         else {
+           etree_value_type r ;
+           r = exp_fold_tree(os->addr_tree,
+                             (lang_output_section_statement_type *)NULL,
+                             lang_allocating_phase_enum,
+                             dot, &dot);
+           if (r.valid == false) {
+             info("%F%S: non constant address expression for section %s\n",
+                  os->name);
+           }
+           dot = r.value;
+         }
+         /* The section starts here */
+         /* First, align to what the section needs */
+
+         dot = align_power(dot, os->bfd_section->alignment_power);
+         os->bfd_section->vma = dot;
+         os->bfd_section->output_offset = 0;
+
+         (void)  lang_size_sections(os->children.head, os, &os->children.head,
+                                    os->fill, dot);
+         /* Ignore the size of the input sections, use the vma and size to */
+         /* align against */
+
+
+         after = ALIGN(os->bfd_section->vma +
+                       os->bfd_section->size,
+                       os->block_value) ;
+
+
+         os->bfd_section->size = after - os->bfd_section->vma;
+         dot = os->bfd_section->vma + os->bfd_section->size;
+         os->processed = true;
+
+         /* Replace into region ? */
+         if (os->addr_tree == (etree_type *)NULL 
+             && os->region !=(lang_memory_region_type*)NULL ) {
+           os->region->current = dot;
+         }
+       }
+
+       break;
+
+      case lang_data_statement_enum: 
+       {
+       unsigned int size;
+       s->data_statement.output_vma = dot;
+       s->data_statement.output_section =
+         output_section_statement->bfd_section;
+
+       switch (s->data_statement.type) {
+       case LONG:
+         size = LONG_SIZE;
+         break;
+       case SHORT:
+         size = SHORT_SIZE;
+         break;
+       case BYTE:
+         size = BYTE_SIZE;
+         break;
+
+       }
+       dot += size;
+       output_section_statement->bfd_section->size += size;
+      }
+       break;
+
+      case lang_wild_statement_enum:
+
+       dot =   lang_size_sections(s->wild_statement.children.head,
+                                  output_section_statement,
+                                  &s->wild_statement.children.head,
+
+                                  fill, dot);
+
+       break;
+
+      case lang_object_symbols_statement_enum:
+       create_object_symbols = output_section_statement;
+       break;
+      case lang_output_statement_enum:
+
+      case lang_target_statement_enum:
+       break;
+      case lang_common_statement_enum:
+       dot =   size_common(output_section_statement, prev, dot);
+
+       break;
+
+      case lang_input_section_enum:
+       dot =   size_input_section(prev,
+                                  output_section_statement,
+                                  output_section_statement->fill, dot);
+       break;
+      case lang_input_statement_enum:
+       break;
+      case lang_fill_statement_enum:
+       fill = s->fill_statement.fill;
+       break;
+      case lang_assignment_statement_enum:
+       {
+         bfd_vma newdot = dot;
+         exp_fold_tree(s->assignment_statement.exp,
+                       output_section_statement,
+                       lang_allocating_phase_enum,
+                       dot,
+                       &newdot);
+
+         if (newdot != dot) 
+           /* We've been moved ! so insert a pad */
+           {
+             lang_statement_union_type *new = 
+               (lang_statement_union_type *)
+                 ldmalloc(sizeof(lang_padding_statement_type));
+             /* Link into existing chain */
+             new->header.next = *prev;
+             *prev = new;
+             new->header.type = lang_padding_statement_enum;
+             new->padding_statement.output_section =
+               output_section_statement->bfd_section;
+             new->padding_statement.output_offset =
+               dot - output_section_statement->bfd_section->vma;
+             new->padding_statement.fill = fill;
+             new->padding_statement.size = newdot - dot;
+             output_section_statement->bfd_section->size +=
+               new->padding_statement.size;
+             dot =   newdot;
+           }
+       }
+
+       break;
+      case lang_padding_statement_enum:
+       FAIL();
+       break;
+      default:
+       FAIL();
+       break;
+      case lang_address_statement_enum:
+       break;
+      }
+      prev = &s->header.next;      
+    }
+  return dot;
+}
+
+
+static bfd_vma
+lang_do_assignments(s, output_section_statement, fill, dot)
+lang_statement_union_type *s;
+lang_output_section_statement_type * output_section_statement;
+unsigned short fill;
+bfd_vma dot;
+{
+
+  for (; s != (lang_statement_union_type *)NULL ; s = s->next) 
+    {
+      switch (s->header.type) {
+      case lang_output_section_statement_enum:
+       {
+         lang_output_section_statement_type *os =
+           &(s->output_section_statement);
+         dot = os->bfd_section->vma;
+         (void) lang_do_assignments(os->children.head, os, os->fill, dot);
+         dot = os->bfd_section->vma + os->bfd_section->size;
+       }
+       break;
+      case lang_wild_statement_enum:
+
+       dot = lang_do_assignments(s->wild_statement.children.head,
+                                   output_section_statement,
+                                   fill, dot);
+
+       break;
+
+      case lang_object_symbols_statement_enum:
+      case lang_output_statement_enum:
+      case lang_target_statement_enum:
+      case lang_common_statement_enum:
+       break;
+      case lang_data_statement_enum:
+       {
+         etree_value_type value ;
+         value =   exp_fold_tree(s->data_statement.exp,
+                                 0, lang_final_phase_enum, dot, &dot);
+         s->data_statement.value = value.value;
+         if (value.valid == false) info("%F%P: Invalid data statement\n");
+       }
+       switch (s->data_statement.type) {
+       case LONG:
+         dot += LONG_SIZE;
+         break;
+       case SHORT:
+         dot += SHORT_SIZE;
+         break;
+       case BYTE:
+         dot += BYTE_SIZE;
+         break;
+       }
+       break;
+      case lang_input_section_enum:
+       {
+         asection *in =    s->input_section.section;
+         dot += in->size;
+       }
+       break;
+
+      case lang_input_statement_enum:
+       break;
+      case lang_fill_statement_enum:
+       fill = s->fill_statement.fill;
+       break;
+      case lang_assignment_statement_enum:
+       {
+         exp_fold_tree(s->assignment_statement.exp,
+                       output_section_statement,
+                       lang_final_phase_enum,
+                       dot,
+                       &dot);
+       }
+
+       break;
+      case lang_padding_statement_enum:
+       dot += s->padding_statement.size;
+       break;
+      default:
+       FAIL();
+       break;
+      case lang_address_statement_enum:
+       break;
+      }
+
+    }
+  return dot;
+}
+
+
+
+static void lang_relocate_globals() 
+{ 
+
+  /*
+     Each ldsym_type maintains a chain of pointers to asymbols which
+     references the definition.  Replace each pointer to the referenence
+     with a pointer to only one place, preferably the definition. If
+     the defintion isn't available then the common symbol, and if
+     there isn't one of them then choose one reference.
+     */
+
+  FOR_EACH_LDSYM(lgs) {
+    asymbol *it;
+    if (lgs->sdefs_chain) {
+      it = *(lgs->sdefs_chain);
+    }
+    else if (lgs->scoms_chain != (asymbol **)NULL) {
+      it = *(lgs->scoms_chain);
+    }
+    else if (lgs->srefs_chain != (asymbol **)NULL) {
+      it = *(lgs->srefs_chain);
+    }
+    else {
+      FAIL();
+    }
+    if (it != (asymbol *)NULL)
+      {
+       asymbol **ptr= lgs->srefs_chain;
+
+       while (ptr != (asymbol **)NULL) {
+         asymbol *ref = *ptr;
+         *ptr = it;
+         ptr = (asymbol **)(ref->udata);
+       }
+      }
+  }
+}
+
+
+
+/* now that all the jiggery pokery is finished, copy important data from
+ * out internal form to the bfd way. Also create a section
+ * for each dummy file
+ */
+
+static void
+lang_create_output_section_statements()
+{
+  lang_statement_union_type*os;
+  for (os = lang_output_section_statement.head;
+       os != (lang_statement_union_type*)NULL;
+       os = os->output_section_statement.next) {
+    lang_output_section_statement_type *s =
+      &os->output_section_statement;
+    init_os(s);
+  }
+  script_file->the_bfd->sections = output_bfd->sections;
+}
+
+static void
+lang_finish()
+{
+  ldsym_type *lgs;
+
+  if (entry_symbol == (char *)NULL) {
+    /* No entry has been specified, look for start */
+    entry_symbol = "start";
+  }
+  lgs = ldsym_get_soft(entry_symbol);
+  if (lgs && lgs->sdefs_chain) {
+    asymbol *sy = *(lgs->sdefs_chain);
+    /* We can set the entry address*/
+    bfd_set_start_address(output_bfd,
+                         outside_symbol_address(sy));
+
+  }
+  else {
+    /* Can't find anything reasonable, 
+       use the first address in the text section 
+       */
+    asection *ts = bfd_get_section_by_name(output_bfd, ".text");
+    if (ts) {
+      bfd_set_start_address(output_bfd, ts->vma);
+    }
+  }
+}
+
+/* By now we know the target architecture, and we may have an */
+/* ldfile_output_machine_name */
+static void
+lang_check()
+{
+  lang_statement_union_type *file;
+
+  
+  for (file = file_chain.head;
+       file != (lang_statement_union_type *)NULL;
+       file=file->input_statement.next) 
+    {
+      /* Inspect the architecture and ensure we're linking like
+        with like
+        */
+
+      if (bfd_arch_compatible( file->input_statement.the_bfd,
+                             output_bfd,
+                             &ldfile_output_architecture,
+                             &ldfile_output_machine)) {
+       bfd_set_arch_mach(output_bfd,
+                         ldfile_output_architecture, ldfile_output_machine);
+      }
+      else {
+       enum bfd_architecture this_architecture =
+         bfd_get_architecture(file->input_statement.the_bfd);
+       unsigned long this_machine =
+         bfd_get_machine(file->input_statement.the_bfd);
+       
+       info("%I: architecture %s",
+            file,
+            bfd_printable_arch_mach(this_architecture, this_machine));
+       info(" incompatible with output %s\n",
+            bfd_printable_arch_mach(ldfile_output_architecture,
+                                    ldfile_output_machine));
+       ldfile_output_architecture = this_architecture;
+       ldfile_output_machine = this_machine;
+       bfd_set_arch_mach(output_bfd,
+                         ldfile_output_architecture,
+                         ldfile_output_machine);
+
+
+      }
+    }
+}
+
+
+/*
+ * run through all the global common symbols and tie them 
+ * to the output section requested.
+ */
+
+static void
+lang_common()
+{
+  ldsym_type *lgs;
+  if (config.relocateable_output == false ||
+      command_line.force_common_definition== true) {
+    for (lgs = symbol_head;
+        lgs != (ldsym_type *)NULL;
+        lgs=lgs->next)
+      {
+       asymbol *com ;
+       size_t size;
+       size_t align;
+       if (lgs->scoms_chain != (asymbol **)NULL) {
+
+         com = *(lgs->scoms_chain);
+         size = com->value;
+         align = sizeof(int);
+         /* Round up size of object to nearest int */
+         size = ALIGN(size, sizeof(int));
+         /* Force alignment */
+         if (size) {
+           while ((size & align)==0) align<<=1;
+           if (align > 8) {
+             align = 8;
+           }
+         }
+         /* Change from a common symbol into a definition of
+            a symbol */
+         lgs->sdefs_chain = lgs->scoms_chain;
+         lgs->scoms_chain = (asymbol **)NULL;
+         commons_pending--;
+         /* Point to the correct common section */
+         com->section =
+           ((lang_input_statement_type *)
+            (com->the_bfd->usrdata))->common_section;
+         /*  Fix the size of the common section */
+
+
+         com->flags = BSF_EXPORT | BSF_GLOBAL;
+
+         if (write_map) 
+           {
+             printf ("Allocating common %s: %x at %x\n",
+                     lgs->name, 
+                     (unsigned) size,
+                     (unsigned)  com->section->size);
+           }
+         com->value = com->section->size;
+         com->section->size += size;
+       }
+      }
+  }
+}
+
+/*
+run through the input files and ensure that every input 
+section has somewhere to go. If one is found without
+a destination then create an input request and place it
+into the statement tree.
+*/
+
+static void lang_place_orphans()
+{
+  lang_input_statement_type *file;
+  for (file = (lang_input_statement_type*)file_chain.head;
+       file != (lang_input_statement_type*)NULL;
+       file = (lang_input_statement_type*)file->next) {
+    asection *s;  
+    for (s = file->the_bfd->sections;
+        s != (asection *)NULL;
+        s = s->next) {
+      if ( s->output_section == (asection *)NULL) {
+       /* This section of the file is not attatched, root
+          around for a sensible place for it to go */
+
+       if (file->common_section == s) {
+         /* This is a lonely common section which must
+            have come from an archive. We attatch to the
+            section with the wildcard  */
+         wild_doit(&default_common_section->children, s, 
+                   default_common_section, file);        
+       }
+       else {
+         lang_output_section_statement_type *os = 
+           lang_output_section_statement_lookup(s->name);
+
+         wild_doit(&os->children, s, os, file);
+       }
+      }
+    }
+
+  }
+}
+
+
+/*
+ * phase_2
+ *
+ * peformed after every file has been opened and symbols read
+ */
+static void
+lang_phase_2()
+{
+  lang_init2();
+  lang_create_output_section_statements();
+  lang_open_input(statement_list.head, (char *)NULL, 
+                 ( lang_output_section_statement_type *)NULL);
+  lang_place_orphans();
+  lang_common();
+
+  ldemul_before_allocation();
+
+  lang_size_sections(statement_list.head,
+                    (lang_output_section_statement_type *)NULL,
+                    &(statement_list.head), 0, (bfd_vma)0);
+  ldemul_after_allocation();
+  /* Do it once again now that we know the sizes of everything */
+
+  lang_do_assignments(statement_list.head,
+                     (lang_output_section_statement_type *)NULL,
+                     0, (bfd_vma)0);
+
+
+
+  lang_check();
+
+  lang_relocate_globals();
+
+
+  lang_finish();
+}
+
+
+
+
+void
+lang_set_flags(ptr, flags)
+lang_section_flags_type *ptr;
+char *flags;
+{
+  boolean state = true;
+  ptr->flag_read = false;
+  ptr->flag_write = false;
+  ptr->flag_executable = false;
+  ptr->flag_loadable= false;
+  while (*flags)
+    {
+      if (*flags == '!') {
+       state = false;
+       flags++;
+      }
+      else state = true;
+      switch (*flags) {
+      case 'R':
+       ptr->flag_read = state; 
+       break;
+      case 'W':
+       ptr->flag_write = state; 
+       break;
+      case 'X':
+       ptr->flag_executable= state;
+       break;
+      case 'L':
+       ptr->flag_loadable= state;
+       break;
+      default:
+       info("%P%F illegal syntax in flags\n");
+       break;
+      }
+      flags++;
+    }
+}
+
+
+
+void
+lang_for_each_file(func)
+void (*func)();
+{
+  lang_input_statement_type *f;
+  for (f = (lang_input_statement_type *)file_chain.head; 
+       f != (lang_input_statement_type *)NULL;
+       f = (lang_input_statement_type *)f->next)  
+    {
+      func(f);
+    }
+}
+
+
+void
+lang_for_each_input_section(func)
+void (*func)();
+{
+  lang_input_statement_type *f;
+  for (f = (lang_input_statement_type *)file_chain.head; 
+       f != (lang_input_statement_type *)NULL;
+       f = (lang_input_statement_type *)f->next)  
+    {
+      asection *s;
+      for (s = f->the_bfd->sections;
+          s != (asection *)NULL;
+          s = s->next) {
+       func(f->the_bfd, s);
+      }
+    }
+}
+
+
+
+void 
+ldlang_add_file(entry)
+lang_input_statement_type *entry;
+{
+  lang_has_input_file = true;
+  lang_statement_append(&file_chain,
+                       (lang_statement_union_type *)entry,
+                       &entry->next);
+}
+
+
+
+void
+lang_add_output(name)
+char *name;
+{
+  lang_output_statement_type *new = new_stat(lang_output_statement,
+                                            stat_ptr);
+  new->name = name;
+  had_output_filename = true;
+}
+
+
+static lang_output_section_statement_type *current_section;
+
+void
+lang_enter_output_section_statement(output_section_statement_name,
+address_exp,
+block_value)
+char *output_section_statement_name;
+etree_type *address_exp;
+bfd_vma block_value;
+{
+  lang_output_section_statement_type *os;
+  current_section = 
+    os =
+      lang_output_section_statement_lookup(output_section_statement_name);
+
+
+  /* Add this statement to tree */
+  /*  add_statement(lang_output_section_statement_enum,
+      output_section_statement);*/
+  /* Make next things chain into subchain of this */
+
+  if (os->addr_tree ==
+      (etree_type *)NULL) {
+    os->addr_tree =
+      address_exp;
+  }
+  os->block_value = block_value;
+  stat_ptr = & os->children;
+
+}
+
+
+void 
+lang_final()
+{
+  if (had_output_filename == false) {
+    lang_add_output("a.out");
+  }
+
+
+}
+
+
+
+
+
+asymbol *create_symbol(name, flags, section)
+char *name;
+flagword flags;
+asection *section;
+{
+  extern lang_input_statement_type *script_file;
+  asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **));
+  /* Add this definition to script file */
+  asymbol *def =  (asymbol  *)bfd_make_empty_symbol(script_file->the_bfd);
+  def->name = name;
+  def->udata = 0;
+  def->flags = flags;
+  def->section = section;
+
+  *def_ptr = def;
+  Q_enter_global_ref(def_ptr);
+  return def;
+}
+
+
+void
+lang_process()
+{
+  lang();
+  lang_phase_2();
+}
+
+
+/* EXPORTED TO YACC */
+void
+lang_section_start(name, address)
+char *name;
+etree_type *address;
+{
+  lang_address_statement_type *ad =new_stat(lang_address_statement, stat_ptr);
+  ad->section_name = name;
+  ad->address = address;
+}
+void lang_add_entry(name)
+char *name;
+{
+  entry_symbol = name;
+}
+
+void
+lang_add_target(name)
+char *name;
+{
+  lang_target_statement_type *new = new_stat(lang_target_statement,
+                                           stat_ptr);
+  new->target = name;
+
+}
+void
+lang_add_wild(section_name, filename)
+char *section_name;
+char *filename;
+{
+  lang_wild_statement_type *new = new_stat(lang_wild_statement,
+                                          stat_ptr);
+
+  if (section_name != (char *)NULL && strcmp(section_name,"COMMON") == 0)
+    {
+      placed_commons = true;
+    }
+  new->section_name = section_name;
+  new->filename = filename;
+  lang_list_init(&new->children);
+}
+
+void
+lang_add_map(name)
+char *name;
+{
+  while (*name) {
+    switch (*name) {
+    case 'F':
+      map_option_f = true;
+      break;
+    }
+    name++;
+  }
+}
+
+void lang_add_fill(exp)
+int exp;
+{
+  lang_fill_statement_type *new =   new_stat(lang_fill_statement, 
+                                             stat_ptr);
+  new->fill = exp;
+}
+
+void lang_add_data(type, exp)
+int type;
+union etree_union *exp;
+{
+
+ lang_data_statement_type *new = new_stat(lang_data_statement,
+                                           stat_ptr);
+ new->exp = exp;
+ new->type = type;
+
+}
+void
+lang_add_assignment(exp)
+etree_type *exp;
+{
+  lang_assignment_statement_type *new = new_stat(lang_assignment_statement,
+                                           stat_ptr);
+  new->exp = exp;
+}
+
+void
+lang_add_attribute(attribute)
+enum statement_enum attribute;
+{
+  new_statement(attribute, sizeof(lang_statement_union_type),stat_ptr);
+}
+
+
+
+void 
+lang_startup(name)
+char *name;
+{
+  if (startup_file != (char *)NULL) {
+   info("%P%FMultiple STARTUP files\n");
+  }
+  first_file->filename = name;
+  first_file->local_sym_name = name;
+
+  startup_file= name;
+}
+void 
+lang_float(maybe)
+boolean maybe;
+{
+  lang_float_flag = maybe;
+}
+
+void 
+lang_leave_output_section_statement(fill, memspec)
+bfd_vma fill;
+char *memspec;
+{
+  current_section->fill = fill;
+  current_section->region = lang_memory_region_lookup(memspec);
+  stat_ptr = &statement_list;
+}
+
+void
+lang_abs_symbol_at_end_of(section, name)
+char *section;
+char *name;
+{
+  extern bfd *output_bfd;
+  extern asymbol *create_symbol();
+  asection *s = bfd_get_section_by_name(output_bfd, section);
+  /* Add a symbol called _end */
+  asymbol *def = create_symbol(name,
+                              BSF_GLOBAL | BSF_EXPORT |
+                              BSF_ABSOLUTE,
+                              (asection *)NULL);
+  if (s != (asection *)NULL) {
+    def->value = s->vma + s->size;
+  }
+  else {
+    def->value = 0;
+  }
+}
+
+void 
+lang_statement_append(list, element, field)
+lang_statement_list_type *list;
+lang_statement_union_type *element;
+lang_statement_union_type **field;
+{
+  *(list->tail) = element;
+  list->tail = field;
+}
+
+
+static void 
+lang_for_each_statement_worker(func,  s)
+void (*func)();
+lang_statement_union_type *s;
+{
+  for (; s != (lang_statement_union_type *)NULL ; s = s->next) 
+    {
+      func(s);
+
+      switch (s->header.type) {
+      case lang_output_section_statement_enum:
+       lang_for_each_statement_worker
+         (func, 
+          s->output_section_statement.children.head);
+       break;
+      case lang_wild_statement_enum:
+       lang_for_each_statement_worker
+         (func, 
+          s->wild_statement.children.head);
+       break;
+      case lang_data_statement_enum:
+      case lang_object_symbols_statement_enum:
+      case lang_output_statement_enum:
+      case lang_target_statement_enum:
+      case lang_common_statement_enum:
+      case lang_input_section_enum:
+      case lang_input_statement_enum:
+      case lang_fill_statement_enum:
+      case lang_assignment_statement_enum:
+      case lang_padding_statement_enum:
+      case lang_address_statement_enum:
+       break;
+      default:
+       FAIL();
+       break;
+      }
+    }
+}
+
+void lang_for_each_statement(func)
+void (*func)();
+{
+  lang_for_each_statement_worker(func,
+                                statement_list.head);
+
+}
diff --git a/ld/ldlang.h b/ld/ldlang.h
new file mode 100644 (file)
index 0000000..ab102a5
--- /dev/null
@@ -0,0 +1,347 @@
+/* ldlang.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 enum {
+  lang_input_file_is_l_enum,
+  lang_input_file_is_symbols_only_enum,
+  lang_input_file_is_marker_enum,
+  lang_input_file_is_fake_enum,
+lang_input_file_is_search_file_enum,
+  lang_input_file_is_file_enum } lang_input_file_enum_type;
+
+typedef unsigned short fill_type;
+typedef struct statement_list {
+  union lang_statement_union *head;
+  union lang_statement_union **tail;
+} lang_statement_list_type;
+
+
+typedef struct {
+  boolean flag_read;
+  boolean flag_write;
+  boolean flag_executable;
+  boolean flag_loadable;
+} lang_section_flags_type;
+
+typedef struct memory_region_struct {
+  char *name;
+  struct memory_region_struct *next;
+  bfd_vma origin;
+  bfd_offset length;
+  bfd_vma current;
+  lang_section_flags_type flags;
+} lang_memory_region_type ;
+
+typedef struct lang_statement_header_struct 
+{
+union  lang_statement_union  *next;
+  enum statement_enum {
+    lang_output_section_statement_enum,
+    lang_assignment_statement_enum,
+    lang_input_statement_enum,
+    lang_address_statement_enum,
+    lang_wild_statement_enum,
+    lang_input_section_enum,
+    lang_common_statement_enum,
+    lang_object_symbols_statement_enum,
+    lang_fill_statement_enum,
+    lang_data_statement_enum,
+    lang_target_statement_enum,
+    lang_output_statement_enum,
+    lang_padding_statement_enum,
+
+    lang_afile_asection_pair_statement_enum
+  } type;
+
+} lang_statement_header_type;
+
+
+typedef struct 
+{
+  lang_statement_header_type header;
+  union etree_union *exp;
+}  lang_assignment_statement_type;
+
+
+typedef struct lang_target_statement_struct {
+  lang_statement_header_type header;
+  char *target;
+} lang_target_statement_type;
+
+
+typedef struct lang_output_statement_struct {
+  lang_statement_header_type header;
+  char *name;
+} lang_output_statement_type;
+
+
+typedef struct lang_output_section_statement_struct 
+{
+  lang_statement_header_type header;
+  union etree_union *addr_tree;
+  lang_statement_list_type children;
+  char *memspec;
+  union lang_statement_union *next;
+  char *name;
+  unsigned long subsection_alignment;
+  boolean processed;
+
+  asection *bfd_section;
+  lang_section_flags_type flags;
+  struct memory_region_struct *region;
+  size_t block_value;
+  fill_type fill;
+} lang_output_section_statement_type;
+
+
+typedef struct {
+  lang_statement_header_type header;
+} lang_common_statement_type;
+
+typedef struct {
+  lang_statement_header_type header;
+} lang_object_symbols_statement_type;
+
+typedef struct {
+  lang_statement_header_type header;
+fill_type fill;
+} lang_fill_statement_type;
+
+typedef struct {
+  lang_statement_header_type header;
+  unsigned int type;
+  union  etree_union *exp;
+  bfd_vma value;
+  asection *output_section;
+  bfd_vma output_vma;
+} lang_data_statement_type;
+
+
+
+
+typedef struct lang_input_statement_struct
+  {
+    lang_statement_header_type header;
+    /* Name of this file.  */
+    char *filename;
+    /* Name to use for the symbol giving address of text start */
+    /* Usually the same as filename, but for a file spec'd with -l
+       this is the -l switch itself rather than the filename.  */
+    char *local_sym_name;
+
+    /* Describe the layout of the contents of the file */
+
+    /* The file's a.out header.  */
+    /*  struct exec header;*/
+    /* Offset in file of GDB symbol segment, or 0 if there is none.  */
+    int symseg_offset;
+
+    /* Describe data from the file loaded into core */
+
+    bfd *the_bfd;
+
+    boolean closed;
+    file_ptr passive_position;
+
+    /* Symbol table of the file.  */
+    asymbol **asymbols;
+    unsigned int symbol_count;
+
+    /* Next two used only if `relocatable_output' or if needed for */
+    /* output of undefined reference line numbers. */
+    /* Text reloc info saved by `write_text' for `coptxtrel'.  */
+
+
+    /* Offset in bytes in the output file symbol table
+       of the first local symbol for this file.  Set by `write_file_symbols'.  */
+    int local_syms_offset;
+
+    /* For library members only */
+
+    /* For a library, points to chain of entries for the library members.  */
+    struct lang_input_statement_struct *subfiles;
+    /* For a library member, offset of the member within the archive.
+       Zero for files that are not library members.  */
+    /*  int starting_offset;*/
+    /* Size of contents of this file, if library member.  */
+    int total_size;
+    /* For library member, points to the library's own entry.  */
+    struct lang_input_statement_struct *superfile;
+    /* For library member, points to next entry for next member.  */
+    struct lang_input_statement_struct *chain;
+    /* Point to the next file - whatever it is, wanders up and down archives */
+    union lang_statement_union  *next;
+    /* Point to the next file, but skips archive contents */
+    union  lang_statement_union  *next_real_file;
+
+    boolean is_archive;
+
+    /* 1 if file's header has been read into this structure.  */
+    boolean header_read_flag;
+
+    /* 1 means search a set of directories for this file.  */
+    boolean search_dirs_flag;
+
+    /* 1 means this is base file of incremental load.
+       Do not load this file's text or data.
+       Also default text_start to after this file's bss. */
+    boolean just_syms_flag;
+
+    boolean loaded;
+
+
+    /*    unsigned int globals_in_this_file;*/
+    char *target;
+    boolean real;
+
+    asection *common_section;
+    asection *common_output_section;
+  } lang_input_statement_type;
+
+typedef struct {
+  lang_statement_header_type header;
+  asection *section;
+  lang_input_statement_type *ifile;
+} lang_input_section_type;
+
+
+typedef struct {
+  lang_statement_header_type header;
+  asection *section;
+  union lang_statement_union *file;
+} lang_afile_asection_pair_statement_type;
+
+typedef struct lang_wild_statement_struct {
+  lang_statement_header_type header;
+  char *section_name;
+  char *filename;
+  lang_statement_list_type children;
+} lang_wild_statement_type;
+
+typedef struct lang_address_statement_struct {
+  lang_statement_header_type header;
+  char *section_name;
+  union  etree_union *address;
+} lang_address_statement_type;
+
+typedef struct {
+  lang_statement_header_type header;
+  bfd_vma output_offset;
+  size_t size;
+  asection *output_section;
+  fill_type fill;
+} lang_padding_statement_type;
+
+typedef union lang_statement_union 
+{
+  lang_statement_header_type header;
+  union lang_statement_union *next;
+  lang_wild_statement_type wild_statement;
+  lang_data_statement_type data_statement;
+  lang_address_statement_type address_statement;
+  lang_output_section_statement_type output_section_statement;
+  lang_afile_asection_pair_statement_type afile_asection_pair_statement;
+  lang_assignment_statement_type assignment_statement;
+  lang_input_statement_type input_statement;
+  lang_target_statement_type target_statement;
+  lang_output_statement_type output_statement;
+  lang_input_section_type input_section;
+  lang_common_statement_type common_statement;
+  lang_object_symbols_statement_type object_symbols_statement;
+  lang_fill_statement_type fill_statement;
+  lang_padding_statement_type padding_statement;
+} lang_statement_union_type;
+
+
+
+PROTO(void,lang_init,(void));
+PROTO(struct memory_region_struct ,*lang_memory_region_lookup,(char *));
+PROTO(struct lang_output_section_statement_struct *,lang_output_section_find,(char *));
+
+PROTO(void ,lang_map,(struct _iobuf *));
+PROTO(void,lang_set_flags,(lang_section_flags_type *, char *));
+PROTO(void,lang_add_output,(char *));
+
+PROTO(void,lang_final,(void));
+PROTO(struct symbol_cache_entry *,create_symbol,(char *, unsigned int, struct sec_struct *));
+PROTO(void ,lang_process,(void));
+PROTO(void ,lang_section_start,(char *, union etree_union *));
+PROTO(void,lang_add_entry,(char *));
+PROTO(void,lang_add_target,(char *));
+PROTO(void,lang_add_wild,(char *, char *));
+PROTO(void,lang_add_map,(char *));
+PROTO(void,lang_add_fill,(int));
+PROTO(void,lang_add_assignment,(union etree_union *));
+PROTO(void,lang_add_attribute,(enum statement_enum));
+PROTO(void,lang_startup,(char *));
+PROTO(void,lang_float,(enum boolean));
+PROTO(void,lang_leave_output_section_statement,(bfd_vma, char *));
+PROTO(void,lang_abs_symbol_at_end_of,(char *, char *));
+PROTO(void,lang_statement_append,(struct statement_list *, union lang_statement_union *, union lang_statement_union **));
+PROTO(void, lang_for_each_file,(void (*dothis)(lang_input_statement_type *)));
+
+#define LANG_FOR_EACH_ASYMBOL(asymbol) \
+     
+#define LANG_FOR_EACH_INPUT_STATEMENT(statement)               \
+  extern lang_statement_list_type file_chain;                  \
+  lang_input_statement_type *statement;                                \
+  for (statement = (lang_input_statement_type *)file_chain.head;\
+       statement != (lang_input_statement_type *)NULL;         \
+       statement = (lang_input_statement_type *)statement->next)\
+
+#define LANG_FOR_EACH_INPUT_SECTION(statement, abfd, section, x) \
+{ extern lang_statement_list_type file_chain;                  \
+  lang_input_statement_type *statement;                                \
+  for (statement = (lang_input_statement_type *)file_chain.head;\
+       statement != (lang_input_statement_type *)NULL;         \
+       statement = (lang_input_statement_type *)statement->next)\
+    {                                                          \
+      asection *section;                                       \
+      bfd *abfd = statement->the_bfd;                          \
+      for (section = abfd->sections;                           \
+          section != (asection *)NULL;                         \
+          section = section->next) {                           \
+       x;                                                      \
+      }                                                                \
+    }                                                          \
+ }             
+
+#define LANG_FOR_EACH_OUTPUT_SECTION(section, x)               \
+ { extern bfd *output_bfd;                                     \
+   asection *section;                                          \
+   for (section = output_bfd->sections;                                \
+       section != (asection *)NULL;                            \
+       section = section->next)                                \
+       { x; }                                                  \
+ }
+                                       
+
+PROTO(void, lang_process,(void));
+PROTO(void, ldlang_add_file,(lang_input_statement_type *));
+
+PROTO(lang_output_section_statement_type *,lang_output_section_find,());
+
+PROTO(lang_input_statement_type *,
+       lang_add_input_file,(char *name,
+                           lang_input_file_enum_type file_type,
+                           char *target));
+PROTO(lang_output_section_statement_type *,
+lang_output_section_statement_lookup,(char *name));
diff --git a/ld/ldlex.h b/ld/ldlex.h
new file mode 100644 (file)
index 0000000..fe4e017
--- /dev/null
@@ -0,0 +1,26 @@
+/* ldlex.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.  */
+
+PROTO(int, lex_input, (void));
+PROTO(void, lex_unput, (int));
+PROTO(int ,yywrap,(void));
+PROTO(void, parse_args,(int, char **));
+PROTO(void, parse_line,(char*));
+
diff --git a/ld/ldlex.l b/ld/ldlex.l
new file mode 100644 (file)
index 0000000..67af46b
--- /dev/null
@@ -0,0 +1,490 @@
+%{
+/* 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.  */
+
+/*
+ *  $Id$ 
+ *
+ * $Log$
+ * Revision 1.1  1991/03/21 21:28:50  gumby
+ * Initial revision
+ *
+ * Revision 1.3  1991/03/16  22:27:24  rich
+ * fish
+ *
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:27  chrisb
+ * Initial revision
+ *
+ * Revision 1.6  1991/03/10  09:31:32  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.5  1991/03/09  03:25:49  sac
+ * Can now parse the -Ur flag
+ *
+ * Revision 1.4  1991/03/06  02:26:04  sac
+ * Added support for constructor sections.
+ * Remove parsing ambiguity.
+ * Lint
+ *
+ * Revision 1.3  1991/02/22  17:15:14  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+
+
+/*SUPPRESS 529*/
+/*SUPPRESS 26*/
+/*SUPPRESS 29*/
+#define LEXDEBUG
+#include "sysdep.h"
+#include "bfd.h"
+
+#include <ctype.h>
+#include "ldlex.h"
+
+#include "ld.h"
+#include "ldexp.h"
+#include "ldgram.tab.h"
+#include "ldmisc.h"
+
+#undef input
+#undef unput
+#define input lex_input
+#define unput lex_unput
+int debug;
+extern boolean ldgram_want_filename;
+extern boolean ldgram_mustbe_filename;
+extern boolean ldgram_mustbe_symbolname;
+static char *command_line;
+
+extern int fgetc();
+extern int yyparse();
+
+typedef struct {
+       char *name;     
+int value;
+} keyword_type;
+#define RTOKEN(x)  {  yylval.token = x; return x; }
+keyword_type keywords[] = 
+{
+"MEMORY",MEMORY,
+"ORIGIN",ORIGIN,
+"BLOCK",BLOCK,
+"LENGTH",LENGTH,
+"ALIGN",ALIGN_K,
+"SUBSECTION_ALIGN",SUBSECTION_ALIGN,
+"ADDR",ADDR,
+"ENTRY",ENTRY,
+"NEXT",NEXT,
+"MAP",MAP,
+"SIZEOF",SIZEOF,
+"TARGET",TARGET_K,
+"SEARCH_DIR",SEARCH_DIR,
+"OUTPUT",OUTPUT,
+"INPUT",INPUT,
+"DEFINED",DEFINED,
+"CREATE_OBJECT_SYMBOLS",CREATE_OBJECT_SYMBOLS,
+"SECTIONS",SECTIONS,
+"FILL",FILL,
+"STARTUP",STARTUP,
+"HLL",HLL,
+"SYSLIB",SYSLIB,
+"FLOAT",FLOAT,
+"LONG", LONG,
+"SHORT", SHORT,
+"BYTE", BYTE,
+"NOFLOAT",NOFLOAT,
+"o",ORIGIN,
+"org",ORIGIN,
+"l", LENGTH,
+"len", LENGTH,
+0,0};
+unsigned int lineno;
+extern boolean hex_mode;
+FILE *ldlex_input_stack;
+static unsigned int have_pushback;
+#define NPUSHBACK 10
+int pushback[NPUSHBACK];
+int thischar;
+extern char *ldfile_input_filename;
+
+int
+lex_input()
+{
+  /*
+     When we know that the next token must be a filename we force the 
+     input routine to return a '#' character, which will cause the special
+     filname regexp to match the following chars even if they don't look
+     much like a filename to any sane person.
+     */
+  if (ldgram_mustbe_filename) {
+    ldgram_mustbe_filename = false;
+    return '#';
+  }
+
+  if (have_pushback > 0) 
+    {
+      have_pushback --;
+      return thischar = pushback[have_pushback];
+    }
+  if (ldlex_input_stack) {
+    thischar = fgetc(ldlex_input_stack);
+
+    if (thischar == EOF)  {
+      fclose(ldlex_input_stack);
+      ldlex_input_stack = (FILE *)NULL;
+      ldfile_input_filename = (char *)NULL;
+      thischar = lex_input();
+
+    }
+  }
+  else if (command_line && *command_line)  {
+    thischar = *(command_line++);
+  }
+  else thischar = 0;
+  if(thischar == '\t') thischar = ' ';
+  return thischar ;
+}
+
+void
+lex_unput(c)
+int c;
+{
+  if (have_pushback > NPUSHBACK) {
+    info("%F%P Too many pushbacks\n");
+  }
+
+  pushback[have_pushback] = c;
+  have_pushback ++;
+}
+
+
+       int
+yywrap()
+        { return 1; }
+/*VARARGS*/
+
+void
+allprint(x) 
+int x;
+{
+fprintf(yyout,"%d",x);
+}
+
+void
+sprint(x) 
+char *x;
+{
+fprintf(yyout,"%s",x);
+}
+
+int  thischar;
+
+void parse_line(arg)
+char *arg;
+{
+  command_line = arg;
+  have_pushback = 0;
+  yyparse();
+}
+
+
+
+void
+parse_args(ac, av)
+int ac;
+char **av;
+{
+  char *p;
+  int i;
+  size_t size = 0;
+  char *dst;
+  debug = 1;
+  for (i= 1; i < ac; i++) {
+    size += strlen(av[i]) + 2; 
+  }
+  dst = p = (char *)ldmalloc(size + 2);
+/* Put a space arount each option */
+
+
+  for (i =1; i < ac; i++) {
+
+    unsigned int s = strlen(av[i]);
+  *dst++ = ' ';
+    memcpy(dst, av[i], s);
+    dst[s] = ' ';
+    dst += s + 1;
+  }
+  *dst = 0;
+  parse_line(p);
+
+  free(p);
+
+
+}
+
+long number(text, base)
+char *text;
+int base;
+{
+unsigned  long l = 0;
+  char *p;
+  for (p = text; *p != 0; p++) {
+    if (*p == 'K') {
+      l =l * 1024;
+    }
+    else if(*p== 'M') {
+      l =l * 1024 * 1024;
+    }
+    else {
+      l =l * base;
+      if (isdigit(*p))  {
+       l += *p - '0';
+      }
+      else if (islower(*p)) {
+       l += *p - 'a' + 10;
+      }
+      else {
+       l += *p - 'A' + 10;
+      }
+    }
+  }
+  return l;
+}
+%}
+
+%a 4000
+%o 5000
+FILENAMECHAR   [a-zA-Z0-9\/\.\-\_\+]
+FILENAME       {FILENAMECHAR}+
+
+
+WHITE          [ \t]+
+
+%%
+"\n"           { lineno++; }
+
+
+"\ -defsym" { return OPTION_defsym; }
+"\ -noinhibit_exec" { return OPTION_noinhibit_exec; }
+"\ -format" { return OPTION_format; }
+"\ -n"         { return OPTION_n; }
+"\ -r"         { return OPTION_r; }
+"\ -Ur"                { return OPTION_Ur; }
+"\ -o"         { return OPTION_o; }
+"\ -g"         { return OPTION_g; }
+"\ -e"         { return OPTION_e; }
+"\ -b"         { return OPTION_b; }
+"\ -dc"                { return OPTION_dc; }
+"\ -dp"                { return OPTION_dp; }
+"\ -d"         { return OPTION_d; }
+"\ -v"         { return OPTION_v; }
+"\ -M"         { return OPTION_M; }
+"\ -t"         { return OPTION_t; }
+"\ -X"         { return OPTION_X; }
+"\ -x"         { return OPTION_x; }
+"\ -c"         { return OPTION_c; }
+"\ -s"            { return OPTION_s; }
+"\ -S"            { return OPTION_S; }
+"\ -l"{FILENAME} {
+               yylval.name = buystring(yytext+3);
+               return OPTION_l; 
+       }
+
+"\ -L"{FILENAME}       { 
+               yylval.name = buystring(yytext+3);
+               return OPTION_L; 
+        }
+"\ -Ttext"  {
+                yylval.name = ".text";
+                return OPTION_Texp;
+              }
+"\ -Tdata"  {
+                yylval.name = ".data";
+                return OPTION_Texp;
+              }
+"\ -Tbss"  {
+                yylval.name = ".bss";
+                return OPTION_Texp;
+              }
+
+"\ -T"{FILENAME}  {
+                yylval.name = buystring(yytext+3);
+                return OPTION_Tfile;
+              }
+"\ -T"          {
+                return OPTION_T;
+              }
+
+"\ -A"{FILENAME} {
+                 yylval.name = buystring(yytext+3);
+                return OPTION_Aarch;
+              }
+" " { }
+"<<="          { RTOKEN(LSHIFTEQ);}
+">>="          { RTOKEN(RSHIFTEQ);}
+"||"           { RTOKEN(OROR);}
+"=="           { RTOKEN(EQ);}
+"!="           { RTOKEN(NE);}
+">="           { RTOKEN(GE);}
+"<="           { RTOKEN(LE);}
+"<<"           { RTOKEN(LSHIFT);}
+">>"           { RTOKEN(RSHIFT);}
+"+="           { RTOKEN(PLUSEQ);}
+"-="           { RTOKEN(MINUSEQ);}
+"*="           { RTOKEN(MULTEQ);}
+"/="           { RTOKEN(DIVEQ);}
+"&="           { RTOKEN(ANDEQ);}
+"|="           { RTOKEN(OREQ);}
+
+"&&"           { RTOKEN(ANDAND);}
+">"            { RTOKEN('>');}
+","            { RTOKEN(',');}
+"&"            { RTOKEN('&');}
+"|"            { RTOKEN('|');}
+"~"            { RTOKEN('~');}
+"!"            { RTOKEN('!');}
+"?"            { RTOKEN('?');}
+"*"            { RTOKEN('*');}
+"%"            { RTOKEN('%');}
+"<"            { RTOKEN('<');}
+"+"            { RTOKEN('+');}
+">"            { RTOKEN('>');}
+"}"            { RTOKEN('}') ; }
+"{"            { RTOKEN('{'); }
+")"            { RTOKEN(')');}
+"("            { RTOKEN('(');}
+"]"            { RTOKEN(']');}
+"["            { RTOKEN('[');}
+":"            { RTOKEN(':'); }
+";"            { RTOKEN(';');}
+"-"            { RTOKEN('-');}
+"="            { RTOKEN('=');}
+
+
+"/*"           { 
+  while (1) {
+    int ch;
+    ch = input();
+    while (ch != '*') {
+      if (ch == '\n') {lineno++; }
+      ch = input();
+    }
+
+
+
+    if (input() == '/') {
+      break;
+    }
+    unput(yytext[yyleng-1]);
+  }
+}
+
+"\""[^\"]*"\"" {
+
+  yylval.name = buystring(yytext+1);
+  yylval.name[yyleng-2] = 0; /* Fry final quote */
+  return NAME;
+}
+[0][0-7KM]* {
+
+  yylval.integer = number(yytext+1, 8);
+ return INT;
+}
+
+[0-9]+[KM]? {
+  if (hex_mode == true) {
+    yylval.integer = number(yytext, 16);
+  }
+  else {
+    yylval.integer = number(yytext, 10);
+  }
+  return INT;
+}
+
+0[Xx][0-9a-fA-FKM]+ {
+  yylval.integer = number(yytext+2,16);        
+  return INT;
+}
+
+"\#"{WHITE}*{FILENAMECHAR}+ {
+  char *p = yytext+1;
+  while(*p ==' ' || *p == '\t') p++;
+  yylval.name = buystring(p);
+  return NAME;
+}
+
+
+{FILENAMECHAR}         {
+
+int ch;
+  keyword_type *k;
+  if (yytext[0] == '/' && ldgram_mustbe_symbolname) 
+    { RTOKEN('/');}
+   ch = input();
+  while (true) {
+    if (isalpha(ch) || isdigit(ch) || ch == '.'  || ch == '_') {
+      yytext[yyleng++] = ch;
+    }
+    else if (ch == '-' && ldgram_want_filename == true) {
+      yytext[yyleng++] = ch;
+    }
+    else if (ch == '+' && ldgram_want_filename == true) {
+      yytext[yyleng++] = ch;
+    }
+
+    else if (ch == '/' && ldgram_want_filename == true) {
+      yytext[yyleng++] = ch;
+    }
+
+    else break;
+    ch = input();
+  }
+
+  yytext[yyleng] = 0;
+  unput(ch);
+
+  for(k = keywords; k ->name != (char *)NULL; k++) {
+
+    if (strcmp(k->name, yytext)==0) {
+      yylval.token = k->value;
+      return k->value;
+    }
+  }
+  yylval.name = buystring(yytext);
+  return NAME;
+}
+
+
+
+
+
+%%
diff --git a/ld/ldmain.c b/ld/ldmain.c
new file mode 100644 (file)
index 0000000..3f9db08
--- /dev/null
@@ -0,0 +1,806 @@
+/* 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.  */
+
+/* 
+ *  Written by Steve Chamberlain steve@cygnus.com
+ *
+ * $Id$ 
+ *
+ * $Log$
+ * Revision 1.1  1991/03/21 21:28:52  gumby
+ * Initial revision
+ *
+ * Revision 1.1  1991/03/13  00:48:27  chrisb
+ * Initial revision
+ *
+ * Revision 1.7  1991/03/10  19:15:45  sac
+ * Fixed a prototype problem
+ *
+ * Revision 1.6  1991/03/10  09:31:32  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.5  1991/03/09  03:31:02  sac
+ * After a fatal info message, the output file is deleted.
+ *
+ * Revision 1.4  1991/03/06  02:28:31  sac
+ * Fixed partial linking and error messages.
+ *
+ * Revision 1.3  1991/02/22  17:15:02  sac
+ * Added RCS keywords and copyrights
+ *
+ *
+ */
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "config.h"
+#include "ld.h"
+#include "ldmain.h"
+#include "ldmisc.h"
+#include "ldwrite.h"
+#include "ldgram.h"
+#include "ldsym.h"
+#include "ldlang.h"
+#include "ld-emul.h"
+#include "ldlex.h"
+#include "ldfile.h"
+
+/* IMPORTS */
+extern boolean lang_has_input_file;
+
+/* EXPORTS */
+
+char *default_target;
+char *output_filename = "a.out";
+/* Name this program was invoked by.  */
+char *program_name;
+
+/* The file that we're creating */
+bfd *output_bfd;
+
+extern boolean option_v;
+
+/* The local symbol prefix */
+char lprefix = 'L';
+
+/* Count the number of global symbols multiply defined.  */
+int multiple_def_count;
+
+
+/* Count the number of symbols defined through common declarations.
+   This count is referenced in symdef_library, linear_library, and
+   modified by enter_global_ref.
+
+   It is incremented when a symbol is created as a common, and
+   decremented when the common declaration is overridden
+
+   Another way of thinking of it is that this is a count of
+   all ldsym_types with a ->scoms field
+*/
+unsigned int commons_pending;
+
+
+/* Count the number of global symbols referenced and not defined. 
+   common symbols are not included in this count.
+  */
+
+unsigned int undefined_global_sym_count;
+
+
+
+/* Count the number of warning symbols encountered. */
+int warning_count;
+
+/* have we had a load script ? */
+extern boolean had_script;
+
+
+
+/* Nonzero means print names of input files as processed.  */
+boolean trace_files;
+
+
+
+/* 1 => write load map.  */
+boolean write_map;
+
+
+int unix_relocate;
+
+
+
+
+
+
+
+
+/* Force the make_executable to be output, even if there are non-fatal
+   errors */
+boolean force_make_executable;
+
+
+/* A count of the total number of local symbols ever seen - by adding
+ the symbol_count field of each newly read afile.*/
+
+
+unsigned int total_symbols_seen;
+
+/* A count of the number of read files - the same as the number of elements
+ in file_chain
+ */
+unsigned int total_files_seen;
+
+
+/* IMPORTS */
+args_type command_line;
+ld_config_type config;
+int
+main (argc, argv)
+     char **argv;
+     int argc;
+{
+  char *emulation;
+  program_name = argv[0];
+  output_filename = "a.out";
+
+  emulation =  getenv(EMULATION_ENVIRON); 
+
+  /* Initialize the data about options.  */
+  strip_symbols = STRIP_NONE;
+  trace_files = false;
+  discard_locals = DISCARD_NONE;
+
+  write_map = false;
+  config.relocateable_output = false;
+  unix_relocate = 0;
+  command_line.force_common_definition = false;
+
+  ldfile_add_arch("");
+
+  config.make_executable = true;
+  force_make_executable = false;
+
+
+  /* Initialize the cumulative counts of symbols.  */
+  undefined_global_sym_count = 0;
+  warning_count = 0;
+  multiple_def_count = 0;
+  commons_pending = 0;
+
+  config.magic_demand_paged = true ;
+  config.make_executable = true;
+
+  if (emulation == (char *)NULL) {
+    emulation= DEFAULT_EMULATION;
+  }
+  ldemul_choose_mode(emulation);
+
+  default_target =  ldemul_choose_target();
+
+  lang_init();
+  ldemul_before_parse();
+
+  lang_has_input_file = false;
+  parse_args(argc, argv);
+
+  if (lang_has_input_file == false) {
+    info("%P%F: No input files\n");
+  }
+
+  ldemul_after_parse();
+
+  lang_process();
+
+
+
+
+  /* Print error messages for any missing symbols, for any warning
+     symbols, and possibly multiple definitions */
+
+  /* Print a map, if requested.  */
+
+  if (write_map) {
+    ldsym_print_symbol_table ();
+    lang_map(stdout);
+  }
+
+
+  if (config.relocateable_output) {
+    output_bfd->flags &=  ~( D_PAGED);
+    output_bfd->flags |= EXEC_P;
+    ldwrite();
+    bfd_close(output_bfd);
+  }
+  else {
+    output_bfd->flags |= EXEC_P;
+
+    ldwrite();
+    bfd_close(output_bfd);
+    if (config.make_executable == false && force_make_executable == false) {
+      unlink(output_filename);
+    }
+    return (!config.make_executable);
+  }
+
+  return(0);
+} /* main() */
+
+
+void
+Q_read_entry_symbols (desc, entry)
+     bfd *desc;
+     struct lang_input_statement_struct *entry;
+{
+  if (entry->asymbols == (asymbol **)NULL) {
+    size_t table_size = get_symtab_upper_bound(desc);
+    entry->asymbols = (asymbol **)ldmalloc(table_size);
+
+    entry->symbol_count =  bfd_canonicalize_symtab(desc, entry->asymbols) ;
+  }
+}
+
+
+/*
+ * turn this item into a reference 
+ */
+static void
+refize(sp, nlist_p)
+ldsym_type *sp;
+asymbol **nlist_p;
+{
+  asymbol *sym = *nlist_p;
+  sym->value = 0;
+  sym->flags = BSF_UNDEFINED;
+  sym->section = (asection *)NULL;
+  sym->udata =(void *)( sp->srefs_chain);
+  sp->srefs_chain = nlist_p;
+}
+/*
+This function is called for each name which is seen which has a global
+scope. It enters the name into the global symbol table in the correct
+symbol on the correct chain. Remember that each ldsym_type has three
+chains attatched, one of all definitions of a symbol, one of all
+references of a symbol and one of all common definitions of a symbol.
+
+When the function is over, the supplied is left connected to the bfd
+to which is was born, with its udata field pointing to the next member
+on the chain in which it has been inserted.
+
+A certain amount of jigery pokery is necessary since commons come
+along and upset things, we only keep one item in the common chain; the
+one with the biggest size seen sofar. When another common comes along
+it either bumps the previous definition into the ref chain, since it
+is bigger, or gets turned into a ref on the spot since the one on the
+common chain is already bigger. If a real definition comes along then
+the common gets bumped off anyway.
+
+Whilst all this is going on we keep a count of the number of multiple
+definitions seen, undefined global symbols and pending commons.
+*/
+
+
+void
+Q_enter_global_ref (nlist_p)
+     asymbol **nlist_p;
+
+{
+  asymbol *sym = *nlist_p;
+  char *name = sym->name;
+  ldsym_type *sp = ldsym_get (name);
+
+  flagword this_symbol_flags = sym->flags;
+
+
+  ASSERT(sym->udata == 0);
+
+  /* Just place onto correct chain */
+  if (flag_is_common(this_symbol_flags)) {
+    /* If we have a definition of this symbol already then
+     * this common turns into a reference. Also we only
+     * ever point to the largest common, so if we
+     * have a common, but it's bigger that the new symbol
+     * the turn this into a reference too.
+     */
+    if (sp->sdefs_chain)  
+      {
+       /* This is a common symbol, but we already have a definition
+          for it, so just link it into the ref chain as if
+          it were a reference
+          */
+       refize(sp, nlist_p);
+      }
+    else  if (sp->scoms_chain) {
+      /* If we have a previous common, keep only the biggest */
+      if ( (*(sp->scoms_chain))->value > sym->value) {
+       /* other common is bigger, throw this one away */
+       refize(sp, nlist_p);
+      }
+      else if (sp->scoms_chain != nlist_p) {
+       /* other common is smaller, throw that away */
+       refize(sp, sp->scoms_chain);
+       sp->scoms_chain = nlist_p;
+      }
+    }
+    else {
+      /* This is the first time we've seen a common, so
+       * remember it - if it was undefined before, we know it's defined now
+       */
+      if (sp->srefs_chain)
+       undefined_global_sym_count--;
+
+      commons_pending++;
+      sp->scoms_chain = nlist_p;
+    }
+  }
+
+  else if (flag_is_defined(this_symbol_flags)) {
+    /* This is the definition of a symbol, add to def chain */
+    if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) {
+      /* Multiple definition */
+      asymbol *sy = *(sp->sdefs_chain);
+      lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata;
+      lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata;
+      asymbol ** stat1_symbols  = stat1 ? stat1->asymbols: 0;
+      asymbol ** stat_symbols = stat ? stat->asymbols:0;
+      
+      multiple_def_count++;
+      info("%C: multiple definition of `%T'\n",
+          sym->the_bfd,
+          sym->section,
+          stat1_symbols,
+          sym->value,
+          sym);
+          
+      info("%C: first seen here\n",
+          sy->the_bfd,
+          sy->section,
+          stat_symbols,
+          sy->value);
+    }
+    else {
+      sym->udata =(void *)( sp->sdefs_chain);
+      sp->sdefs_chain = nlist_p;
+    }
+    /* A definition overrides a common symbol */
+    if (sp->scoms_chain) {
+      refize(sp, sp->scoms_chain);
+      sp->scoms_chain = 0;
+      commons_pending--;
+    }
+    else if (sp->srefs_chain) {
+      /* If previously was undefined, then remember as defined */
+      undefined_global_sym_count--;
+    }
+  }
+  else {
+    if (sp->scoms_chain == (asymbol **)NULL 
+       && sp->srefs_chain == (asymbol **)NULL 
+       && sp->sdefs_chain == (asymbol **)NULL) {
+      /* And it's the first time we've seen it */
+      undefined_global_sym_count++;
+
+    }
+
+    refize(sp, nlist_p);
+  }
+
+  ASSERT(sp->sdefs_chain == 0 || sp->scoms_chain == 0);
+  ASSERT(sp->scoms_chain ==0 || (*(sp->scoms_chain))->udata == 0);
+
+
+}
+
+static void
+Q_enter_file_symbols (entry)
+lang_input_statement_type *entry;
+{
+  asymbol **q ;
+  entry->common_section =
+    bfd_make_section(entry->the_bfd, "COMMON");
+  
+  ldlang_add_file(entry);
+
+
+  if (trace_files || option_v) {
+    info("%I\n", entry);
+  }
+
+  total_symbols_seen += entry->symbol_count;
+  total_files_seen ++;
+  for (q = entry->asymbols; *q; q++)
+    {
+      asymbol *p = *q;
+
+      if (flag_is_undefined_or_global_or_common(p->flags))
+       {
+         
+         Q_enter_global_ref(q);
+       }
+      ASSERT(p->flags != 0);
+    }
+}
+
+
+
+/* Searching libraries */
+
+struct lang_input_statement_struct *decode_library_subfile ();
+void linear_library (), symdef_library ();
+
+/* Search the library ENTRY, already open on descriptor DESC.
+   This means deciding which library members to load,
+   making a chain of `struct lang_input_statement_struct' for those members,
+   and entering their global symbols in the hash table.  */
+
+void
+search_library (entry)
+     struct lang_input_statement_struct *entry;
+{
+
+  /* No need to load a library if no undefined symbols */
+  if (!undefined_global_sym_count) return;
+
+  if (bfd_has_map(entry->the_bfd)) 
+    symdef_library (entry);
+  else
+    linear_library (entry);
+
+}
+
+
+void
+Q_read_file_symbols (entry)
+struct lang_input_statement_struct *entry;
+{
+  if (entry->asymbols == (asymbol **)NULL
+      &&entry->real == true 
+      && entry->filename != (char *)NULL)
+    {
+      ldfile_open_file (entry);
+
+      if (bfd_check_format(entry->the_bfd, bfd_object))
+       {
+         entry->the_bfd->usrdata = (void*)entry;
+
+
+         Q_read_entry_symbols (entry->the_bfd, entry);
+         Q_enter_file_symbols (entry);
+       }
+      else if (bfd_check_format(entry->the_bfd, bfd_archive)) 
+       {
+         entry->the_bfd->usrdata = (void *)entry;
+
+         entry->subfiles = (lang_input_statement_type *)NULL;
+         search_library (entry);
+       }
+      else 
+       {
+         info("%F%I: malformed input file (not rel or archive) \n", entry);
+       }
+    }
+
+}
+
+
+/* Construct and return a lang_input_statement_struct for a library member.
+   The library's lang_input_statement_struct is library_entry,
+   and the library is open on DESC.
+   SUBFILE_OFFSET is the byte index in the library of this member's header.
+   We store the length of the member into *LENGTH_LOC.  */
+
+lang_input_statement_type *
+decode_library_subfile (library_entry, subfile_offset)
+     struct lang_input_statement_struct *library_entry;
+     bfd *subfile_offset;
+{
+  register struct lang_input_statement_struct *subentry;
+  subentry = (struct lang_input_statement_struct *) ldmalloc (sizeof (struct lang_input_statement_struct));
+  subentry->filename = subfile_offset -> filename;
+  subentry->local_sym_name  = subfile_offset->filename;
+  subentry->asymbols = 0;
+  subentry->the_bfd = subfile_offset;
+  subentry->subfiles = 0;
+  subentry->next = 0;
+  subentry->superfile = library_entry;
+  subentry->is_archive = false;
+  subentry->header_read_flag = false;
+  subentry->just_syms_flag = false;
+  subentry->loaded = false;
+  subentry->chain = 0;
+
+  return subentry;
+}
+
+boolean  subfile_wanted_p ();
+void
+clear_syms(entry, offset)
+struct lang_input_statement_struct *entry;
+file_ptr offset;
+{
+  carsym *car;
+  unsigned long indx = bfd_get_next_mapent(entry->the_bfd,
+                                          BFD_NO_MORE_SYMBOLS,
+                                          &car);
+  while (indx != BFD_NO_MORE_SYMBOLS) {
+    if (car->file_offset == offset) {
+      car->name = 0;
+    }
+    indx = bfd_get_next_mapent(entry->the_bfd, indx, &car);
+  }
+
+}
+
+/* Search a library that has a map
+ */
+void
+symdef_library (entry)
+     struct lang_input_statement_struct *entry;
+
+{
+  register struct lang_input_statement_struct *prev = 0;
+
+  boolean not_finished = true;
+
+
+  while (not_finished == true)
+    {
+      carsym *exported_library_name;
+      bfd *prev_archive_member_bfd = 0;    
+
+      int idx = bfd_get_next_mapent(entry->the_bfd,
+                                   BFD_NO_MORE_SYMBOLS,
+                                   &exported_library_name);
+
+      not_finished = false;
+
+      while (idx != BFD_NO_MORE_SYMBOLS  && undefined_global_sym_count)
+       {
+
+         if (exported_library_name->name) 
+           {
+
+             ldsym_type *sp =  ldsym_get_soft (exported_library_name->name);
+
+             /* If we find a symbol that appears to be needed, think carefully
+                about the archive member that the symbol is in.  */
+             /* So - if it exists, and is referenced somewhere and is
+                undefined or */
+             if (sp && sp->srefs_chain && !sp->sdefs_chain)
+               {
+                 bfd *archive_member_bfd = bfd_get_elt_at_index(entry->the_bfd, idx);
+                 struct lang_input_statement_struct *archive_member_lang_input_statement_struct;
+
+                 if (archive_member_bfd && bfd_check_format(archive_member_bfd, bfd_object)) 
+                   {
+
+                     /* Don't think carefully about any archive member
+                        more than once in a given pass.  */
+                     if (prev_archive_member_bfd != archive_member_bfd)
+                       {
+
+                         prev_archive_member_bfd = archive_member_bfd;
+
+                         /* Read the symbol table of the archive member.  */
+
+                         if (archive_member_bfd->usrdata != (void *)NULL) {
+
+                           archive_member_lang_input_statement_struct =(lang_input_statement_type *) archive_member_bfd->usrdata;
+                         }
+                         else {
+
+                           archive_member_lang_input_statement_struct =
+                             decode_library_subfile (entry, archive_member_bfd);
+                           archive_member_bfd->usrdata = (void *) archive_member_lang_input_statement_struct;
+
+                         }
+
+         if (archive_member_lang_input_statement_struct == 0) {
+           info ("%F%I contains invalid archive member %s\n",
+                   entry,
+                   sp->name);
+         }
+
+                         if (archive_member_lang_input_statement_struct->loaded == false)  
+                           {
+
+                             Q_read_entry_symbols (archive_member_bfd, archive_member_lang_input_statement_struct);
+                             /* Now scan the symbol table and decide whether to load.  */
+
+
+                             if (subfile_wanted_p (archive_member_lang_input_statement_struct) == true)
+
+                               {
+                                 /* This member is needed; load it.
+                                    Since we are loading something on this pass,
+                                    we must make another pass through the symdef data.  */
+
+                                 not_finished = true;
+
+                                 Q_enter_file_symbols (archive_member_lang_input_statement_struct);
+
+                                 if (prev)
+                                   prev->chain = archive_member_lang_input_statement_struct;
+                                 else
+                                   entry->subfiles = archive_member_lang_input_statement_struct;
+
+
+                                 prev = archive_member_lang_input_statement_struct;
+
+
+                                 /* Clear out this member's symbols from the symdef data
+                                    so that following passes won't waste time on them.  */
+                                 clear_syms(entry, exported_library_name->file_offset);
+                                 archive_member_lang_input_statement_struct->loaded = true;
+                               }
+                           }
+                       }
+                   }
+               }
+           }
+         idx = bfd_get_next_mapent(entry->the_bfd, idx, &exported_library_name);
+       }
+    }
+}
+
+void
+linear_library (entry)
+struct lang_input_statement_struct *entry;
+{
+  boolean more_to_do = true;
+  register struct lang_input_statement_struct *prev = 0;
+
+  while (more_to_do) {
+
+    bfd *  archive = bfd_openr_next_archived_file(entry->the_bfd,0);
+
+    more_to_do = false;
+    while (archive) {
+      if (bfd_check_format(archive, bfd_object)) 
+       {
+         register struct lang_input_statement_struct *subentry;
+
+         subentry = decode_library_subfile (entry,
+                                            archive);
+
+         archive->usrdata = (void *) subentry;
+         if (!subentry) return;
+         if (subentry->loaded == false) {
+           Q_read_entry_symbols (archive, subentry);
+
+           if (subfile_wanted_p (subentry) == true)
+             {
+               Q_enter_file_symbols (subentry);
+
+               if (prev)
+                 prev->chain = subentry;
+               else 
+                 entry->subfiles = subentry;
+               prev = subentry;
+
+               more_to_do = true;
+               subentry->loaded = true;
+             }
+         }
+       }
+      archive = bfd_openr_next_archived_file(entry->the_bfd,archive);
+    }
+
+  }
+}
+
+  /* ENTRY is an entry for a library member.
+     Its symbols have been read into core, but not entered.
+     Return nonzero if we ought to load this member.  */
+
+boolean
+subfile_wanted_p (entry)
+struct lang_input_statement_struct *entry;
+{
+  asymbol **q;
+
+  for (q = entry->asymbols; *q; q++)
+    {
+      asymbol *p = *q;
+
+      /* If the symbol has an interesting definition, we could
+        potentially want it.  */
+
+      if (p->flags & BSF_FORT_COMM 
+         || p->flags & BSF_GLOBAL)
+       {
+         register ldsym_type *sp = ldsym_get_soft (p->name);
+
+
+         /* If this symbol has not been hashed,
+            we can't be looking for it. */
+         if (sp != (ldsym_type *)NULL 
+             && sp->sdefs_chain == (asymbol **)NULL) {
+           if (sp->srefs_chain  != (asymbol **)NULL
+               || sp->scoms_chain != (asymbol **)NULL)
+             {
+               /* This is a symbol we are looking for.  It is either
+                  not yet defined or common.  */
+
+               if (flag_is_common(p->flags))
+                 {
+                   /* This libary member has something to
+                      say about this element. We should 
+                      remember if its a new size  */
+                   /* Move something from the ref list to the com list */
+                   if(sp->scoms_chain) {
+                     /* Already a common symbol, maybe update it */
+                     if (p->value > (*(sp->scoms_chain))->value) {
+                       (*(sp->scoms_chain))->value = p->value;
+                     }
+                   }
+                   else {
+                     /* Take a value from the ref chain
+                        Here we are moving a symbol from the owning bfd
+                        to another bfd. We must set up the
+                        common_section portion of the bfd thing */
+
+                     
+
+                     sp->scoms_chain = sp->srefs_chain;
+                     sp->srefs_chain =
+                       (asymbol **)((*(sp->srefs_chain))->udata);
+                     (*(sp->scoms_chain))->udata = (void*)NULL;
+
+                     (*(  sp->scoms_chain))->flags = BSF_FORT_COMM;
+                     commons_pending++;
+                     undefined_global_sym_count--;
+                   } {
+                     asymbol *com = *(sp->scoms_chain);
+                     if (((lang_input_statement_type *)
+                          (com->the_bfd->usrdata))->common_section ==
+                         (asection *)NULL) {
+                       ((lang_input_statement_type *)
+                        (com->the_bfd->usrdata))->common_section = 
+                          bfd_make_section(com->the_bfd, "COMMON");
+                     }
+                   }
+                   ASSERT(p->udata == 0);
+                 }
+             
+               else {
+                 if (write_map)
+                   {
+                     info("%I needed due to %s\n",entry, sp->name);
+                   }
+                 return true;
+               }
+             }
+         }
+       }
+    }
+
+  return false;
+}
+
diff --git a/ld/ldmain.h b/ld/ldmain.h
new file mode 100644 (file)
index 0000000..9f3fa1a
--- /dev/null
@@ -0,0 +1,23 @@
+/* ldmain.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.  */
+
+PROTO(void, Q_enter_global_ref,(asymbol **));
+PROTO(void, Q_read_file_symbols,(struct lang_input_statement_struct *));
+
diff --git a/ld/ldmisc.c b/ld/ldmisc.c
new file mode 100644 (file)
index 0000000..2f73066
--- /dev/null
@@ -0,0 +1,303 @@
+/* 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.  */
+
+/*
+ * $Id$ 
+ *
+ * $Log$
+ * Revision 1.1  1991/03/21 21:28:55  gumby
+ * Initial revision
+ *
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:30  chrisb
+ * Initial revision
+ *
+ * Revision 1.7  1991/03/10  09:31:34  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.6  1991/03/09  03:31:01  sac
+ * After a fatal info message, the output file is deleted.
+ *
+ * Revision 1.5  1991/03/06  21:59:54  sac
+ * Made %C print function name if available
+ *
+ * Revision 1.4  1991/03/06  02:27:45  sac
+ * Added support for linenumber printing via %C
+ *
+ * Revision 1.3  1991/02/22  17:15:03  sac
+ * Added RCS keywords and copyrights
+ *
+ */
+
+/*
+  ldmisc.c
+
+*/
+
+#include "sysdep.h"
+#include <varargs.h>
+#include "bfd.h"
+
+#include "ld.h"
+#include "ldmisc.h"
+#include "ldlang.h"
+
+/* IMPORTS */
+
+extern char *program_name;
+
+extern FILE *ldlex_input_stack;
+extern char *ldfile_input_filename;
+extern ld_config_type config;
+
+void
+yyerror(arg) 
+char *arg;
+{ 
+  info("%P%F: %S %s\n",arg);
+}
+
+extern int errno;
+extern   int  sys_nerr;
+extern char *sys_errlist[];
+
+/*
+ %F error is fatal
+ %P print progam name
+ %S print script file and linenumber
+ %E current bfd error or errno
+ %I filename from a lang_input_statement_type
+ %B filename from a bfd
+ %T symbol table entry
+ %X no object output, fail return
+ %V hex bfd_vma
+ %C Clever filename:linenumber 
+ %
+*/
+void info(va_alist)
+va_dcl
+{
+  char *fmt;
+  boolean fatal = false;
+  va_list arg;
+  va_start(arg);
+  fmt = va_arg(arg, char *);
+  while (*fmt) {
+    while (*fmt != '%' && *fmt != '\0') {
+      fputc(*fmt, stderr);
+      fmt++;
+    }
+    if (*fmt == '%') {
+      fmt ++;
+      switch (*fmt++) {
+      case 'X':
+       config.make_executable = false;
+       break;
+      case 'V':
+       fprintf(stderr,"%08lx", va_arg(arg, bfd_vma));
+       break;
+      case 'T':
+       {
+         asymbol *symbol = va_arg(arg, asymbol *);
+         if (symbol) {
+           asection *section = symbol->section;
+           if ((symbol->flags & BSF_UNDEFINED) == 0) {
+             char *section_name = section == (asection *)NULL ?
+               "absolute" : section->name;
+             fprintf(stderr,"%s (%s)", symbol->name, section_name);
+           }
+           else {
+             fprintf(stderr,"%s", symbol->name);
+           }
+         }
+         else {
+           fprintf(stderr,"no symbol");
+         }
+       }
+       break;
+      case 'B':
+       { 
+         bfd *abfd = va_arg(arg, bfd *);
+         if (abfd->my_archive) {
+           fprintf(stderr,"%s(%s)", abfd->my_archive->filename,
+                   abfd->filename);
+         }
+         else {
+           fprintf(stderr,"%s", abfd->filename);
+
+         }
+       }
+       break;
+      case 'F':
+       fatal = true;
+       break;
+      case 'P':
+       fprintf(stderr,"%s", program_name);
+       break;
+      case 'E':
+       /* Replace with the most recent errno explanation */
+
+
+       fprintf(stderr, bfd_errmsg(bfd_error));
+
+
+       break;
+      case 'I':
+       {
+         lang_input_statement_type *i =
+           va_arg(arg,lang_input_statement_type *);
+       
+         fprintf(stderr,"%s", i->local_sym_name);
+       }
+       break;
+      case 'S':
+       /* Print source script file and line number */
+
+       if (ldlex_input_stack) {
+         extern unsigned int lineno;
+         if (ldfile_input_filename == (char *)NULL) {
+           fprintf(stderr,"command line");
+         }
+         else {
+           fprintf(stderr,"%s:%u", ldfile_input_filename, lineno + 1);
+         }
+       }
+       else {
+         fprintf(stderr,"command line ");
+       }
+       break;
+      case 'C':
+       {
+         char *filename;
+         char *functionname;
+         unsigned int linenumber;
+         bfd *abfd = va_arg(arg, bfd *);
+         asection *section = va_arg(arg, asection *);
+         asymbol **symbols = va_arg(arg, asymbol **);
+         bfd_vma offset = va_arg(arg, bfd_vma);
+        
+         if (bfd_find_nearest_line(abfd,
+                                   section,
+                                   symbols,
+                                   offset,
+                                   &filename,
+                                   &functionname,
+                                   &linenumber))
+           {
+               if (filename == (char *)NULL)   
+                   filename = abfd->filename;
+               if (functionname != (char *)NULL)
+                   fprintf(stderr,"%s:%u: (%s)", filename, linenumber,  functionname);
+               else if (linenumber != 0) 
+                   fprintf(stderr,"%s:%u", filename, linenumber);
+               else
+                   fprintf(stderr,"%s", filename);
+
+           }
+         else {
+           fprintf(stderr,"%s", abfd->filename);
+         }
+       }
+       break;
+               
+      case 's':
+       fprintf(stderr,"%s", va_arg(arg, char *));
+       break;
+      case 'd':
+       fprintf(stderr,"%d", va_arg(arg, int));
+       break;
+      default:
+       fprintf(stderr,"%s", va_arg(arg, char *));
+       break;
+      }
+    }
+  }
+  if (fatal == true) {
+    extern char *output_filename;
+    if (output_filename)
+      unlink(output_filename);
+    exit(1);
+  }
+  va_end(arg);
+}
+
+
+void 
+info_assert(file, line)
+char *file;
+unsigned int line;
+{
+  info("%F%P internal error %s %d\n", file,line);
+}
+
+/* Return a newly-allocated string
+   whose contents concatenate those of S1, S2, S3.  */
+
+char *
+concat (s1, s2, s3)
+     char *s1, *s2, *s3;
+{
+  size_t len1 = strlen (s1);
+  size_t len2 = strlen (s2);
+  size_t len3 = strlen (s3);
+  char *result = ldmalloc (len1 + len2 + len3 + 1);
+
+  if (len1 != 0)
+    memcpy(result, s1, len1);
+  if (len2 != 0)
+    memcpy(result+len1, s2, len2);
+  if (len3 != 0)
+    memcpy(result+len1+len2, s2, len3);
+  *(result + len1 + len2 + len3) = 0;
+
+  return result;
+}
+
+
+
+char  *ldmalloc (size)
+size_t size;
+{
+  char * result =  malloc (size);
+
+  if (result == (char *)NULL && size != 0)
+    info("%F%P virtual memory exhausted\n");
+
+  return result;
+} 
+
+
+
+char *buystring(x)
+char *x;
+{
+  size_t  l = strlen(x)+1;
+  char *r = ldmalloc(l);
+  memcpy(r, x,l);
+  return r;
+}
diff --git a/ld/ldmisc.h b/ld/ldmisc.h
new file mode 100644 (file)
index 0000000..e3463d1
--- /dev/null
@@ -0,0 +1,34 @@
+/* ldmisc.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.  */
+
+
+
+/* VARARGS*/
+PROTO(void,info,());
+PROTO(void,info_assert,(char *, unsigned int));
+PROTO(void,yyerror,(char *));
+PROTO(char *,concat,(char *, char *, char *));
+PROTO(char *, ldmalloc,(size_t));
+PROTO(char *,buystring,(char *));
+#define ASSERT(x) \
+{ if (!(x)) info_assert(__FILE__,__LINE__); }
+
+#define FAIL() \
+{ info_assert(__FILE__,__LINE__); }
diff --git a/ld/ldsym.c b/ld/ldsym.c
new file mode 100644 (file)
index 0000000..796060c
--- /dev/null
@@ -0,0 +1,452 @@
+/* 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.  */
+
+/*
+ *  $Id$ 
+ *
+ *  $Log$
+ *  Revision 1.1  1991/03/21 21:28:58  gumby
+ *  Initial revision
+ *
+ * Revision 1.1  1991/03/13  00:48:32  chrisb
+ * Initial revision
+ *
+ * Revision 1.4  1991/03/10  09:31:36  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.3  1991/03/06  02:28:56  sac
+ * Cleaned up
+ *
+ * Revision 1.2  1991/02/22  17:15:06  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/* 
+   Written by Steve Chamberlain steve@cygnus.com
+   All symbol handling for the linker
+ */
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "ld.h"
+#include "ldsym.h"
+#include "ldmisc.h"
+#include "ldlang.h"
+/* IMPORT */
+
+extern bfd *output_bfd;
+/* Head and tail of global symbol table chronological list */
+
+ldsym_type *symbol_head = (ldsym_type *)NULL;
+ldsym_type **symbol_tail_ptr = &symbol_head;
+
+/*
+  incremented for each symbol in the ldsym_type table
+  no matter what flavour it is 
+*/
+unsigned int global_symbol_count;
+
+/* IMPORTS */
+
+extern boolean option_longmap ;
+
+/* LOCALS */
+#define        TABSIZE 1009
+static ldsym_type *global_symbol_hash_table[TABSIZE];
+
+/* Compute the hash code for symbol name KEY.  */
+
+int
+hash_string (key)
+     char *key;
+{
+  register char *cp;
+  register int k;
+
+  cp = key;
+  k = 0;
+  while (*cp)
+    k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+  return k;
+}
+
+/* Get the symbol table entry for the global symbol named KEY.
+   Create one if there is none.  */
+ldsym_type *
+ldsym_get (key)
+     char *key;
+{
+  register int hashval;
+  register ldsym_type *bp;
+
+  /* Determine the proper bucket.  */
+
+  hashval = hash_string (key) % TABSIZE;
+
+  /* Search the bucket.  */
+
+  for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
+    if (! strcmp (key, bp->name))
+      return bp;
+
+  /* Nothing was found; create a new symbol table entry.  */
+
+  bp = (ldsym_type *) ldmalloc (sizeof (ldsym_type));
+  bp->srefs_chain = (asymbol **)NULL;
+  bp->sdefs_chain = (asymbol **)NULL;
+  bp->scoms_chain = (asymbol **)NULL;
+  bp->name = (char *) ldmalloc (strlen (key) + 1);
+  strcpy (bp->name, key);
+
+
+
+
+  /* Add the entry to the bucket.  */
+
+  bp->link = global_symbol_hash_table[hashval];
+  global_symbol_hash_table[hashval] = bp;
+
+  /* Keep the chronological list up to date too */
+  *symbol_tail_ptr = bp;
+  symbol_tail_ptr = &bp->next;
+  bp->next = 0;
+  global_symbol_count++;
+
+  return bp;
+}
+
+/* Like `ldsym_get' but return 0 if the symbol is not already known.  */
+
+ldsym_type *
+ldsym_get_soft (key)
+     char *key;
+{
+  register int hashval;
+  register ldsym_type *bp;
+
+  /* Determine which bucket.  */
+
+  hashval = hash_string (key) % TABSIZE;
+
+  /* Search the bucket.  */
+
+  for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
+    if (! strcmp (key, bp->name))
+      return bp;
+
+  return 0;
+}
+
+
+
+
+
+static void
+list_file_locals (entry)
+lang_input_statement_type *entry;
+{
+  asymbol **q;
+  fprintf (stderr, "\nLocal symbols of ");
+  info("%I", entry);
+  fprintf (stderr, ":\n\n");
+  if (entry->asymbols) {
+    for (q = entry->asymbols; *q; q++) 
+      {
+       asymbol *p = *q;
+       /* If this is a definition,
+          update it if necessary by this file's start address.  */
+       if (p->flags & BSF_LOCAL)
+        info("  %V %s\n",p->value, p->name);
+      }
+  }
+}
+
+
+static void
+print_file_stuff(f)
+lang_input_statement_type *f;
+{
+  fprintf (stderr, "  %s", f->filename);
+  fprintf (stderr, " ");
+  if (f->just_syms_flag) 
+    {
+      fprintf (stderr, " symbols only\n");
+    }
+  else 
+    {
+      asection *s;
+      if (option_longmap) {
+       for (s = f->the_bfd->sections;
+            s != (asection *)NULL;
+            s = s->next) {
+         fprintf (stderr, "%08lx %08x 2**%2ud %s\n",
+                  s->output_offset,
+                  (unsigned)s->size, s->alignment_power, s->name);
+       }
+      }
+      else {         
+       for (s = f->the_bfd->sections;
+            s != (asection *)NULL;
+            s = s->next) {
+         fprintf (stderr, "%s %lx(%x) ",
+                  s->name,
+                  s->output_offset,
+                  (unsigned)   s->size);
+       }
+       fprintf (stderr, "hex \n");
+      }
+    }
+}
+
+void
+ldsym_print_symbol_table ()
+{
+  fprintf (stderr, "\nFiles:\n\n");
+
+  lang_for_each_file(print_file_stuff);
+
+  fprintf (stderr, "\nGlobal symbols:\n\n");
+  {
+    register ldsym_type *sp;
+
+    for (sp = symbol_head; sp; sp = sp->next)
+      {
+       if (sp->sdefs_chain) 
+         {
+           asymbol *defsym = *(sp->sdefs_chain);
+           asection *defsec = bfd_get_section(defsym);
+           fprintf(stderr,"%08lx ",defsym->value);
+           if (defsec)
+             {
+               fprintf(stderr,"%08lx ",defsym->value+defsec->vma);
+               fprintf(stderr,
+                       "%7s",
+                       bfd_section_name(output_bfd,
+                                        defsec));
+
+             }
+           else 
+             {
+               fprintf(stderr,"         .......");
+             }
+
+         }     
+       else {
+         fprintf(stderr,"undefined");
+       }
+
+
+       if (sp->scoms_chain) {
+         fprintf(stderr, " common size %5lu    %s",
+                 (*(sp->scoms_chain))->value, sp->name);
+       }
+       if (sp->sdefs_chain) {
+         fprintf(stderr, " symbol def %08lx    %s",
+                 (*(sp->sdefs_chain))->value,
+                 sp->name);
+       }
+       else {
+         fprintf(stderr, " undefined    %s",
+                 sp->name);
+       }
+       fprintf(stderr, "\n");
+
+      }
+  }
+  lang_for_each_file(list_file_locals);
+}
+
+extern lang_output_section_statement_type *create_object_symbols;
+extern char lprefix;
+static asymbol **
+write_file_locals(output_buffer)
+asymbol **output_buffer;
+{
+LANG_FOR_EACH_INPUT_STATEMENT(entry)
+    {
+      /* Run trough the symbols and work out what to do with them */
+      unsigned int i;
+
+      /* Add one for the filename symbol if needed */
+      if (create_object_symbols 
+         != (lang_output_section_statement_type *)NULL) {
+       asection *s;
+       for (s = entry->the_bfd->sections;
+            s != (asection *)NULL;
+            s = s->next) {
+         if (s->output_section == create_object_symbols->bfd_section) {
+           /* Add symbol to this section */
+           asymbol * newsym  =
+             (asymbol *)bfd_make_empty_symbol(entry->the_bfd);
+           newsym->name = entry->local_sym_name;
+           /* The symbol belongs to the output file's text section */
+
+           /* The value is the start of this section in the output file*/
+           newsym->value  = 0;
+           newsym->flags = BSF_LOCAL;
+           newsym->section = s;
+           *output_buffer++ = newsym;
+           break;
+         }
+       }
+      }
+      for (i = 0; i < entry->symbol_count; i++) 
+       {
+         asymbol *p = entry->asymbols[i];
+
+         if (flag_is_global(p->flags) || flag_is_absolute(p->flags))
+           {
+             /* We are only interested in outputting 
+                globals at this stage in special circumstances */
+             if (p->the_bfd == entry->the_bfd 
+                 && flag_is_not_at_end(p->flags)) {
+               /* And this is one of them */
+               *(output_buffer++) = p;
+               p->flags |= BSF_KEEP;
+             }
+           }
+         else {
+           if (flag_is_ordinary_local(p->flags)) 
+             {
+               if (discard_locals == DISCARD_ALL)
+                 {  }
+               else if (discard_locals == DISCARD_L &&
+                        (p->name[0] == lprefix)) 
+                 {  }
+               else if (p->flags ==  BSF_WARNING) 
+                 {  }
+               else 
+                 { *output_buffer++ = p; }
+             }
+           else if (flag_is_debugger(p->flags)) 
+             {
+               /* Only keep the debugger symbols if no stripping required */
+               if (strip_symbols == STRIP_NONE) {
+                 *output_buffer++ = p;
+               }
+             }
+           else if (flag_is_undefined(p->flags)) 
+             { /* This must be global */
+             }
+           else if (flag_is_common(p->flags)) {
+          /* And so must this */
+           } 
+           else if (p->flags & BSF_CTOR) {
+             /* Throw it away */
+           }
+else
+             {
+               FAIL();
+             }
+         }
+       }
+
+
+    }
+  return output_buffer;
+}
+
+
+static asymbol **
+write_file_globals(symbol_table)
+asymbol **symbol_table;
+{
+  FOR_EACH_LDSYM(sp)
+    {
+      if (sp->sdefs_chain != (asymbol **)NULL) {
+       asymbol *bufp = (*(sp->sdefs_chain));
+
+       if ((bufp->flags & BSF_KEEP) ==0) {
+         ASSERT(bufp != (asymbol *)NULL);
+
+         bufp->name = sp->name;
+
+         if (sp->scoms_chain != (asymbol **)NULL)      
+
+           {
+             /* 
+                defined as common but not allocated, this happens
+                only with -r and not -d, write out a common
+                definition
+                */
+             bufp = *(sp->scoms_chain);
+           }
+         *symbol_table++ = bufp;
+       }
+      }
+      else if (sp->scoms_chain != (asymbol **)NULL) {
+       /* This symbol is a common - just output */
+       asymbol *bufp = (*(sp->scoms_chain));
+       *symbol_table++ = bufp;
+      }
+      else if (sp->srefs_chain != (asymbol **)NULL) {
+       /* This symbol is undefined but has a reference */
+       asymbol *bufp = (*(sp->srefs_chain));
+       *symbol_table++ = bufp;
+      }
+      else {
+       /*
+          This symbol has neither defs nor refs, it must have come
+          from the command line, since noone has used it it has no
+          data attatched, so we'll ignore it 
+          */
+      }
+    }
+  return symbol_table;
+}
+
+
+
+void
+ldsym_write()
+{
+  if (strip_symbols != STRIP_ALL) {
+    /* We know the maximum size of the symbol table -
+       it's the size of all the global symbols ever seen +
+       the size of all the symbols from all the files +
+       the number of files (for the per file symbols)
+       +1 (for the null at the end)
+       */
+    extern unsigned int total_files_seen;
+    extern unsigned int total_symbols_seen;
+
+    asymbol **  symbol_table =  (asymbol **) 
+      ldmalloc ((size_t)(global_symbol_count +
+                        total_files_seen +
+                        total_symbols_seen + 1) *     sizeof (asymbol *));
+    asymbol ** tablep = write_file_locals(symbol_table);
+
+    tablep = write_file_globals(tablep);
+
+    *tablep =  (asymbol *)NULL;
+    bfd_set_symtab(output_bfd, symbol_table, (unsigned)( tablep - symbol_table));
+  }
+}
diff --git a/ld/ldwrite.c b/ld/ldwrite.c
new file mode 100644 (file)
index 0000000..a4282b3
--- /dev/null
@@ -0,0 +1,441 @@
+/* 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.  */
+
+/*
+ * $Id$ 
+ *
+ *  $Log$
+ *  Revision 1.1  1991/03/21 21:29:04  gumby
+ *  Initial revision
+ *
+ * Revision 1.2  1991/03/15  18:45:55  rich
+ * foo
+ *
+ * Revision 1.1  1991/03/13  00:48:37  chrisb
+ * Initial revision
+ *
+ * Revision 1.7  1991/03/10  19:15:03  sac
+ * Took out the abort() which had been put in the wrong place
+ * Updated the version #.
+ *
+ * Revision 1.6  1991/03/10  09:31:41  rich
+ *  Modified Files:
+ *     Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
+ *     ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
+ *     ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
+ *     ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
+ *     ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
+ *
+ * As of this round of changes, ld now builds on all hosts of (Intel960)
+ * interest and copy passes my copy test on big endian hosts again.
+ *
+ * Revision 1.5  1991/03/09  03:25:08  sac
+ * Added support for LONG, SHORT and BYTE keywords in scripts
+ *
+ * Revision 1.4  1991/03/06  21:59:34  sac
+ * Completed G++ support
+ *
+ * Revision 1.3  1991/03/06  02:29:52  sac
+ * Added support for partial linking.
+ *
+ * Revision 1.2  1991/02/22  17:15:11  sac
+ * Added RCS keywords and copyrights
+ *
+*/
+
+/* 
+   This module writes out the final image by reading sections from the
+   input files, relocating them and writing them out
+
+   There are two main paths through this module, one for normal
+   operation and one for partial linking. 
+
+   During  normal operation, raw section data is read along with the
+   associated relocation information, the relocation info applied and
+   the section data written out on a section by section basis.
+
+   When partially linking, all the relocation records are read to work
+   out how big the output relocation vector will be. Then raw data is
+   read, relocated and written section by section.
+
+   Written by Steve Chamberlain steve@cygnus.com
+
+*/
+
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "ldlang.h"
+#include "ld.h"
+#include "ldwrite.h"
+#include "ldmisc.h"
+#include "ldsym.h"
+#include "ldgram.tab.h"
+
+
+
+char *ldmalloc();
+/* Static vars for do_warnings and subroutines of it */
+int list_unresolved_refs;      /* List unresolved refs */
+int list_warning_symbols;      /* List warning syms */
+int list_multiple_defs;                /* List multiple definitions */
+extern int errno;
+extern char *sys_errlist[];
+
+extern unsigned int undefined_global_sym_count;
+
+extern bfd *output_bfd;
+
+extern struct lang_output_section_statement_struct * create_object_symbols;
+
+extern char lprefix;
+
+#ifdef __STDC__
+void lang_for_each_statement(void (*func)());
+#else /* __STDC__ */
+void lang_for_each_statement();
+#endif /* __STDC__ */
+
+extern size_t largest_section;
+ld_config_type config;
+
+extern unsigned int global_symbol_count;
+
+boolean trace_files;
+
+static void perform_relocation(input_bfd,
+                              input_section,
+                              data,
+                              symbols)
+bfd *input_bfd;
+asection *input_section;
+void *data;
+asymbol **symbols;
+{
+  static asymbol *error_symbol = (asymbol *)NULL;
+  static unsigned int error_count = 0;
+#define MAX_ERRORS_IN_A_ROW 5
+  size_t reloc_size = get_reloc_upper_bound(input_bfd, input_section);
+
+  arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
+  arelent **parent;
+  bfd *ob = output_bfd;
+  asection *os = input_section->output_section;
+  if (config.relocateable_output == false) ob = (bfd *)NULL;
+
+  if (bfd_canonicalize_reloc(input_bfd, 
+                            input_section,
+                            reloc_vector,
+                            symbols) )
+    {
+      for (parent = reloc_vector; *parent; parent++) 
+       {
+
+         bfd_reloc_status_enum_type r=
+           bfd_perform_relocation(input_bfd,
+                                  *parent,
+                                  data,
+                                  input_section, 
+                                  ob);
+
+         if (r == bfd_reloc_ok) {
+           if (ob != (bfd *)NULL) {
+             /* A parital link, so keep the relocs */
+             os->orelocation[os->reloc_count] = *parent;
+             os->reloc_count++;
+           }
+         }
+         else
+           {
+             asymbol *s;
+             arelent *p = *parent;
+
+             if (ob != (bfd *)NULL) {
+               /* A parital link, so keep the relocs */
+               os->orelocation[os->reloc_count] = *parent;
+               os->reloc_count++;
+             }
+
+             if (p->sym_ptr_ptr != (asymbol **)NULL) {
+               s = *(p->sym_ptr_ptr);
+             }
+             else {
+               s = (asymbol *)NULL;
+             }
+             switch (r)
+               {
+               case bfd_reloc_undefined:
+                 /* We remember the symbol, and never print more than
+                    a reasonable number of them in a row */
+                 if (s == error_symbol) {
+                   error_count++;
+                 }
+                 else {
+                   error_count = 0;
+                   error_symbol = s;
+                 }
+                 if (error_count < MAX_ERRORS_IN_A_ROW) {
+                   info("%C: undefined reference to `%T'\n",
+                        input_bfd,
+                        input_section,
+                        symbols,
+                        (*parent)->address,
+                        s);
+                   config.make_executable = false;
+                 }
+                 else if (error_count == MAX_ERRORS_IN_A_ROW) {
+                   info("%C: more undefined references to `%T' follow\n",
+                        input_bfd,
+                        input_section,
+                        symbols,
+                        (*parent)->address,
+                        s);
+                 }                 
+                 else {
+                   /* Don't print any more */
+                 }
+                 break;
+               case bfd_reloc_dangerous: 
+                 info("%B: relocation may be wrong `%T'\n",
+                      input_bfd,
+                      s);
+                 break;
+               case bfd_reloc_outofrange:
+                 info("%B:%s relocation address out of range %T (%x)\n",
+                      input_bfd,
+                      input_section->name,
+                      s,
+                      p->address); 
+                 break;
+               case bfd_reloc_overflow:
+                 info("%B:%s relocation overflow in %T reloc type %d\n",
+                      input_bfd,
+                      input_section->name,
+                      s,
+                      p->howto->type);
+                 break;
+               default:
+                 info("%F%B: relocation error, symbol `%T'\n",
+                      input_bfd,
+                      s);
+                 break;
+               }
+           }
+       }
+    }
+  free((char *)reloc_vector);
+}
+
+
+
+
+
+
+void  *data_area;
+
+static void
+copy_and_relocate(statement)
+lang_statement_union_type *statement;
+{
+  switch (statement->header.type) {
+  case lang_fill_statement_enum: 
+    {
+#if 0
+      bfd_byte play_area[SHORT_SIZE];
+      unsigned int i;
+      bfd_putshort(output_bfd, statement->fill_statement.fill, play_area);
+      /* Write out all entire shorts */
+      for (i = 0;
+          i < statement->fill_statement.size - SHORT_SIZE + 1;
+          i+= SHORT_SIZE)
+       {
+         bfd_set_section_contents(output_bfd,
+                                  statement->fill_statement.output_section,
+                                  play_area,
+                                  statement->data_statement.output_offset +i,
+                                  SHORT_SIZE);
+
+       }
+
+      /* Now write any remaining byte */
+      if (i < statement->fill_statement.size) 
+       {
+         bfd_set_section_contents(output_bfd,
+                                  statement->fill_statement.output_section,
+                                  play_area,
+                                  statement->data_statement.output_offset +i,
+                                  1);
+
+       }
+#endif
+    }
+    break;
+  case lang_data_statement_enum:
+    {
+      bfd_vma value = statement->data_statement.value;
+      bfd_byte play_area[LONG_SIZE];
+      unsigned int size;
+      switch (statement->data_statement.type) {
+      case LONG:
+       bfd_putlong(output_bfd, value,  play_area);
+       size = LONG_SIZE;
+       break;
+      case SHORT:
+       bfd_putshort(output_bfd, value,  play_area);
+       size = SHORT_SIZE;
+       break;
+      case BYTE:
+       bfd_putchar(output_bfd, value,  play_area);
+       size = BYTE_SIZE;
+       break;
+      }
+      
+      bfd_set_section_contents(output_bfd,
+                              statement->data_statement.output_section,
+                              play_area,
+                              statement->data_statement.output_vma,
+                              size);
+                              
+                              
+
+
+    }
+    break;
+  case lang_input_section_enum:
+    {
+    
+      asection *i  = statement->input_section.section;
+      asection *output_section = i->output_section;
+      lang_input_statement_type *ifile = statement->input_section.ifile;
+      bfd *inbfd = ifile->the_bfd;
+      if (output_section->flags & SEC_LOAD && i->size != 0) 
+       {
+         if(bfd_get_section_contents(inbfd,
+                                     i,
+                                     data_area,
+                                     0L,
+                                     i->size) == false) 
+           {
+             info("%F%B error reading section contents %E\n",
+                  inbfd);
+           }
+         perform_relocation (inbfd,  i,  data_area, ifile->asymbols);
+
+
+         if(bfd_set_section_contents(output_bfd,
+                                     output_section,
+                                     data_area,
+                                     (file_ptr)i->output_offset,
+                                     i->size) == false) 
+           {
+             info("%F%B error writing section contents of %E\n",
+                  output_bfd);
+           }
+
+       }
+    }
+    break;
+
+ default:
+    /* All the other ones fall through */
+    ;
+
+  }
+}
+
+void
+write_norel()
+{
+  /* Output the text and data segments, relocating as we go.  */
+  lang_for_each_statement(copy_and_relocate);
+}
+
+
+static void read_relocs(abfd, section, symbols)
+bfd *abfd;
+asection *section;
+asymbol **symbols;
+{
+  /* Work out the output section ascociated with this input section */
+  asection *output_section = section->output_section;
+
+  size_t reloc_size = get_reloc_upper_bound(abfd, section);
+  arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
+
+  if (bfd_canonicalize_reloc(abfd, 
+                            section,
+                            reloc_vector,
+                            symbols)) {
+    output_section->reloc_count   += section->reloc_count;
+  }
+}
+
+
+static void
+write_rel()
+{
+  /*
+     Run through each section of each file and work work out the total
+     number of relocation records which will finally be in each output
+     section 
+     */
+
+  LANG_FOR_EACH_INPUT_SECTION
+    (statement, abfd, section,
+     (read_relocs(abfd, section, statement->asymbols)));
+
+
+
+  /*
+     Now run though all the output sections and allocate the space for
+     all the relocations
+     */
+  LANG_FOR_EACH_OUTPUT_SECTION
+    (section, 
+     (section->orelocation =
+      (arelent **)ldmalloc((size_t)(sizeof(arelent **)*
+                                   section->reloc_count)),
+      section->reloc_count = 0,
+     section->flags |= SEC_HAS_CONTENTS));
+
+
+  /*
+     Copy the data, relocating as we go
+     */
+  lang_for_each_statement(copy_and_relocate);
+}
+
+void
+ldwrite ()
+{
+  data_area = (void*) ldmalloc(largest_section);
+  if (config.relocateable_output == true)
+    {
+      write_rel();
+    }
+  else 
+    {
+    write_norel();
+  }
+  free(data_area);
+  /* Output the symbol table (both globals and locals).  */
+  ldsym_write ();
+
+}
+    
diff --git a/ld/ldwrite.h b/ld/ldwrite.h
new file mode 100644 (file)
index 0000000..2658801
--- /dev/null
@@ -0,0 +1,24 @@
+/* ldwrite.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.  */
+
+
+
+
+PROTO(void, ldwrite, (void));