This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

IPA changes to ld


Here are the changes which SGI made to the GNU linker for IPA
(interprocedural analysis).  This is of interest to anyone who wants
to use the IPA optimizations of SGI's Pro64 (at
http://oss.sgi.com/projects/Pro64 - the next release will include
IPA).  It also could potentially be used to help add IPA to GCC or
other compilers.

Overall architecture (as I understand it):

* When the compiler goes from .c to .o it writes a "fake" .o - which
in fact contains compiler intermediate language rather than an object
file.  This is in order to make it possible to use IPA with unmodified
Makefiles.

* When invoking the linker, the modified linker looks at a .o.  If it
is a fake .o, then it loads a shared library ipa.so and passes control
(so if fake .o's are not present, nothing changes; there are also
compiler time #ifdefs to disable the whole thing even before that, if
desired).  The ipa.so passes the intermediate code through a compiler
backend (this is the part which would need to be replaced to make this
whole scheme work with GCC and RTL, rather than Pro64 and WHIRL).
This is implemented as a modified linker rather than a separate
program so that it uses the exact same search paths as the real
linker.

SGI plans to distribute this code from
http://oss.sgi.com/projects/Pro64 - but if it is merged into GNU ld
that has the potential to make life easier in general (and if not,
well, we can just keep distributing it separately).  I'll be up-front
about this - it isn't obvious to me that the patch which I've enclosed
is the best possible solution (which would be general-purpose, easily
applicable to GCC as well as Pro64, etc).  But I wanted to at least
send our diff to the binutils mailing list before distributing our own
version.  The plus side is that none of this code should affect
functionality for users not using IPA.  And of course the other plus
side to this code rather than other hypothetical solutions is that it
does exist.

I can probably help (or find someone who can) if there are simple
problems like diffs which don't apply any more and the like.  If there
is more complicated work to be done, well, I can see what I can do but
it ultimately comes down to conning ^W persuading a victim ^W
volunteer (either within or without SGI) to work on it.

diff -u -r ./bfd/bfd-in2.h /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/bfd-in2.h
--- ./bfd/bfd-in2.h	Thu Feb 22 20:42:51 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/bfd-in2.h	Thu Feb 22 18:24:59 2001
@@ -1233,6 +1233,11 @@
 #define BFD_COM_SECTION_NAME "*COM*"
 #define BFD_IND_SECTION_NAME "*IND*"
 
+#ifdef IPA_LINK
+#define BFD_WHD_SECTION_NAME "*WHD*"
+#define BFD_WHT_SECTION_NAME "*WHT*"
+#endif
+
      /* the absolute section */
 extern const asection bfd_abs_section;
 #define bfd_abs_section_ptr ((asection *) &bfd_abs_section)
@@ -1249,10 +1254,25 @@
 #define bfd_ind_section_ptr ((asection *) &bfd_ind_section)
 #define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr)
 
+#ifdef IPA_LINK
+     /* Pointer to the dummy whirl data section */
+extern const asection bfd_whirl_data_section;
+#define bfd_whirl_data_section_ptr ((asection *) &bfd_whirl_data_section)
+#define bfd_is_whirl_data_section(sec) ((sec) == bfd_whirl_data_section_ptr)
+     /* Pointer to the dummy whirl text section */
+extern const asection bfd_whirl_text_section;
+#define bfd_whirl_text_section_ptr ((asection *) &bfd_whirl_text_section)
+#define bfd_is_whirl_text_section(sec) ((sec) == bfd_whirl_text_section_ptr)
+#endif
+
 extern const struct symbol_cache_entry * const bfd_abs_symbol;
 extern const struct symbol_cache_entry * const bfd_com_symbol;
 extern const struct symbol_cache_entry * const bfd_und_symbol;
 extern const struct symbol_cache_entry * const bfd_ind_symbol;
+#ifdef IPA_LINK
+extern const struct symbol_cache_entry * const bfd_whirl_data_symbol;
+extern const struct symbol_cache_entry * const bfd_whirl_text_symbol;
+#endif
 
 #define bfd_get_section_size_before_reloc(section) \
      ((section)->reloc_done ? (abort (), (bfd_size_type) 1) \
diff -u -r ./bfd/configure /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/configure
--- ./bfd/configure	Thu Feb 22 20:43:50 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/configure	Thu Feb 22 18:25:01 2001
@@ -5728,7 +5728,7 @@
 
 trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
 
-DEFS="-DHAVE_CONFIG_H"
+DEFS="-DHAVE_CONFIG_H -DIPA_LINK"
 
 # Without the "./", some shells look in PATH for config.status.
 : ${CONFIG_STATUS=./config.status}
diff -u -r ./bfd/elf-bfd.h /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/elf-bfd.h
--- ./bfd/elf-bfd.h	Thu Feb 22 20:44:43 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/elf-bfd.h	Thu Feb 22 18:25:03 2001
@@ -193,6 +193,15 @@
      not currently set by all the backends.  */
 #define ELF_LINK_NON_GOT_REF 010000
 
+#ifdef IPA_LINK
+  /* Symbol was marked as having their address taken.  */
+#define ELF_LINK_HASH_ADDRESS_TAKEN 010000
+#endif
+
+#ifdef IPA_LINK
+  /* The internal index ipa has for this symbol */
+  long ipa_indx;
+#endif
 };
 
 
diff -u -r ./bfd/elflink.h /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/elflink.h
--- ./bfd/elflink.h	Thu Feb 22 20:45:42 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/elflink.h	Thu Feb 22 18:25:05 2001
@@ -60,6 +60,20 @@
   PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, 
 	   struct elf_link_hash_entry **));
 
+#ifdef IPA_LINK
+#define SHN_IPA_TEXT     0xff01         /* Allocated text symbols.  */
+#define SHN_IPA_DATA     0xff02         /* Allocated data symbols.  */
+#endif
+
+#ifdef IPA_LINK
+int
+ld_set_ndx (bfd *abfd)
+{
+    return 0;
+}
+#pragma weak ld_set_ndx
+#endif
+
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
 
@@ -369,8 +383,13 @@
 	     something wrong with the archive.  */
 	  if (element->archive_pass != 0)
 	    {
+#ifdef IPA_LINK
+	      /* Already got this obj, skip it and continue */
+	      continue;
+#else
 	      bfd_set_error (bfd_error_bad_value);
 	      goto error_return;
+#endif
 	    }
 	  element->archive_pass = 1;
 
@@ -488,6 +507,14 @@
     {
       h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
      
+#ifdef IPA_LINK
+      /*
+        For SGI intermediate WHIRL format we need to mark the
+        symbol.
+      */
+      h->ipa_indx = ld_set_ndx (abfd);
+#endif
+
       return true;
     }
 
@@ -833,6 +860,9 @@
          of the code does not think we are using the regular
          definition.  */
       if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+#ifdef IPA_LINK
+	if (!ipa_is_whirl(abfd))
+#endif
 	    h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
       else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
 	h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
@@ -1321,6 +1351,12 @@
 	     calls the value we call the alignment.  */
 	  value = sym.st_size;
 	}
+#ifdef IPA_LINK
+      else if (sym.st_shndx == SHN_IPA_TEXT)
+        sec = bfd_whirl_text_section_ptr;
+      else if (sym.st_shndx == SHN_IPA_DATA)
+        sec = bfd_whirl_data_section_ptr;
+#endif
       else
 	{
 	  /* Leave it up to the processor backend.  */
@@ -1606,6 +1642,9 @@
 	    {
 	      if (! definition)
 		{
+#ifdef IPA_LINK
+		  if (!ipa_is_whirl(abfd)) 
+#endif
 		      new_flag = ELF_LINK_HASH_REF_REGULAR;
 		  if (bind != STB_WEAK)
 		    new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
@@ -1675,6 +1714,12 @@
 			      bfd_ind_section_ptr, (bfd_vma) 0, name, false,
 			      collect, (struct bfd_link_hash_entry **) &hi)))
 			goto error_return;
