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