+#ifdef IPA_LINK
+                      if ((flags & BSF_WEAK) != 0) {
+                        hi->weakdef = h->weakdef;
+                        weaks = hi;
+                      }
+#endif // IPA_LINK
 		    }
 		  else
 		    {
diff -u -r ./bfd/linker.c /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/linker.c
--- ./bfd/linker.c	Thu Feb 22 20:46:15 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/linker.c	Thu Feb 22 18:25:08 2001
@@ -25,6 +25,10 @@
 #include "bfdlink.h"
 #include "genlink.h"
 
+#ifdef IPA_LINK
+#pragma weak ipa_is_whirl
+#endif
+      
 /*
 SECTION
 	Linker Functions
@@ -433,6 +437,19 @@
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
 	   struct bfd_link_order *, boolean));
 
+#ifdef IPA_LINK
+
+/* The strong version is defined in ld. */
+#if 1
+boolean is_ipa = 0;
+#pragma weak is_ipa
+#else
+boolean __is_ipa = 0;
+#pragma weak is_ipa = __is_ipa
+#endif
+
+#endif
+
 /* The link hash table structure is defined in bfdlink.h.  It provides
    a base hash table which the backend specific hash tables are built
    upon.  */
@@ -1577,6 +1594,12 @@
 	  {
 	    enum bfd_link_hash_type oldtype;
 
+#ifdef IPA_LINK
+            if (is_ipa && !ipa_is_whirl(abfd))
+                // We only changes definitions for WHIRL object symbols only
+                break;
+#endif
+ 
 	    /* Define a symbol.  */
 	    oldtype = h->type;
 	    if (action == DEFW)
@@ -1588,6 +1611,11 @@
 	      h->type = bfd_link_hash_defined;
 	      }
 	    h->u.def.section = section;
+#ifdef IPA_LINK
+            /* ipa_set_def_bfd(abfd,h); */
+            if (is_ipa)
+                h->u.def.section = (asection *)abfd;
+#endif
 	    h->u.def.value = value;
 
 	    /* If we have been asked to, we act like collect2 and
diff -u -r ./bfd/section.c /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/section.c
--- ./bfd/section.c	Thu Feb 22 20:46:35 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/section.c	Thu Feb 22 18:25:10 2001
@@ -546,6 +546,11 @@
   GLOBAL_SYM_INIT (BFD_UND_SECTION_NAME, &bfd_und_section),
   GLOBAL_SYM_INIT (BFD_ABS_SECTION_NAME, &bfd_abs_section),
   GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, &bfd_ind_section)
+#ifdef IPA_LINK
+  ,
+  GLOBAL_SYM_INIT (BFD_WHD_SECTION_NAME, &bfd_whirl_data_section),
+  GLOBAL_SYM_INIT (BFD_WHT_SECTION_NAME, &bfd_whirl_text_section)
+#endif
 };
 
 #define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX)	\
@@ -781,6 +786,18 @@
     {
       return bfd_ind_section_ptr;
     }
+
+#ifdef IPA_LINK
+  if (strcmp (name, BFD_WHD_SECTION_NAME) == 0)
+    {
+      return bfd_whirl_data_section_ptr;
+    }
+
+  if (strcmp (name, BFD_WHT_SECTION_NAME) == 0)
+    {
+      return bfd_whirl_text_section_ptr;
+    }
+#endif
 
   while (sect)
     {
diff -u -r ./ld/configure /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/configure
--- ./ld/configure	Thu Feb 22 20:40:28 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/configure	Thu Feb 22 18:25:17 2001
@@ -4595,7 +4595,7 @@
 
 trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
 
-DEFS="-DHAVE_CONFIG_H"
+DEFS="-DHAVE_CONFIG_H -DIPA_LINK"
 
 # Without the "./", some shells look in PATH for config.status.
 : ${CONFIG_STATUS=./config.status}
diff -u -r ./ld/ldlang.c /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/ldlang.c
--- ./ld/ldlang.c	Thu Feb 22 20:41:02 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/ldlang.c	Thu Feb 22 18:25:23 2001
@@ -40,6 +40,17 @@
 
 #include <ctype.h>
 
+#ifdef IPA_LINK
+extern boolean is_ipa;
+
+extern boolean
+ipa_is_whirl(bfd *);
+
+extern void
+ipa_process_whirl ( bfd *);
+
+#endif
+
 /* FORWARDS */
 static lang_statement_union_type *new_statement PARAMS ((enum statement_enum,
 							 size_t,
@@ -1500,6 +1511,22 @@
     einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd);
 
   entry->loaded = true;
+
+#ifdef IPA_LINK
+  if (is_ipa) {
+    switch (bfd_get_format (entry->the_bfd)) {
+      default:
+        break;
+
+      case bfd_object:
+        ld_set_cur_obj(entry->the_bfd);
+        if (ipa_is_whirl(entry->the_bfd)) {
+          ipa_process_whirl(entry->the_bfd);
+        }
+        break;
+    }
+  }
+#endif
 }
 
      
@@ -4023,6 +4050,11 @@
   /* Create a bfd for each input file */
   current_target = default_target;
   open_input_bfds (statement_list.head, false);
+
+#ifdef IPA_LINK
+  if (is_ipa)
+    return;
+#endif
 
   ldemul_after_open ();
 
diff -u -r ./ld/ldmain.c /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/ldmain.c
--- ./ld/ldmain.c	Thu Feb 22 20:41:43 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/ldmain.c	Thu Feb 22 18:25:23 2001
@@ -42,6 +42,11 @@
 #include "ldctor.h"
 
 
+#ifdef IPA_LINK
+#include "ipa_ld.h"
+#include "ipa_cmdline.h"
+#endif
+
 /* Somewhere above, sys/stat.h got included . . . . */
 #if !defined(S_ISDIR) && defined(S_IFDIR)
 #define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
@@ -131,6 +136,18 @@
 static boolean notice PARAMS ((struct bfd_link_info *, const char *,
 			       bfd *, asection *, bfd_vma));
 
+#ifdef IPA_LINK
+boolean is_ipa = FALSE;
+
+    /* I have to call this through ld because otherwise
+       ipa_ld.o will get pulled in whether it is wanted
+       or not. */
+int ld_set_ndx(bfd *abfd)
+{
+    return ipa_set_ndx(abfd);
+}
+#endif
+
 static struct bfd_link_callbacks link_callbacks =
 {
   add_archive_element,
@@ -160,14 +177,26 @@
     }
 }
 
+#ifdef IPA_LINK
+int
+main (argc, argv,envp)
+     int argc;
+     char **argv;
+     char **envp;
+#else
 int
 main (argc, argv)
      int argc;
      char **argv;
+#endif
 {
   char *emulation;
   long start_time = get_run_time ();
 
+#ifdef IPA_LINK
+  ipa_search_command_line(argc,argv,envp);
+#endif
+
 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
   setlocale (LC_MESSAGES, "");
 #endif
@@ -345,6 +374,13 @@
 
 
   lang_process ();
+
+#ifdef IPA_LINK
+  if (is_ipa) {
+    cleanup_symtab_for_ipa();
+    (*p_ipa_driver) (ipa_argc, ipa_argv);
+  }
+#endif
 
   /* Print error messages for any missing symbols, for any warning
      symbols, and possibly multiple definitions */
diff -u -r ./ld/lexsup.c /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/lexsup.c
--- ./ld/lexsup.c	Thu Feb 22 20:42:20 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/ld/lexsup.c	Thu Feb 22 18:25:23 2001
@@ -126,6 +126,22 @@
 #define OPTION_SECTION_START		(OPTION_FINI + 1)
 #define OPTION_STDERR_TO_FILE           (OPTION_SECTION_START + 1)
 
+#ifdef IPA_LINK
+
+#define OPTION_KEEP                     (OPTION_STDERR_TO_FILE + 1)
+#define OPTION_SHOW                     (OPTION_KEEP + 1)
+#define OPTION_IPA                      (OPTION_SHOW + 1)
+#define OPTION_DEFAULT_GROUP            (OPTION_IPA + 1)
+#define OPTION_IPA_GROUP                (OPTION_DEFAULT_GROUP + 1)
+#define OPTION_INLINE_GROUP             (OPTION_IPA_GROUP + 1)
+#define OPTION_INTERNAL_GROUP           (OPTION_INLINE_GROUP + 1)
+#define OPTION_AR_MEMBERS               (OPTION_INTERNAL_GROUP + 1)
+#define OPTION_IPACOM                   (OPTION_AR_MEMBERS + 1)
+#define OPTION_OPT_GROUP                (OPTION_IPACOM + 1)
+#define OPTION_TENV_GROUP               (OPTION_OPT_GROUP + 1)
+
+#endif
+
 /* The long options.  This structure is used for both the option
    parsing and the help text.  */
 
@@ -377,6 +393,43 @@
   { {"mpc860c0", optional_argument, NULL, OPTION_MPC860C0},
       '\0', N_("[=WORDS]"), N_("Modify problematic branches in last WORDS (1-10,\n\t\t\t\tdefault 5) words of a page"), TWO_DASHES }
 
+#ifdef IPA_LINK
+    ,
+  { {"ipa", no_argument, NULL, OPTION_IPA},
+      '\0', NULL, N_("Use Inter Process Analysis"), TWO_DASHES },
+
+  { {"show", no_argument, NULL, OPTION_SHOW},
+      '\0', NULL, N_("If IPA then show phases, otherwise unused"), ONE_DASH },
+
+  { {"keep", no_argument, NULL, OPTION_KEEP},
+      '\0', NULL, N_("Don't delete intermediate files"), TWO_DASHES },
+
+  { {"DEFAULT", no_argument, NULL, OPTION_DEFAULT_GROUP},
+      '\0', NULL, N_("Message about xxxxxx"), TWO_DASHES },
+
+  { {"IPA:", no_argument, NULL, OPTION_IPA_GROUP},
+      '\0', NULL, N_("Options passed to IPA"), TWO_DASHES },
+
+  { {"INLINE:", no_argument, NULL, OPTION_INLINE_GROUP},
+      '\0', NULL, N_("Options passed to inliner during ipa phase"), TWO_DASHES },
+
+  { {"INTERNAL:", no_argument, NULL, OPTION_INTERNAL_GROUP},
+      '\0', NULL, N_("Non-user options passed to the backend during ipa phase"), TWO_DASHES },
+
+  { {"ar_members", required_argument, NULL, OPTION_AR_MEMBERS},
+      '\0', NULL, N_("Designates specific objects within an archive"), TWO_DASHES },
+
+  { {"ipacom", no_argument, NULL, OPTION_IPACOM},
+      '\0', NULL, N_("Message about xxxxxx"), TWO_DASHES },
+
+  { {"OPT:", no_argument, NULL, OPTION_OPT_GROUP},
+      '\0', NULL, N_("Optimization options passed to backend during ipa phase"), TWO_DASHES },
+
+  { {"TENV:", no_argument, NULL, OPTION_TENV_GROUP},
+      '\0', NULL, N_("Target environment options passed to backend during ipa phase"), TWO_DASHES }
+
+#endif
+
 };
 
 #define OPTION_COUNT ((int) (sizeof ld_options / sizeof ld_options[0]))
@@ -1078,6 +1131,28 @@
 	case OPTION_FINI:
 	  link_info.fini_function = optarg;
 	  break;
+
+#ifdef IPA_LINK
+        /* These are options that just get passed to ipa */
+        case OPTION_KEEP:
+        case OPTION_DEFAULT_GROUP:
+        case OPTION_IPA_GROUP:
+        case OPTION_INLINE_GROUP:
+        case OPTION_INTERNAL_GROUP:
+        case OPTION_IPACOM:
+        case OPTION_OPT_GROUP:
+        case OPTION_TENV_GROUP:
+        case OPTION_IPA:
+        case OPTION_SHOW:
+          break;
+
+        case OPTION_AR_MEMBERS:
+          lang_add_input_file ( optarg,
+                                lang_input_file_is_file_enum,
+                                (char *) NULL);
+          break;
+#endif
+
 	}
     }
 
--- /dev/null	Thu Feb 22 19:32:40 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/ipa_ld.c	Thu Feb 22 18:25:07 2001
@@ -0,0 +1,1245 @@
+#if defined(__GNUC__)
+#include <stdio.h>		/* for sys_errlist */
+#endif
+#include <stdlib.h>		/* for getenv(3) */
+#include <unistd.h>		/* for unlink(2), rmdir(2), etc. */
+#include <libgen.h>		/* for basename(3) */
+#include <sys/stat.h>		/* for chmod(2) */
+#include <sys/mman.h>		/* for mmap(2) */
+#include <fcntl.h>		/* for open(2) */
+#include <sys/dir.h>		/* for opendir(2), readdir, closedir */
+#include <sys/wait.h>		/* for waitpid(2) */
+#include <alloca.h>		/* for alloca(3) */
+#include <signal.h>		/* for kill(2) */
+#include <limits.h>		/* for PATH_MAX */
+#include <errno.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include "aout/ar.h"
+
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+
+#include "ipa_ld.h"
+
+#define DEFAULT_TOOLROOT "/usr/bin/sgicc"
+
+extern boolean is_ipa;
+
+extern struct bfd_link_info link_info; /* defined in ld/ldmain.c */
+extern char **environ_vars;	    /* list of environment variables */
+
+extern void process_whirl64(void *, off_t, void *, int, const char *);
+#pragma weak process_whirl64
+
+extern void *ipa_open_input(char *, off_t *);
+#pragma weak ipa_open_input
+
+void *(*p_ipa_open_input)(char *, off_t *) = NULL;
+void (*p_ipa_init_link_line)(int, char **) = NULL;
+void (*p_ipa_add_link_flag)(const char*) = NULL;
+void (*p_ipa_driver)(int, char **) = NULL;
+void (*p_process_whirl64)(void *, off_t, void *, int, const char *) = NULL;
+int  (*p_Count_elf_external_gots)(void) = NULL;
+void (*p_ipa_insert_whirl_marker)(void) = NULL;
+void (*p_Sync_symbol_attributes)(unsigned int, unsigned int, boolean, unsigned int) = NULL;
+
+string toolroot = 0;		    /* set to environment variable TOOLROOT */
+
+static int active_pid;
+
+static mode_t cmask = 0;	    /* file creation mode mask */
+
+static string thisfile = __FILE__;
+
+static char *default_path = "/usr/ia64-sgi-linux/lib/gcc-lib/ia64-sgi-linux/sgicc-1.0";
+static char *env_name = "LD_LIBRARY_PATH";
+
+static string *tmp_list = 0;
+static int tmp_list_size = 0;
+static int tmp_list_max = 0;
+string tmpdir = 0;
+static int tmpdir_length = 0;
+static bfd *p_current_bfd = NULL;
+
+string outfilename = "./a.out";
+string WB_flags = NULL;
+string Y_flags = NULL;
+
+LD_IPA_OPTION ld_ipa_opt[] = {
+/************************************************/
+/*  ld_ipa_option_enum	    flag	    set */
+/************************************************/
+    {LD_IPA_SHARABLE, 	    F_CALL_SHARED,  F_CALL_SHARED}, 
+    {LD_IPA_DEMANGLE, 	    0,		    0}, 
+    {LD_IPA_SHOW, 	    0,		    0}, 
+    {LD_IPA_HIDES, 	    0,		    0}, 
+    {LD_IPA_TARGOS, 	    TOS_IA64_64,    0}, 
+    {LD_IPA_ISA,	    0,		    0},
+    {LD_IPA_XXXX, 	    0,		    0}, 
+    {LD_IPA_XXXX, 	    0,		    0}
+};
+
+
+
+	/*******************************************************
+		Dummy functions and variables so we don't
+		have to muck with ipa sources.
+
+		
+	 *******************************************************/
+
+char * always_demangle(char *name, char Demangle){return NULL;}
+char *__Release_ID;
+void read_one_section(int index, void *p_void){return;}
+
+void merge_ext(void *p_sym, char *name, int num, void *p_obj) 
+    {return;}
+
+void msg (int type, int msg_id, ...) {return;}
+
+
+	/*******************************************************
+		Function: ipa_copy_of
+
+		Allocate for and copy given string into a copy.
+
+	 *******************************************************/
+char *
+ipa_copy_of (char *str)
+{
+    register int len;
+    register char *p;
+
+    len = strlen(str) + 1;
+    p = (char *) MALLOC (len);
+    MALLOC_ASSERT (p);
+    BCOPY (str, p, len);
+    return p;
+} /* ipa_copy_of */
+
+
+	/*******************************************************
+		Function: concat_names
+
+		Create a new string by concating 2 other strings.
+
+	 *******************************************************/
+string
+concat_names(const string name1, const string name2)
+{
+    char *mangled_name = NULL;
+    int len = strlen(name1)+strlen(name2)+1;
+
+    mangled_name = (char *)MALLOC(len);
+    MALLOC_ASSERT(mangled_name);
+
+    strcpy(mangled_name, name1);
+    strcat(mangled_name, name2);
+
+    return(mangled_name);
+}
+
+	/*******************************************************
+		Function: dump_argv
+
+		This routines depends on the last argv element
+		being NULL and no others.
+
+	 *******************************************************/
+static void
+dump_argv (string *argv)
+{ 
+    fputs (argv[0], stderr);
+    argv++;
+    while (*argv)
+	fprintf (stderr, " %s", *argv++);
+    fputc ('\n', stderr);
+
+} /* dump_argv */
+
+	/*******************************************************
+		Function: do_compile
+
+		Actually perform compilation
+
+	 *******************************************************/
+int
+do_compile (string *argv)
+{
+    int pid;
+    
+    if (toolroot) {
+	if ((toolroot = getenv ("TOOLROOT")) == 0)
+	    toolroot = ipa_copy_of(DEFAULT_TOOLROOT);
+	else
+	    toolroot = concat_names (toolroot, DEFAULT_TOOLROOT);
+    }
+
+    argv[0] = concat_names (toolroot, basename (argv[0]));
+
+    if (ld_ipa_opt[LD_IPA_VERBOSE].flag || ld_ipa_opt[LD_IPA_SHOW].flag)
+	dump_argv (argv);
+
+    pid = fork();
+    pid = execve(argv[0], argv, environ_vars);
+
+    if (pid < 0) {
+    	perror(argv[0]);
+	exit(1);
+    }
+
+    active_pid = pid;
+    
+    FREE (argv[0]);
+    argv[0] = NULL;
+
+    if (toolroot) {
+    	FREE (toolroot);
+	toolroot = NULL;
+    }
+
+    return pid;
+
+} /* do_compile */
+
+	/*******************************************************
+		Function: ld_kill_compilation
+
+		
+
+	 *******************************************************/
+static void
+ld_kill_compilation (int sig)
+{
+    if (active_pid != 0) {
+	kill (active_pid, sig);
+	active_pid = 0;
+    }
+
+} /* ld_kill_compilation */
+
+
+	/*******************************************************
+		Function: add_to_tmp_file_list
+
+		Maintain list of temp. files created so they are all
+		removed on error or when done.  Assume the first entry
+		is "tmpdir".
+
+	 *******************************************************/
+void
+add_to_tmp_file_list (string path)
+{
+    if (tmp_list_max == 0) {
+	tmp_list_max = DEFAULT_TMP_LIST_SIZE;
+	tmp_list = (string *) MALLOC (tmp_list_max * sizeof(string));
+	MALLOC_ASSERT (tmp_list);
+    } else if (tmp_list_size >= tmp_list_max) {
+	tmp_list_max *= 2;
+	tmp_list = (string *)REALLOC (tmp_list, tmp_list_max * sizeof(string));
+	MALLOC_ASSERT (tmp_list);
+    }
+
+    tmp_list[tmp_list_size++] = path;
+
+} /* add_to_tmp_file_list */
+
+	/*******************************************************
+		Function: remove_from_tmp_file_list
+
+		
+
+	 *******************************************************/
+static void
+remove_from_tmp_file_list (string path)
+{
+
+    if (tmp_list_size == 0)
+	return;
+
+    /* if the last entry is not what we need, don't bother searching for it */
+    if (tmp_list[tmp_list_size - 1] == path)
+	tmp_list_size--;
+    
+} /* remove_from_tmp_file_list */
+
+
+	/*******************************************************
+		Function: cleanup_all_files
+
+		
+
+	 *******************************************************/
+void
+cleanup_all_files (void)
+{
+    int i;
+
+    if (ld_ipa_opt[LD_IPA_KEEP_TEMPS].flag)
+	return;
+    
+    for (i = tmp_list_size - 1; i > 0; i--)
+	UNLINK (tmp_list[i]);
+
+    if (tmp_list_size >= 1)
+	RMDIR (tmp_list[0]);
+
+} /* cleanup_all_files */
+
+
+	/*******************************************************
+		Function: make_temp_file
+
+		Create a unique file
+
+	 *******************************************************/
+/* create a unique file */
+string
+make_temp_file (string name, char suffix)
+{
+    char path[PATH_MAX];
+    int len;
+    int count = 1;
+
+    len = strlen (name);
+    if (len+4 >= PATH_MAX) {
+	fprintf(stderr,"%s %s\n","path name too long:", name);
+	exit(1);
+    }
+
+    strcpy (path, name);
+
+    if (suffix && len >= 2) {
+	/* remove the original suffix */
+	if (path[len-2] == '.') {
+	    len -= 2;
+	    path[len] = 0;
+	}
+    }
+
+    if (suffix) {
+	path[len] = '.';
+	path[len+1] = suffix;
+	path[len+2] = 0;
+    }
+
+    if (access (path, F_OK) != 0)
+	return ipa_copy_of (path);
+
+    do {
+	if (suffix)
+	    sprintf (&(path[len]), ".%d.%c", count, suffix);
+	else
+	    sprintf (&(path[len]), "%d", count);
+	count++;
+    } while (access (path, F_OK) == 0);
+
+    return ipa_copy_of (path);
+
+} /* make_temp_file */
+
+/* ====================================================================
+ *
+ * create_tmpdir
+ *
+ * Create a temporary directory for (1) relocatable objects generated
+ * from the backend under IPA control, (2) IR objects extracted from an
+ * archive, and (3) IR objects generated by IPA.
+ *
+ * There are three cases.  If this is a directory to be kept, because
+ * either -keep or a trace flag is specified for an IPA build, then the
+ * directory is named <outfilename>.ipakeep, and if it already exists,
+ * all files are cleared from it.  If it is a temporary directory for
+ * an IPA build, a unique name is used with the template
+ * $TMPDIR/<outfilename_with_path_stripped>.ipaXXXXXX .  For a normal link, 
+ * a temporary directory
+ * is created in the DEFAULT_TMPDIR with the name template XXXXXX.
+ *
+ * ====================================================================
+ */
+
+int
+create_tmpdir ( int tracing )
+{
+    int fixedname = is_ipa && ( ld_ipa_opt[LD_IPA_KEEP_TEMPS].flag );
+
+    if ( is_ipa ) {
+	if ( fixedname ) {
+	    tmpdir = concat_names ( outfilename, ".ipakeep" );
+	} else {
+	    char *tmpdir_env_var;
+	    if ((tmpdir_env_var = getenv("TMPDIR")) != NULL) {
+		char *filename;
+	        tmpdir_env_var = concat_names ( tmpdir_env_var, "/");
+		if ((filename = strrchr(outfilename, '/')) != NULL)
+		    filename++;
+		else
+		    filename = outfilename;
+		
+	        tmpdir = concat_names ( tmpdir_env_var, filename);
+	    }
+	    else
+	        tmpdir = outfilename;
+	    tmpdir = concat_names ( tmpdir, ".ipaXXXXXX" );
+	}
+    } else {
+	tmpdir = concat_names ( DEFAULT_TMPDIR, "XXXXXX" );
+    }
+    if ( ! fixedname ) {
+	tmpdir = mktemp ( tmpdir );
+    }
+    tmpdir_length = strlen ( tmpdir );
+
+    if ( cmask == 0 ) {
+	cmask = umask (0);
+	(void) umask (cmask);
+    }
+
+    if ( MKDIR (tmpdir, 0777 & ~cmask) != 0 ) {
+	if ( errno == EEXIST && fixedname ) {
+	    /* We have an old instance of this directory -- clear it out: */
+	    DIR *dirp;
+	    struct direct *entryp;
+	    char *prefix;
+
+	    dirp = opendir ( tmpdir );
+	    if ( dirp != NULL ) {
+		prefix = concat_names ( tmpdir, "/" );
+		while ( ( entryp = readdir(dirp) ) != NULL ) {
+		    /* Don't bother with names of one or two characters, e.g. '.'
+		     * and '..', since we don't create temporary files with such
+		     * names:
+		     */
+#if defined(_DIRENT_HAVE_D_NAMLEN)
+		  if ( entryp->d_namlen > 2 )
+#else
+		  if (_D_EXACT_NAMLEN(entryp) > 2)
+#endif
+		    {
+			string fname = concat_names ( prefix, entryp->d_name);
+			unlink (fname);
+			FREE (fname);
+		    }
+		}
+		FREE (prefix);
+		closedir ( dirp );
+	    }
+	} else {
+    	    perror("cannot create temporary directory for code generation");
+	    return -1;
+	}
+    }
+
+    add_to_tmp_file_list ( tmpdir );
+
+    return 0;
+
+} /* create_tmpdir */
+
+	/*******************************************************
+		Function: create_unique_file
+
+		
+
+	 *******************************************************/
+string
+create_unique_file (const string path, char suffix)
+{
+    string p;
+    string base = basename (path);
+    string new_path;
+    int fd;
+
+    /* length of tmpdir + basename of path and '/' between the dir
+       and the basename + null terminator */
+    p = (string) MALLOC (strlen(tmpdir) + strlen(base) + 2);
+    MALLOC_ASSERT (p);
+    strcpy (p, tmpdir);
+    strcat (p, "/");
+    strcat (p, base);
+    new_path = make_temp_file (p, suffix);
+    FREE (p);
+
+    if ((fd = creat (new_path, 0666 & ~cmask)) == -1) {
+	perror(new_path);
+	exit(1);
+    }
+
+    CLOSE (fd);
+    
+    return new_path;
+
+} /* create_unique_file */
+
+
+	/*******************************************************
+		Function: get_command_line
+
+		
+
+	 *******************************************************/
+string *
+get_command_line(bfd *abfd, 
+    	    	 string in_path, 
+		 string out_path, 
+		 int *arg_count)
+{
+    static string default_compilation_flags[] = DEFAULT_COMPILATION_FLAGS;
+    int i;
+    int argc = 0;
+    string *old_argv;
+    string *new_argv;
+    Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
+    asection *p_asec;
+
+    for (i = 1; i < ehdr->e_shnum; i++) {
+    	Elf_Internal_Shdr *p_shdr = elf_elfsections (abfd)[i];
+
+	if (p_shdr->sh_info == WT_COMP_FLAGS) {
+	    char *base_addr;
+	    int j;
+	    ELF_WORD *args;
+
+	    if (p_shdr->sh_size <= 1)
+		continue;
+
+	    base_addr = (char *) p_shdr->contents;
+	    argc = (int)(*((ELF_WORD *) base_addr));
+
+	    args = (ELF_WORD *) (base_addr + sizeof(ELF_WORD));
+	    old_argv = (string *) ALLOCA (sizeof(string) * argc);
+	    MALLOC_ASSERT (old_argv);
+	    
+	    for (j = 0; j < argc; j++) {
+		OBJ_ASSERT (args[j] < p_shdr->sh_size, abfd,
+			    "invalid WT_COMP_FLAGS WHIRL section");
+		old_argv[j] = base_addr + args[j];
+	    }
+
+	    break;
+	}
+    }
+
+    if (argc == 0) {
+	argc = DEFAULT_COMPILATION_ARGC;
+	old_argv = default_compilation_flags;
+    }
+
+    new_argv = (string *) MALLOC ((argc + 6) * sizeof(string));
+    MALLOC_ASSERT (new_argv);
+
+    for (i = 0; i < argc; i++)
+	new_argv[i] = old_argv[i];
+
+    new_argv[argc++] = "-64";
+
+    new_argv[argc++] = in_path;
+    new_argv[argc++] = "-o";
+    new_argv[argc++] = out_path;
+    new_argv[argc++] = "-c";
+    new_argv[argc] = 0;
+    
+    *arg_count = argc;
+
+    return new_argv;
+
+} /* get_command_line */
+
+
+	/*******************************************************
+		Function: extract_archive_member
+
+		Given an archive of WHIRL objects, extract the one
+		specified and put it into a separate file.
+
+	 *******************************************************/
+static int
+extract_archive_member (bfd *abfd, string path)
+{
+    int fd = -1;
+    int mode = 0666;
+    pointer addr = (pointer)-1;
+    struct areltdata *p_areltdata = (struct areltdata *)abfd->arelt_data;
+    struct ar_hdr *p_hdr = arch_hdr(abfd);
+
+    if ((fd = OPEN (path, O_RDWR|O_CREAT|O_TRUNC, mode)) != -1)
+	addr = (pointer) MMAP ( 0, 
+	    	    	    	p_hdr->ar_size,  
+				PROT_READ|PROT_WRITE,
+    	    	    	    	MAP_SHARED, 
+				fd, 
+				0);
+	
+    if (fd == -1 || addr == (pointer)-1 || FCHMOD (fd, mode) != 0 ) {
+    	perror("cannot create intermediate file");
+    	return -1;
+    }
+
+    CLOSE (fd);
+
+    MEMCPY (addr, bfd_tell(abfd), p_hdr->ar_size);
+
+    MUNMAP (addr, p_hdr->ar_size);
+
+    return 0;
+
+} /* extract_archive_member */
+
+	/*******************************************************
+		Function: make_link
+
+		
+
+	 *******************************************************/
+int
+make_link (const string dest, const string src)
+{
+    static string working_dir = 0;
+    int link_result;
+
+#if 0
+    LD_ASSERT (dest && src, thisfile,
+	       "NULL path name passed to symbolic_link()");
+#endif
+
+    /* try hard link first */
+
+    if (link (dest, src) == 0)
+	return 0;
+    
+    /* hard link fails, try symbolic link */
+
+    if (dest[0] == '/')
+	link_result = symlink (dest, src);
+    else {
+	string new_dest;
+	
+	if (working_dir == 0) {
+	    string tmp;
+	    working_dir = getcwd ((char *) NULL, PATH_MAX);
+	    if (working_dir == NULL) {
+		perror("getcwd(3)");
+		exit(1);
+    	    }
+	    tmp = working_dir;
+	    working_dir = concat_names (working_dir, "/");
+	    FREE (tmp);
+	}
+
+	new_dest = concat_names (working_dir, dest);
+	link_result = symlink (new_dest, src);
+	FREE (new_dest);
+    }
+
+    return link_result;
+    
+} /* make_link */
+
+	/*******************************************************
+		Function: ld_compile
+
+		
+
+	 *******************************************************/
+string
+ld_compile (bfd *abfd)
+{
+    string input_path;
+    string output_path;
+    int argc;
+    string *argv;
+    int child_pid;
+    int statptr;
+    string file_name = (string)abfd->filename;
+    
+    if (tmpdir == 0)
+	if (create_tmpdir (FALSE) != 0) {
+	    fprintf(stderr,"create_tmpdir() failed for %s\n",abfd->filename);
+    	    exit(1);
+	}
+
+    if ((input_path = create_unique_file (file_name, 'B')) == 0) {
+	    fprintf(stderr,"create_unique_file() failed for %s\n",abfd->filename);
+    	    exit(1);
+    }
+    
+    if (abfd->arelt_data) {
+	if (extract_archive_member (abfd, input_path) != 0) {
+	    fprintf(stderr,"extract_archive_member() failed for %s\n",abfd->filename);
+    	    exit(1);
+	}
+    } else {
+	UNLINK (input_path);
+	if (make_link (file_name, input_path) != 0) {
+	    fprintf(stderr,"make_link() failed for %s\n",abfd->filename);
+    	    exit(1);
+	}
+    }
+
+    if ((output_path = create_unique_file (file_name, 'o')) == 0)
+	if (create_tmpdir (FALSE) != 0) {
+	    fprintf(stderr,"create_unique_file() failed for %s\n",abfd->filename);
+    	    exit(1);
+    	}
+
+    add_to_tmp_file_list (output_path);
+    add_to_tmp_file_list (input_path);
+
+
+    argv = get_command_line (abfd, input_path, output_path, &argc);
+    
+
+    if (ld_ipa_opt[LD_IPA_VERBOSE].flag || ld_ipa_opt[LD_IPA_SHOW].flag)
+    	fprintf(stderr,"Compiling %s\n",abfd->filename);
+
+    child_pid = do_compile (argv);
+
+    (void) waitpid (child_pid, &statptr, 0);
+    if (statptr != 0 && WEXITSTATUS(statptr) != 0)
+    	{
+	fprintf(stderr,"Compile of %s failed!\n",abfd->filename);
+	exit(1);
+	}
+
+    active_pid = 0;
+    
+    FREE (argv);
+
+    UNLINK (input_path);
+    remove_from_tmp_file_list (input_path);
+    FREE (input_path);
+
+    return output_path; 
+
+} /* ld_compile */
+
+	/*******************************************************
+		Function: ld_slookup_mext
+
+		Return pointer to ?? struct.
+	 *******************************************************/
+void *
+ld_slookup_mext(char *name, boolean is_extern)
+{
+    bfd *abfd = p_current_bfd;
+    struct elf_link_hash_entry *p_hash = NULL;
+
+    if (!is_extern)
+    	p_hash = elf_link_hash_lookup (  elf_hash_table (&link_info), 
+    	    	    	    	    name, 
+				    false, 
+				    false, 
+				    false);
+    else
+    	p_hash = ((struct elf_link_hash_entry *)
+    	    bfd_wrapped_link_hash_lookup(   abfd, 
+    	    	    	    	    	    &link_info, 
+					    name, 
+					    false, 
+					    false, 
+					    false));
+
+    return p_hash;
+
+
+}
+
+	/*******************************************************
+		Function: ld_set_st_idx
+
+		This field cannot be used beyond
+		the pass1 phase.
+	 *******************************************************/
+void
+ld_set_st_idx (void *pext, int st_idx)
+{
+    struct elf_link_hash_entry *p_hash = (struct elf_link_hash_entry *)pext;
+
+    p_hash->ipa_indx = st_idx;
+}
+
+	/*******************************************************
+		Function: ld_get_st_idx
+
+		This field cannot be used beyond
+		the pass1 phase.
+	 *******************************************************/
+int
+ld_get_st_idx (void *pext)
+{
+    struct elf_link_hash_entry *p_hash = (struct elf_link_hash_entry *)pext;
+
+    return p_hash->ipa_indx;
+}
+
+
+	/*******************************************************
+		Function: ipa_set_ndx
+
+		This field cannot be used beyond
+		the pass1 phase.
+	 *******************************************************/
+int
+ipa_set_ndx (bfd *abfd)
+{
+    if (ipa_is_whirl(abfd))
+      	return WHIRL_ST_IDX_UNINITIALIZED;
+    else
+      	return WHIRL_ST_IDX_NOT_AVAILABLE;
+}
+
+	/*******************************************************
+		Function: ipa_set_def_bfd
+
+
+	 *******************************************************/
+void
+ipa_set_def_bfd(bfd *abfd, struct bfd_link_hash_entry *p_bfd_hash)
+{
+    if (is_ipa)
+    	p_bfd_hash->u.def.section = (asection *)abfd;
+}
+
+	/*******************************************************
+		Function: ld_resolved_to_obj
+
+		
+	 *******************************************************/
+boolean
+ld_resolved_to_obj (void *pext, void *pobj)
+{
+    struct elf_link_hash_entry *p_hash;
+    bfd *abfd = NULL;
+
+    if (pext)
+    	p_hash = (struct elf_link_hash_entry *)pext;
+    else
+    	p_hash = NULL;
+	
+    switch(p_hash->root.type) {
+
+    	case bfd_link_hash_common:
+	    abfd = p_hash->root.u.c.p->section->owner;
+	    break;
+
+	case bfd_link_hash_undefined:
+	case bfd_link_hash_undefweak:
+	    abfd = p_hash->root.u.undef.abfd;
+	    break;
+
+	case bfd_link_hash_defined:
+	case bfd_link_hash_defweak:
+	    abfd = (bfd *)p_hash->root.u.def.section;
+	    break;
+
+	case bfd_link_hash_new:
+	case bfd_link_hash_indirect:
+	case bfd_link_hash_warning:
+	default:
+	    break;
+	    
+    }
+
+    return (abfd == (struct _bfd *)pobj);
+}
+
+
+	/*******************************************************
+		Function: ld_get_section_base
+
+		Return the raw address of the given section
+		the pass1 phase.
+	 *******************************************************/
+char *
+ld_get_section_base (void *pobj, int sect_ndx)
+{
+    const bfd *abfd = (bfd *) pobj;
+    Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+    Elf_Internal_Shdr *p_shdr = i_shdrp[sect_ndx];
+
+    return (char *)abfd->usrdata+p_shdr->sh_offset;
+}
+
+	/*******************************************************
+		Function: ld_get_section_size
+
+		
+	 *******************************************************/
+unsigned long long
+ld_get_section_size(void *pobj, int sect_ndx)
+{
+    const bfd *abfd = (bfd *) pobj;
+    Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+
+    return ((unsigned long long)i_shdrp[sect_ndx]->sh_size);
+}
+
+	/*******************************************************
+		Function: ld_get_section_name
+
+		
+	 *******************************************************/
+char *
+ld_get_section_name(void *pobj, int sect_ndx)
+{
+    bfd *abfd = (bfd *) pobj;
+    Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+    Elf_Internal_Shdr *p_shdr = i_shdrp[sect_ndx];
+    char *tbl = bfd_elf_get_str_section(abfd, 
+    	    	    	    	    	elf_elfheader (abfd)->e_shstrndx);
+
+    return &tbl[p_shdr->sh_name];
+}
+
+	/*******************************************************
+		Function: ld_get_mmap_addr
+
+		
+	 *******************************************************/
+void *
+ld_get_mmap_addr(void *pobj)
+{
+    const bfd *abfd = (bfd *) pobj;
+
+    return (void *)abfd->usrdata;
+    
+}
+
+	/*******************************************************
+		Function: ld_set_section_data
+
+		
+	 *******************************************************/
+void 
+ld_set_section_data(void *pobj,int ndx)
+{
+    bfd *abfd = (bfd *) pobj;
+    Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+    Elf_Internal_Shdr *p_shdr = i_shdrp[ndx];
+    size_t size = p_shdr->sh_size;
+    char *buf;
+    
+    if (!size)
+    	return;
+	
+    buf = ((char *) bfd_malloc (size));
+    if (buf == NULL) {
+    	fprintf(stderr,"bfd_malloc failed in ld_set_section_data for %s\n",abfd->filename);
+    	exit(1);
+    }
+
+    if (!p_shdr->contents) {
+    	if (bfd_seek (	abfd, p_shdr->sh_offset, SEEK_SET) != 0) {
+    	    fprintf(stderr,"bfd_seek failed in ld_set_section_data for %s\n",abfd->filename);
+    	    exit(1);
+	}
+	if (bfd_read (	(PTR) buf, 1, size, abfd) != size) {
+    	    fprintf(stderr,"Bfd_read failed in ld_set_section_data for %s\n",abfd->filename);
+    	    exit(1);
+	}
+     }
+    
+    return;
+
+}
+
+	/*******************************************************
+		Function: ld_release_section_data
+
+		
+	 *******************************************************/
+void
+ld_release_section_data(void *pobj,int ndx)
+{
+    const bfd *abfd = (bfd *) pobj;
+    Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+    Elf_Internal_Shdr *p_shdr = i_shdrp[ndx];
+
+    if (p_shdr->contents) {
+    	free(p_shdr->contents);
+	p_shdr->contents = NULL;
+ }
+}
+
+	/*******************************************************
+		Function: Count_elf_external_gots
+
+		
+	 *******************************************************/
+int 
+Count_elf_external_gots (void)
+{
+    return(20);     /* This is until we figure out how to estimate for ia64 */
+}
+
+	/*******************************************************
+		Function: ld_set_cur_bfd
+
+
+	 *******************************************************/
+void 
+ld_set_cur_obj(bfd *abfd)
+{
+    p_current_bfd = (bfd *)abfd;
+}
+
+
+	/*******************************************************
+		Function: ld_get_cur_bfd
+
+
+	 *******************************************************/
+void *
+ld_get_cur_obj(void)
+{
+    return p_current_bfd;
+}
+
+	/*******************************************************
+		Function: ipa_is_whirl
+
+
+	 *******************************************************/
+#define ET_SGI_IR   (ET_LOPROC + 0)
+
+boolean
+ipa_is_whirl(bfd *abfd)
+{
+    Elf_Internal_Ehdr *i_ehdrp;	/* Elf file header, internal form */
+
+    i_ehdrp = elf_elfheader (abfd);
+
+    if (i_ehdrp->e_type == ET_SGI_IR) {
+    	    return(TRUE);
+    }
+
+    return(FALSE);
+}
+
+
+	/*******************************************************
+		Function: ipa_process_whirl
+
+		I need to read the WHIRL symbol table so the
+		internal mechanisms of IPA will have their 
+		data structures correctly filled out.
+		
+		Since IPA needs an mmapped view of the object
+		I'm trying to remap it here. It is not ready
+		for archives yet.
+		
+		I am overloading the usrdata field of the bfd
+		with the assumption that bfd is done with it.
+		
+	 *******************************************************/
+void
+ipa_process_whirl ( bfd *abfd) 
+{
+
+    off_t mapped_size;
+    abfd->usrdata = (PTR)(*p_ipa_open_input)((char *)abfd->filename, &mapped_size);
+    (*p_process_whirl64) ( 
+    	    	(void *)abfd, 
+    	    	elf_elfheader (abfd)->e_shnum, 
+		abfd->usrdata+elf_elfheader(abfd)->e_shoff,
+	        0, /* check_whirl_revision */
+		abfd->filename);
+}
+
+
+
+	/*******************************************************
+		Function: ipa_set_syms
+
+		dlopen ipa.so and set entry points with
+		dlsym calls.
+
+	 *******************************************************/
+void
+ipa_set_syms(void)
+{
+
+    void *p_handle = NULL;
+    char *p_error = NULL;
+
+    p_handle = dlopen("ipa.so",RTLD_LAZY);
+    if (!p_handle) {
+    	fputs (dlerror(), stderr);
+    	exit(1);
+    }
+    
+    p_ipa_open_input = dlsym(p_handle,"ipa_open_input");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+    p_ipa_init_link_line = dlsym(p_handle,"ipa_init_link_line");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+    p_ipa_add_link_flag = dlsym(p_handle,"ipa_add_link_flag");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+    p_ipa_driver = dlsym(p_handle,"ipa_driver");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+    p_process_whirl64 = dlsym(p_handle,"process_whirl64");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+    p_ipa_insert_whirl_marker = dlsym(p_handle,"ipa_insert_whirl_marker");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+    p_Sync_symbol_attributes = dlsym(p_handle,"Sync_symbol_attributes");
+    if ((p_error = dlerror()) != NULL)  {
+    	fputs(p_error, stderr);
+    	exit(1);
+    }
+
+}
+
+	/*******************************************************
+		Function: ipa_symbol_sync
+
+		
+
+	 *******************************************************/
+static boolean
+ipa_symbol_sync(struct bfd_link_hash_entry *p_bfd_link_hash, PTR info)
+{
+    const char *name;
+    boolean is_undef = FALSE;
+    struct elf_link_hash_entry *p_elf_link_hash ;
+    unsigned int result = 0;
+    boolean is_weak = FALSE;
+
+    name = p_bfd_link_hash->root.string;
+
+    if (!name)
+    	return(TRUE);
+
+
+    switch (p_bfd_link_hash->type) {
+    	case bfd_link_hash_undefined:
+	    is_undef = TRUE;
+	    break;
+	case bfd_link_hash_undefweak:
+	    is_undef = TRUE;
+	    is_weak = TRUE;
+	    break;
+	case bfd_link_hash_defined:
+	    is_undef = FALSE;
+	    break;
+	case bfd_link_hash_defweak:
+	    is_undef = FALSE;
+	    is_weak = TRUE;
+	    break;
+	case bfd_link_hash_common:
+	    is_undef = FALSE;
+	    result |= OBJ_COMMON;
+	    break;
+	default:
+	    return(TRUE);
+	    break;
+    }
+    
+    p_elf_link_hash = (struct elf_link_hash_entry *)ld_slookup_mext(name,is_undef);
+
+    if (p_elf_link_hash->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) {
+	result |= DEF_IN_OBJ;
+    }
+    if (p_elf_link_hash->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) {
+	result |= USED_IN_OBJ;
+    }
+    if (p_elf_link_hash->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) {
+	result |= USED_IN_DSO;
+    }
+    if (p_elf_link_hash->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) {
+	result |= DEF_IN_DSO;
+    }
+    if (p_elf_link_hash->elf_link_hash_flags & ELF_LINK_HIDDEN) {
+    }
+    if (p_elf_link_hash->elf_link_hash_flags & ELF_LINK_HASH_ADDRESS_TAKEN) {
+	result |= ADDR_TAKEN_IN_OBJ;
+    }
+
+    if (p_elf_link_hash->ipa_indx != WHIRL_ST_IDX_UNINITIALIZED &&
+    	p_elf_link_hash->ipa_indx != WHIRL_ST_IDX_NOT_AVAILABLE) {
+
+    	(*p_Sync_symbol_attributes) (p_elf_link_hash->ipa_indx, 
+				     result,
+			    	     is_weak,
+				     p_elf_link_hash->other);
+	
+    }
+    
+    return(TRUE);
+}
+
+static void
+hash_dummy(struct bfd_link_hash_entry *p_bfd_link_hash, PTR info)
+{
+
+    if (p_bfd_link_hash->root.string) {
+    	printf("*** %s\n",p_bfd_link_hash->root.string);
+    }
+}
+
+	/*******************************************************
+		Function: cleanup_symtab_for_ipa
+
+		In -IPA mode, we pass the last bit of info in the
+		merged symbol table that is needed by ipa.so, and
+		then clean up the storage allcoated.
+		
+	 *******************************************************/
+void
+cleanup_symtab_for_ipa (void)
+{
+
+    /* first, synch. up the symbol attributes with IPA's WHIRL symtab */
+
+    bfd_link_hash_traverse (link_info.hash, ipa_symbol_sync, (PTR) NULL);
+
+#if 0
+    /* TODO */
+    /* collect autognum and other info and pass them to ipa */
+    if (threadlocalsyms)
+	mark_all_xlocal_not_gp_rel ();
+
+    /* finally release all unnecessary storage allocated in ld. */
+#endif
+    
+}  /* cleanup_symtab_for_ipa */
+
+
+
+	/*******************************************************
+		Function: 
+
+		
+
+	 *******************************************************/
+
+
+
+
+
+
--- /dev/null	Thu Feb 22 19:32:40 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/ipa_ld.h	Thu Feb 22 18:25:07 2001
@@ -0,0 +1,294 @@
+#ifndef __IPA_LD_H__
+#define __IPA_LD_H__
+
+#define BCOPY(src, dst, len) \
+    bcopy((const void *)(src), (void *)(dst), (int)(len))    	       
+
+#define FREE(ptr) \
+    free((void *) (ptr))
+
+#define MALLOC_ASSERT(addr) \
+    if (addr == 0) { perror("malloc failed: "); exit(1);}
+
+#define MALLOC(nbytes) \
+    malloc((size_t)(nbytes))
+
+#define REALLOC(ptr, size) \
+    realloc((void *)(ptr), (size_t)(size))
+
+#define UNLINK(path) \
+    unlink((const char *)(path))
+
+#define MKDIR(path, mode) \
+    mkdir((const char *)(path), (mode_t)(mode))
+
+#define RMDIR(path) \
+    rmdir((const char *)(path))	       
+
+#define OPEN(path, oflag, mode) \
+    open((char *)(path), (int)(oflag), (int)(mode))
+
+#define CLOSE(fid) \
+    close((int)(fid))
+
+#define READ(fildes, buf, nbyte) \
+    read((int) (fildes), (void *)(buf), (size_t) (nbyte))
+
+#define ALLOCA(size) \
+    alloca((unsigned int)(size))	       
+	       
+#define FCHMOD(fid, mode) \
+    fchmod((int)(fid), (mode_t)(mode))
+
+#define MMAP(addr, len, prot, flags, fd, off) \
+    mmap((void *)(addr), (int)(len), (int)(prot), (int)(flags), (int)(fd), \
+	 (off_t)(off))
+
+#define MUNMAP(addr, len) \
+    munmap((void *)(addr), (int)(len))
+
+#define MEMCPY(s1, s2, n) \
+    memcpy((void *)(s1), (void *)(s2), (size_t)(n))
+
+#define ELF_WORD int
+
+#define OBJ_ASSERT(EX, obj, str) \
+    if (!(EX)) {fprintf(stderr,"%s: %s\n", obj->filename, str); exit(1);}
+
+#define DEFAULT_TMP_LIST_SIZE 32
+#define DEFAULT_TMPDIR "./ldtmp"
+#define DEFAULT_COMPILATION_FLAGS { "cc", "-c", 0}
+#define DEFAULT_COMPILATION_ARGC 2  /* number of arguments in */
+#define WT_COMP_FLAGS   0x3         /* compilation flags for this object */
+
+#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data))
+#define arch_hdr(_bfd) ((struct ar_hdr *)arch_eltdata(_bfd)->arch_header)
+
+#define FALSE 0
+#define TRUE 1
+
+typedef void *pointer;
+typedef char *string;
+
+/* These are taken from ipc_sumtab_merge.h in the ipa tree. */
+
+enum AUX_ST_FLAG
+{
+    // attributes from an Elf symbols
+
+    USED_IN_OBJ		= 0x00000001,	// referenced in an Elf object
+    USED_IN_DSO		= 0x00000002,	// referenced in a DSO
+    DEF_IN_OBJ		= 0x00000004,	// defined in an Elf object
+    DEF_IN_DSO		= 0x00000008,	// defined in a DSO
+    OBJ_COMMON		= 0x00000010,	// defined in OBJ/DSO as common
+    ADDR_TAKEN_IN_OBJ	= 0x00000020,	// address taken by Elf object or dso
+	// Update Print_AUX_ST_flags when adding new attribute
+
+    OBJ_ATTR_MASK	= 0x0000003f,	// mask for the above bits
+
+    // attributes from an ST
+    
+    COMMON_USED_IN_IO   = 0x00000040,	// common block passed to IO routines
+    IGNORE_REFCOUNTS	= 0x00000080	// ignore the mod/ref counts even
+					// when they hit zero
+};
+
+
+
+/*
+ * These are for passing option information from the
+ * static linker to ipa without involving the linkers
+ * internal option table. Any enumerated types defined
+ * here can be added to,  but not altered in any other
+ * way. This allows the linker to change without affecting
+ * ipa.
+ */
+
+typedef enum{
+    LD_IPA_SHARABLE, 
+    LD_IPA_DEMANGLE, 
+    LD_IPA_SHOW, 
+    LD_IPA_HIDES, 
+    LD_IPA_TARGOS, 
+    LD_IPA_VERBOSE, 
+    LD_IPA_KEEP_TEMPS, 
+    LD_IPA_ISA,
+    LD_IPA_XXXX, 
+    MAX_LD_IPA
+}ld_ipa_option_enum;
+
+typedef struct ld_ipa_option {
+    ld_ipa_option_enum opt_ndx;
+    unsigned    flag		: 4;    /*  */
+    unsigned     set		: 4;    /*  */
+} LD_IPA_OPTION;
+
+extern LD_IPA_OPTION ld_ipa_opt[MAX_LD_IPA];
+
+#define HS_DEFAULT 0
+#define HS_HIDES 1
+#define HS_EXPORTS 2
+#define HS_IGNORE 3
+
+    /*
+     * The following struct is used for storing lists
+     * of names. Most often these lists are gathered
+     * from the commandline, but not always.
+     */
+typedef struct {    /* all symbols specified in command line */
+    char **sym;     /* are collected here, one type per entry */
+    int    num;
+    int	   max;
+} OPTION_SYM;
+
+
+                 /* these are set to bit fields for */
+                 /* easy table initialization */
+#define          F_RELOCATABLE       1
+#define          F_NON_SHARED        2
+#define          F_CALL_SHARED       4
+#define          F_MAKE_SHARABLE     8
+#define          F_STATIC    (F_NON_SHARED | F_RELOCATABLE)
+#define          F_DYNAMIC   (~(F_STATIC))
+#define          F_MAIN      (F_NON_SHARED | F_CALL_SHARED)
+#define		 F_EXEC	     (~F_RELOCATABLE)
+#define          F_ALL       (F_STATIC | F_DYNAMIC)
+#define          F_CALL_SHARED_RELOC (F_RELOCATABLE | F_CALL_SHARED)
+
+typedef enum {
+	TOS_IA64_64,
+	TOS_IA64_32, 
+	TOS_MAX
+}targos_enum;
+
+extern string tos_string[TOS_MAX];
+extern string WB_flags;
+extern string Y_flags;
+extern string toolroot;
+extern string tmpdir;
+extern string outfilename;
+extern string WB_flags;
+extern string Y_flags;
+extern char * __Release_ID;
+
+extern void *(*p_ipa_open_input)(char *, off_t *);
+extern void (*p_ipa_init_link_line)(int, char **);
+extern void (*p_ipa_add_link_flag)(const char*);
+extern void (*p_ipa_driver)(int, char **);
+extern void (*p_process_whirl64)(void *, off_t, void *, int, const char *);
+extern void (*p_ipa_insert_whirl_marker)(void);
+
+/* Function declarations
+ */
+ 
+extern char *
+always_demangle(char *, char );
+
+
+extern void read_one_section(int , void *);
+
+extern void 
+merge_ext(void *, char *, int , void *) ;
+
+extern void 
+msg (int , int , ...);
+
+extern char *
+ipa_copy_of(char *);
+
+extern string
+concat_names(const string, const string);
+
+extern int
+do_compile (string *);
+
+extern void
+add_to_tmp_file_list (string);
+
+extern void
+cleanup_all_files (void);
+
+extern int
+create_tmpdir ( int);
+
+extern string
+create_unique_file (const string, char);
+
+extern string *
+get_command_line(bfd *, string , string , int *);
+
+extern int
+make_link (const string dest, const string src);
+
+extern string
+ld_compile (bfd *abfd);
+
+extern void *
+ld_slookup_mext(char *, boolean);
+
+extern void
+ld_set_st_idx (void *, int);
+
+extern int
+ld_get_st_idx (void *);
+
+extern int
+ipa_set_ndx (bfd *);
+
+extern boolean
+ld_resolved_to_obj (void *, void *);
+
+extern char *
+ld_get_section_base (void *, int );
+
+extern unsigned long long
+ld_get_section_size(void *, int );
+
+extern char *
+ld_get_section_name(void *, int );
+
+extern void *
+ld_get_mmap_addr(void *);
+
+extern void 
+ld_set_section_data(void *,int );
+
+extern void
+ld_release_section_data(void *,int );
+
+extern void 
+ld_set_cur_obj(bfd *);
+
+void *
+ld_get_cur_obj(void);
+
+extern boolean
+ipa_is_whirl(bfd *);
+
+extern void
+ipa_process_whirl ( bfd *);
+
+extern int 
+Count_elf_external_gots (void);
+
+extern void 
+ipa_set_syms (void);
+
+/* The following constant values are shared by both ld and ipa.  Each
+   symtab entry in ld's merged symbol table has an ST_IDX field pointing
+   back to the corresponding entry (if any) in the WHIRL merged symbol
+   table.  When a new entry is added to ld's merged symbol table, if the
+   symbol comes from an Elf object, we set the ST_IDX field to
+   WHIRL_ST_IDX_NOT_AVAILABLE because there is no corresponding ST entry in
+   the WHIRL merged symbol table. If the symbol comes from a WHIRL object,
+   we set the ST_IDX field to WHIRL_ST_IDX_UNINITIALIZED, which means that
+   there will be a corresponding entry in the WHIRL merged symtab but we
+   don't know the value yet.
+ */
+
+#define WHIRL_ST_IDX_UNINITIALIZED (0)
+#define WHIRL_ST_IDX_NOT_AVAILABLE (-1)
+
+
+
+#endif /* __IPA_LD_H__ */
--- /dev/null	Thu Feb 22 19:32:40 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/ipa_cmdline.c	Thu Feb 22 18:25:07 2001
@@ -0,0 +1,687 @@
+#if defined(__GNUC__)
+#include <stdio.h>		/* for sys_errlist */
+#endif
+#include <stdlib.h>		/* for getenv(3) */
+#include <unistd.h>		/* for unlink(2), rmdir(2), etc. */
+#include <libgen.h>		/* for basename(3) */
+#include <sys/stat.h>		/* for chmod(2) */
+#include <sys/mman.h>		/* for mmap(2) */
+#include <fcntl.h>		/* for open(2) */
+#include <sys/dir.h>		/* for opendir(2), readdir, closedir */
+#include <sys/wait.h>		/* for waitpid(2) */
+#include <alloca.h>		/* for alloca(3) */
+#include <signal.h>		/* for kill(2) */
+#include <limits.h>		/* for PATH_MAX */
+#include <errno.h>
+#include <string.h>
+
+#include "aout/ar.h"
+
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+
+#include "ipa_ld.h"
+#include "ipa_cmdline.h"
+
+int arg_count;			    /* argument count */
+char **arg_vector;		    /* argument vector */
+char **environ_vars;		    /* list of environment variables */
+    	    	    	    	    /* used by ipa to invoke recompilation */
+
+unsigned int max_gpa_size = 0x100000; /* gp area size, needs to more accurate */
+unsigned int used_gp_area;
+
+int ipa_argc = 0;
+char ** ipa_argv = NULL;
+
+static int orig_iargc_size = 10;
+static char char_opt[] = {'a','A','b','c','e','f','F','G','h','l','L','m','o','O','R','T','u','y','Y','z','0'};
+
+extern string outfilename;
+extern void ipa_insert_whirl_obj_marker(void);
+
+/* 
+    I took the following out of /usr/include/elf.h because
+    for some reason bfd doesn't want to use it and it was
+    too complicated to use the bfd model at this time.
+    
+    This is stupid, I know.
+    
+*/
+
+/* Standard ELF types.  */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef	int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef	int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef	int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef	int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type of symbol indices.  */
+typedef uint32_t Elf32_Symndx;
+typedef uint64_t Elf64_Symndx;
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#ifndef EI_NIDENT
+#define EI_NIDENT (16)
+#endif
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf32_Half	e_type;			/* Object file type */
+  Elf32_Half	e_machine;		/* Architecture */
+  Elf32_Word	e_version;		/* Object file version */
+  Elf32_Addr	e_entry;		/* Entry point virtual address */
+  Elf32_Off	e_phoff;		/* Program header table file offset */
+  Elf32_Off	e_shoff;		/* Section header table file offset */
+  Elf32_Word	e_flags;		/* Processor-specific flags */
+  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf32_Half	e_phentsize;		/* Program header table entry size */
+  Elf32_Half	e_phnum;		/* Program header table entry count */
+  Elf32_Half	e_shentsize;		/* Section header table entry size */
+  Elf32_Half	e_shnum;		/* Section header table entry count */
+  Elf32_Half	e_shstrndx;		/* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf64_Half	e_type;			/* Object file type */
+  Elf64_Half	e_machine;		/* Architecture */
+  Elf64_Word	e_version;		/* Object file version */
+  Elf64_Addr	e_entry;		/* Entry point virtual address */
+  Elf64_Off	e_phoff;		/* Program header table file offset */
+  Elf64_Off	e_shoff;		/* Section header table file offset */
+  Elf64_Word	e_flags;		/* Processor-specific flags */
+  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf64_Half	e_phentsize;		/* Program header table entry size */
+  Elf64_Half	e_phnum;		/* Program header table entry count */
+  Elf64_Half	e_shentsize;		/* Section header table entry size */
+  Elf64_Half	e_shnum;		/* Section header table entry count */
+  Elf64_Half	e_shstrndx;		/* Section header string table index */
+} Elf64_Ehdr;
+
+	/*******************************************************
+		Function: ipa_opt
+
+
+
+	 *******************************************************/
+static int
+ipa_opt (char **argv )
+{
+    if (ipa_argc == 0) {
+	ipa_argv = (string *) MALLOC (orig_iargc_size * sizeof (string));
+	MALLOC_ASSERT (ipa_argv);
+    }
+    else if (ipa_argc >= orig_iargc_size) {
+	orig_iargc_size *=2;
+	ipa_argv = (string *) REALLOC (ipa_argv, (orig_iargc_size * sizeof(string)));
+	MALLOC_ASSERT (ipa_argv);
+    }
+
+    ipa_argv[ipa_argc++] = ipa_copy_of(argv[0]);
+
+    return 1;
+} /* ipa_opt */
+
+/* ====================================================================
+ *
+ * add_WB_opt
+ *
+ * We have an option -WB,... to be passed to the back end via ipacom.
+ * If WB_flags is NULL, set it to this option with "-WB," stripped.
+ * Otherwise append this option with "-WB" stripped, i.e. retaining the
+ * comma separator.
+ *
+ * ====================================================================
+ */
+
+static void
+add_WB_opt (char **argv)
+{
+    char *p = *argv;
+
+    if ( WB_flags == NULL ) {
+    	WB_flags = concat_names("-Wb,",&p[3]);
+    } else {
+    	char *flg = concat_names(WB_flags,&p[3] ); /* include the comma */
+    	FREE(WB_flags);
+    	WB_flags = flg;
+  }
+
+  return;
+}
+
+
+/* ====================================================================
+ *
+ * add_Y_opt
+ *
+ * We have an option -Y... to be passed to the back end via ipacom.
+ * If Y_flags is NULL, set it to this option.  Otherwise append this
+ * option with a space delimiter.
+ *
+ * ====================================================================
+ */
+
+static void
+add_Y_opt (char **argv)
+{
+    char *p = *argv;
+
+    if ( Y_flags == NULL ) {
+    	Y_flags = ipa_copy_of(p);
+    } else {
+    	char *flg;
+	
+	flg = concat_names(Y_flags," ");
+	FREE (Y_flags);
+	Y_flags = flg;
+	
+	flg = concat_names(Y_flags,p);
+	FREE (Y_flags);
+	Y_flags = flg;
+    }
+
+    return;
+}
+
+	/*******************************************************
+		Function: check_for_whirl
+
+		Check to see if this is an ELF file and then
+		if it is a WHIRL object.
+		
+		I need to expand this to check for archives.
+
+	 *******************************************************/
+#define ET_SGI_IR   (ET_LOPROC + 0)
+static boolean
+check_for_whirl(char *name)
+{
+    int fd = -1;
+    char *raw_bits = NULL;
+    int size,bufsize;
+    Elf32_Ehdr *p_ehdr = NULL;
+    struct stat statb;
+    int test;
+    
+    fd = OPEN(name, O_RDONLY, 0755);
+    if (fd < 0)
+	return FALSE;
+
+    if ((test = fstat(fd, &statb) != 0)) {
+    	CLOSE(fd);
+	return FALSE;
+    }
+
+    if (statb.st_size < sizeof(Elf64_Ehdr)) {
+    	CLOSE(fd);
+    	return FALSE;
+    }
+    
+    bufsize = sizeof(Elf64_Ehdr);
+    
+    raw_bits = (char *)MALLOC(bufsize*4);
+    MALLOC_ASSERT(raw_bits);
+
+    size = READ(fd, raw_bits, bufsize);
+#if 0
+    if (size != statb.st_size) {
+    	CLOSE(fd);
+    	FREE(raw_bits);
+    	return FALSE;
+    }
+#endif
+    
+		/*
+		 * Check that the file is an elf executable.
+		 */
+    p_ehdr = (Elf32_Ehdr *)raw_bits;
+    if (p_ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+	p_ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+	p_ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+	p_ehdr->e_ident[EI_MAG3] != ELFMAG3) {
+	    CLOSE(fd);
+	    FREE(raw_bits);
+	    return(FALSE);
+    }
+
+    if(p_ehdr->e_ident[EI_CLASS] == ELFCLASS32){
+    	Elf32_Ehdr *p32_ehdr = (Elf32_Ehdr *)raw_bits;
+	if (p32_ehdr->e_type == ET_SGI_IR) {
+	    CLOSE(fd);
+	    FREE(raw_bits);
+	    return TRUE;
+	}
+    }
+    else {
+	Elf64_Ehdr *p64_ehdr = (Elf64_Ehdr *)raw_bits;
+	if (p64_ehdr->e_type == ET_SGI_IR) {
+	    CLOSE(fd);
+	    FREE(raw_bits);
+	    return TRUE;
+	}
+     }
+
+    CLOSE(fd);
+    FREE(raw_bits);
+    return FALSE;
+    
+ }
+
+	/*******************************************************
+		Function: needs_argument.
+
+		Determine if this option needs an argument.
+		This routine will need to change as the commandline
+		arguments change or are augmented.
+
+	 *******************************************************/
+static boolean
+needs_argument(char *string, boolean is_double_dash)
+{
+
+    int len = strlen(string);
+
+    if (is_double_dash) {
+    	if ((strcmp (string, "architecture") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "format") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "mri-script") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "entry") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "auxiliary") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "filter") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "gpsize") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "library") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "library-path") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "output") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "just-symbols") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "script") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "undefined") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "trace-symbol") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "assert") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "defsym") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "dynamic-linker") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "Map") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "oformat") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "retain-symbols-file") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "rpath-link") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "split-by-reloc") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "task-link") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "verbose") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "version-script") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "version-exports-section") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "wrap") == 0)) {
+    	    return TRUE;
+    	}
+    }
+    else {
+    	if (len == 1) {
+	    int i;
+	    int size = strlen(char_opt);
+	    for (i=0;i<size;i++) {
+	    	if (char_opt[i] == *string)
+		    return TRUE;
+	    }
+	    return FALSE;
+	}
+    	if ((strcmp (string, "soname") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "rpath") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "Tbss") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "Tdata") == 0)) {
+    	    return TRUE;
+    	}
+    	if ((strcmp (string, "Ttext") == 0)) {
+    	    return TRUE;
+    	}
+    }
+    
+    return FALSE;
+}
+
+
+	/*******************************************************
+		Function: blank_arg.
+
+		Blank out the given argument so other parts
+		of the program that read the argv don't get
+		confused.
+
+	 *******************************************************/
+static void
+blank_arg(char **argv, int ndx)
+{
+
+    int j,len;
+
+    len = strlen(argv[ndx]);
+
+#if 1
+    if (len >=3)
+    	strcpy(argv[ndx],"-g"); /* ignored by the linker */
+    else {
+    	for(j=0;j<len;j++)
+    	    argv[ndx][j] = ' ';
+    }
+#else
+    argv[ndx][0] = '\0';
+#endif
+
+}
+
+	/*******************************************************
+		Function: opt_search_command_line.
+
+		Read through the command line looking at each
+		option. If a linker commandfile is encountered
+		it will be open'ed an it's file descriptor pushed
+		on a stack of file descriptors. The contents of
+		the file will be read like options on the command
+		line.
+
+		This routine will eventually rebuild the input
+		command order to get rid of silly command order
+		errors.
+
+	 *******************************************************/
+boolean
+ipa_search_command_line(int argc,
+			char **argv,
+			char **envp
+			)
+{
+    int i;
+
+    	/*
+    	 * First check if ipa is on.
+    	 */
+    for (i=1;i<argc;i++) {
+    	char *string = argv[i];
+    	if (*string == '-') {
+	    if ((strncmp(string,"-IPA",4)) == 0) {
+	    	is_ipa = TRUE;
+		break;
+	    }
+	    else if ((strncmp(string,"--IPA",5)) == 0) {
+	    	is_ipa = TRUE;
+		break;
+	    }
+	    else if ((strcmp(string,"--ipa")) == 0) {
+	    	is_ipa = TRUE;
+		break;
+	    }
+ 	    else if ((strcmp(string,"-ipa")) == 0) {
+	    	is_ipa = TRUE;
+		break;
+	    }
+    	}
+    }
+
+    if (!is_ipa)
+    	return(FALSE);
+
+    arg_count = argc;
+    arg_vector = argv;
+    environ_vars = envp;
+
+    	/*
+	 *  The ipa.so needs to be opened and entry
+	 *  points need to be found with dlsym.
+	 */
+    ipa_set_syms();
+
+    	/*
+    	 * We need to build up the commandline options
+    	 * that will be passed to the linker/compiler during
+         * the second pass
+    	 */
+    (*p_ipa_init_link_line) (0, NULL);
+
+    for (i=1;i<argc;i++) {
+    	char *string = argv[i];
+    	if (*string == '-' && string[1] == '-') {
+	    if ((strncmp (&string[2], "ipa", strlen ("ipa")) == 0)) {
+	    	continue;
+	    }
+	    if ((strncmp (&string[2], "IPA:", strlen ("IPA:")) == 0)) {
+    	    	char *p = &argv[i][1];
+	    	ipa_opt(&p);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strcmp (&string[2], "keep") == 0)) {
+    	    	ld_ipa_opt[LD_IPA_KEEP_TEMPS].flag = TRUE;
+		    /* Blank out argument */
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    else if ((needs_argument(&string[2],TRUE) == TRUE)) {
+	    	(*p_ipa_add_link_flag) (argv[i++]);
+		(*p_ipa_add_link_flag) (argv[i]);
+		continue;
+	    }
+	}   /* if "--" */
+	else if (*string == '-') {
+	    if ((strncmp(string,"-WB,",4)) == 0) {
+	    	add_WB_opt (&argv[i]);
+
+		    /* Blank out argument */
+		blank_arg(argv,i);
+		continue;
+	    }
+	    else if ((strncmp(string,"-Y",2)) == 0) {
+	    	add_Y_opt (&argv[i]);
+
+		    /* Blank out argument */
+		blank_arg(argv,i);
+		continue;
+	    }
+	    if ((strncmp (string, "-ipacom", strlen ("-ipacom")) == 0)) {
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-ipa", strlen ("-ipa")) == 0)) {
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-DEFAULT:", strlen ("-DEFAULT:")) == 0)) {
+	    	ipa_opt(&argv[i]);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-IPA:", strlen ("-IPA:")) == 0)) {
+	    	ipa_opt(&argv[i]);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-INLINE:", strlen ("-INLINE:")) == 0)) {
+	    	ipa_opt(&argv[i]);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-INTERNAL:", strlen ("-INTERNAL:")) == 0)) {
+	    	ipa_opt(&argv[i]);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-OPT:", strlen ("-OPT:")) == 0)) {
+	    	ipa_opt(&argv[i]);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    if ((strncmp (string, "-TENV:", strlen ("-TENV:")) == 0)) {
+	    	ipa_opt(&argv[i]);
+		blank_arg(argv,i);
+	    	continue;
+	    }
+	    else if ((strcmp(string,"-keep")) == 0) {
+    	    	ld_ipa_opt[LD_IPA_KEEP_TEMPS].flag = TRUE;
+
+		    /* Blank out argument */
+		blank_arg(argv,i);
+		continue;
+	    }
+	    else if ((strcmp(string,"-show")) == 0) {
+    	    	ld_ipa_opt[LD_IPA_SHOW].flag = TRUE;
+
+		    /* Blank out argument */
+		blank_arg(argv,i);
+		continue;
+	    }
+	    else if ((strcmp(string,"-demangle")) == 0) {
+    	    	ld_ipa_opt[LD_IPA_DEMANGLE].flag = TRUE;
+
+		    /* Blank out argument */
+		blank_arg(argv,i);
+		continue;
+	    }
+	    else if ((strcmp(string,"-o")) == 0) {
+    	    	outfilename = MALLOC(strlen(argv[i+1])+3);
+    	    	MALLOC_ASSERT(outfilename);
+		strcpy(outfilename,"./");
+		strcat(outfilename,argv[i+1]);
+	    	(*p_ipa_add_link_flag) (argv[i++]);
+		(*p_ipa_add_link_flag) (argv[i]);
+		continue;
+	    }
+	    else if ((strcmp(string,"-v")) == 0) {
+    	    	ld_ipa_opt[LD_IPA_VERBOSE].flag = TRUE;
+	    }
+	    	    /* Check for sgi debug tracing */
+	    else if (string[1] == 't' && strlen(string) > 3) {
+	    	ipa_opt(&argv[i]);
+
+		    /* Blank out argument */
+		blank_arg(argv,i);
+		continue;
+	    }
+	    else if (needs_argument(&string[1],FALSE)) {
+	    	(*p_ipa_add_link_flag) (argv[i++]);
+		(*p_ipa_add_link_flag) (argv[i]);
+		continue;
+	    }
+	}
+	/* This splits the post ipa commandline arguments */
+	else if (check_for_whirl(argv[i])){
+	    (*p_ipa_insert_whirl_marker)();
+	    continue;
+	}
+
+    	(*p_ipa_add_link_flag) (argv[i]);
+
+    }	    /* for */
+
+    return(TRUE);
+}
+
+	/*******************************************************
+		Function: 
+
+		
+
+	 *******************************************************/
+
+	/*******************************************************
+		Function: 
+
+		
+
+	 *******************************************************/
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Feb 22 19:32:40 2001
+++ /usr/people/jkingdon/WORKAREA/osprey1.0/cygnus_20000828/bfd/ipa_cmdline.h	Thu Feb 22 18:25:07 2001
@@ -0,0 +1,20 @@
+#ifndef __IPA_CMDLINE_H__
+#define __IPA_CMDLINE_H__
+
+
+extern int arg_count;			    /* argument count */
+extern char **arg_vector;		    /* argument vector */
+extern char **environ_vars;		    /* list of environment variables */
+
+extern int ipa_argc;
+extern char **ipa_argv;
+extern unsigned int max_gpa_size;
+extern boolean is_ipa;
+extern unsigned int used_gp_area;
+
+extern boolean
+ipa_search_command_line(int, char **, char **);
+
+
+
+#endif /* __IPA_CMDLINE_H__ */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]