Back to index

cell-binutils  2.17cvs20070401
nlmconv.c
Go to the documentation of this file.
00001 /* nlmconv.c -- NLM conversion program
00002    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
00003    2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
00004 
00005    This file is part of GNU Binutils.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 /* Written by Ian Lance Taylor <ian@cygnus.com>.
00022 
00023    This program can be used to convert any appropriate object file
00024    into a NetWare Loadable Module (an NLM).  It will accept a linker
00025    specification file which is identical to that accepted by the
00026    NetWare linker, NLMLINK.  */
00027 
00028 /* AIX requires this to be the first thing in the file.  */
00029 #ifndef __GNUC__
00030 # ifdef _AIX
00031  #pragma alloca
00032 #endif
00033 #endif
00034 
00035 #include "bfd.h"
00036 #include "libiberty.h"
00037 #include "bucomm.h"
00038 #include "safe-ctype.h"
00039 
00040 #include "ansidecl.h"
00041 #include <time.h>
00042 #include <sys/stat.h>
00043 #include <sys/file.h>
00044 #include <assert.h>
00045 #include "getopt.h"
00046 
00047 /* Internal BFD NLM header.  */
00048 #include "libnlm.h"
00049 #include "nlmconv.h"
00050 
00051 #ifdef NLMCONV_ALPHA
00052 #include "coff/sym.h"
00053 #include "coff/ecoff.h"
00054 #endif
00055 
00056 /* If strerror is just a macro, we want to use the one from libiberty
00057    since it will handle undefined values.  */
00058 #undef strerror
00059 extern char *strerror (int);
00060 
00061 #ifndef SEEK_SET
00062 #define SEEK_SET 0
00063 #endif
00064 
00065 #ifndef R_OK
00066 #define R_OK 4
00067 #define W_OK 2
00068 #define X_OK 1
00069 #endif
00070 
00071 /* Global variables.  */
00072 
00073 /* The name used to invoke the program.  */
00074 char *program_name;
00075 
00076 /* Local variables.  */
00077 
00078 /* Whether to print out debugging information (currently just controls
00079    whether it prints the linker command if there is one).  */
00080 static int debug;
00081 
00082 /* The symbol table.  */
00083 static asymbol **symbols;
00084 
00085 /* A section we create in the output file to hold pointers to where
00086    the sections of the input file end up.  We will put a pointer to
00087    this section in the NLM header.  These is an entry for each input
00088    section.  The format is
00089        null terminated section name
00090        zeroes to adjust to 4 byte boundary
00091        4 byte section data file pointer
00092        4 byte section size
00093    We don't need a version number.  The way we find this information
00094    is by finding a stamp in the NLM header information.  If we need to
00095    change the format of this information, we can simply change the
00096    stamp.  */
00097 static asection *secsec;
00098 
00099 /* A temporary file name to be unlinked on exit.  Actually, for most
00100    errors, we leave it around.  It's not clear whether that is helpful
00101    or not.  */
00102 static char *unlink_on_exit;
00103 
00104 /* The list of long options.  */
00105 static struct option long_options[] =
00106 {
00107   { "debug", no_argument, 0, 'd' },
00108   { "header-file", required_argument, 0, 'T' },
00109   { "help", no_argument, 0, 'h' },
00110   { "input-target", required_argument, 0, 'I' },
00111   { "input-format", required_argument, 0, 'I' }, /* Obsolete */
00112   { "linker", required_argument, 0, 'l' },
00113   { "output-target", required_argument, 0, 'O' },
00114   { "output-format", required_argument, 0, 'O' }, /* Obsolete */
00115   { "version", no_argument, 0, 'V' },
00116   { NULL, no_argument, 0, 0 }
00117 };
00118 
00119 /* Local routines.  */
00120 
00121 int main (int, char **);
00122 
00123 static void show_usage (FILE *, int);
00124 static const char *select_output_format
00125   (enum bfd_architecture, unsigned long, bfd_boolean);
00126 static void setup_sections (bfd *, asection *, void *);
00127 static void copy_sections (bfd *, asection *, void *);
00128 static void mangle_relocs
00129   (bfd *, asection *, arelent ***, long *, char *, bfd_size_type);
00130 static void default_mangle_relocs
00131   (bfd *, asection *, arelent ***, long *, char *, bfd_size_type);
00132 static char *link_inputs (struct string_list *, char *, char *);
00133 
00134 #ifdef NLMCONV_I386
00135 static void i386_mangle_relocs (bfd *, asection *, arelent ***, long *, char *, bfd_size_type);
00136 #endif
00137 
00138 #ifdef NLMCONV_ALPHA
00139 static void alpha_mangle_relocs (bfd *, asection *, arelent ***, long *, char *, bfd_size_type);
00140 #endif
00141 
00142 #ifdef NLMCONV_POWERPC
00143 static void powerpc_build_stubs (bfd *, bfd *, asymbol ***, long *);
00144 static void powerpc_resolve_stubs (bfd *, bfd *);
00145 static void powerpc_mangle_relocs (bfd *, asection *, arelent ***, long *, char *, bfd_size_type);
00146 #endif
00147 
00148 /* The main routine.  */
00149 
00150 int
00151 main (int argc, char **argv)
00152 {
00153   int opt;
00154   char *input_file = NULL;
00155   const char *input_format = NULL;
00156   const char *output_format = NULL;
00157   const char *header_file = NULL;
00158   char *ld_arg = NULL;
00159   Nlm_Internal_Fixed_Header fixed_hdr_struct;
00160   Nlm_Internal_Variable_Header var_hdr_struct;
00161   Nlm_Internal_Version_Header version_hdr_struct;
00162   Nlm_Internal_Copyright_Header copyright_hdr_struct;
00163   Nlm_Internal_Extended_Header extended_hdr_struct;
00164   bfd *inbfd;
00165   bfd *outbfd;
00166   asymbol **newsyms, **outsyms;
00167   long symcount, newsymalloc, newsymcount;
00168   long symsize;
00169   asection *text_sec, *bss_sec, *data_sec;
00170   bfd_vma vma;
00171   bfd_size_type align;
00172   asymbol *endsym;
00173   long i;
00174   char inlead, outlead;
00175   bfd_boolean gotstart, gotexit, gotcheck;
00176   struct stat st;
00177   FILE *custom_data = NULL;
00178   FILE *help_data = NULL;
00179   FILE *message_data = NULL;
00180   FILE *rpc_data = NULL;
00181   FILE *shared_data = NULL;
00182   size_t custom_size = 0;
00183   size_t help_size = 0;
00184   size_t message_size = 0;
00185   size_t module_size = 0;
00186   size_t rpc_size = 0;
00187   asection *custom_section = NULL;
00188   asection *help_section = NULL;
00189   asection *message_section = NULL;
00190   asection *module_section = NULL;
00191   asection *rpc_section = NULL;
00192   asection *shared_section = NULL;
00193   bfd *sharedbfd;
00194   size_t shared_offset = 0;
00195   size_t shared_size = 0;
00196   static Nlm_Internal_Fixed_Header sharedhdr;
00197   int len;
00198   char *modname;
00199   char **matching;
00200 
00201 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
00202   setlocale (LC_MESSAGES, "");
00203 #endif
00204 #if defined (HAVE_SETLOCALE)
00205   setlocale (LC_CTYPE, "");
00206 #endif
00207   bindtextdomain (PACKAGE, LOCALEDIR);
00208   textdomain (PACKAGE);
00209 
00210   program_name = argv[0];
00211   xmalloc_set_program_name (program_name);
00212 
00213   expandargv (&argc, &argv);
00214 
00215   bfd_init ();
00216   set_default_bfd_target ();
00217 
00218   while ((opt = getopt_long (argc, argv, "dHhI:l:O:T:Vv", long_options,
00219                           (int *) NULL))
00220         != EOF)
00221     {
00222       switch (opt)
00223        {
00224        case 'd':
00225          debug = 1;
00226          break;
00227        case 'H':
00228        case 'h':
00229          show_usage (stdout, 0);
00230          break;
00231        case 'I':
00232          input_format = optarg;
00233          break;
00234        case 'l':
00235          ld_arg = optarg;
00236          break;
00237        case 'O':
00238          output_format = optarg;
00239          break;
00240        case 'T':
00241          header_file = optarg;
00242          break;
00243        case 'v':
00244        case 'V':
00245          print_version ("nlmconv");
00246          break;
00247        case 0:
00248          break;
00249        default:
00250          show_usage (stderr, 1);
00251          break;
00252        }
00253     }
00254 
00255   /* The input and output files may be named on the command line.  */
00256   output_file = NULL;
00257   if (optind < argc)
00258     {
00259       input_file = argv[optind];
00260       ++optind;
00261       if (optind < argc)
00262        {
00263          output_file = argv[optind];
00264          ++optind;
00265          if (optind < argc)
00266            show_usage (stderr, 1);
00267          if (strcmp (input_file, output_file) == 0)
00268            {
00269              fatal (_("input and output files must be different"));
00270            }
00271        }
00272     }
00273 
00274   /* Initialize the header information to default values.  */
00275   fixed_hdr = &fixed_hdr_struct;
00276   memset ((void *) &fixed_hdr_struct, 0, sizeof fixed_hdr_struct);
00277   var_hdr = &var_hdr_struct;
00278   memset ((void *) &var_hdr_struct, 0, sizeof var_hdr_struct);
00279   version_hdr = &version_hdr_struct;
00280   memset ((void *) &version_hdr_struct, 0, sizeof version_hdr_struct);
00281   copyright_hdr = &copyright_hdr_struct;
00282   memset ((void *) &copyright_hdr_struct, 0, sizeof copyright_hdr_struct);
00283   extended_hdr = &extended_hdr_struct;
00284   memset ((void *) &extended_hdr_struct, 0, sizeof extended_hdr_struct);
00285   check_procedure = NULL;
00286   custom_file = NULL;
00287   debug_info = FALSE;
00288   exit_procedure = "_Stop";
00289   export_symbols = NULL;
00290   map_file = NULL;
00291   full_map = FALSE;
00292   help_file = NULL;
00293   import_symbols = NULL;
00294   message_file = NULL;
00295   modules = NULL;
00296   sharelib_file = NULL;
00297   start_procedure = "_Prelude";
00298   verbose = FALSE;
00299   rpc_file = NULL;
00300 
00301   parse_errors = 0;
00302 
00303   /* Parse the header file (if there is one).  */
00304   if (header_file != NULL)
00305     {
00306       if (! nlmlex_file (header_file)
00307          || yyparse () != 0
00308          || parse_errors != 0)
00309        exit (1);
00310     }
00311 
00312   if (input_files != NULL)
00313     {
00314       if (input_file != NULL)
00315        {
00316          fatal (_("input file named both on command line and with INPUT"));
00317        }
00318       if (input_files->next == NULL)
00319        input_file = input_files->string;
00320       else
00321        input_file = link_inputs (input_files, ld_arg, map_file);
00322     }
00323   else if (input_file == NULL)
00324     {
00325       non_fatal (_("no input file"));
00326       show_usage (stderr, 1);
00327     }
00328 
00329   inbfd = bfd_openr (input_file, input_format);
00330   if (inbfd == NULL)
00331     bfd_fatal (input_file);
00332 
00333   if (! bfd_check_format_matches (inbfd, bfd_object, &matching))
00334     {
00335       bfd_nonfatal (input_file);
00336       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
00337        {
00338          list_matching_formats (matching);
00339          free (matching);
00340        }
00341       exit (1);
00342     }
00343 
00344   if (output_format == NULL)
00345     output_format = select_output_format (bfd_get_arch (inbfd),
00346                                      bfd_get_mach (inbfd),
00347                                      bfd_big_endian (inbfd));
00348 
00349   assert (output_format != NULL);
00350 
00351   /* Use the output file named on the command line if it exists.
00352      Otherwise use the file named in the OUTPUT statement.  */
00353   if (output_file == NULL)
00354     {
00355       non_fatal (_("no name for output file"));
00356       show_usage (stderr, 1);
00357     }
00358 
00359   outbfd = bfd_openw (output_file, output_format);
00360   if (outbfd == NULL)
00361     bfd_fatal (output_file);
00362   if (! bfd_set_format (outbfd, bfd_object))
00363     bfd_fatal (output_file);
00364 
00365   assert (bfd_get_flavour (outbfd) == bfd_target_nlm_flavour);
00366 
00367   /* XXX: Should we accept the unknown bfd format here ?  */
00368   if (bfd_arch_get_compatible (inbfd, outbfd, TRUE) == NULL)
00369     non_fatal (_("warning: input and output formats are not compatible"));
00370 
00371   /* Move the values read from the command file into outbfd.  */
00372   *nlm_fixed_header (outbfd) = fixed_hdr_struct;
00373   *nlm_variable_header (outbfd) = var_hdr_struct;
00374   *nlm_version_header (outbfd) = version_hdr_struct;
00375   *nlm_copyright_header (outbfd) = copyright_hdr_struct;
00376   *nlm_extended_header (outbfd) = extended_hdr_struct;
00377 
00378   /* Start copying the input BFD to the output BFD.  */
00379   if (! bfd_set_file_flags (outbfd, bfd_get_file_flags (inbfd)))
00380     bfd_fatal (bfd_get_filename (outbfd));
00381 
00382   symsize = bfd_get_symtab_upper_bound (inbfd);
00383   if (symsize < 0)
00384     bfd_fatal (input_file);
00385   symbols = (asymbol **) xmalloc (symsize);
00386   symcount = bfd_canonicalize_symtab (inbfd, symbols);
00387   if (symcount < 0)
00388     bfd_fatal (input_file);
00389 
00390   /* Make sure we have a .bss section.  */
00391   bss_sec = bfd_get_section_by_name (outbfd, NLM_UNINITIALIZED_DATA_NAME);
00392   if (bss_sec == NULL)
00393     {
00394       bss_sec = bfd_make_section (outbfd, NLM_UNINITIALIZED_DATA_NAME);
00395       if (bss_sec == NULL
00396          || ! bfd_set_section_flags (outbfd, bss_sec, SEC_ALLOC)
00397          || ! bfd_set_section_alignment (outbfd, bss_sec, 1))
00398        bfd_fatal (_("make .bss section"));
00399     }
00400 
00401   /* We store the original section names in the .nlmsections section,
00402      so that programs which understand it can resurrect the original
00403      sections from the NLM.  We will put a pointer to .nlmsections in
00404      the NLM header area.  */
00405   secsec = bfd_make_section (outbfd, ".nlmsections");
00406   if (secsec == NULL)
00407     bfd_fatal (_("make .nlmsections section"));
00408   if (! bfd_set_section_flags (outbfd, secsec, SEC_HAS_CONTENTS))
00409     bfd_fatal (_("set .nlmsections flags"));
00410 
00411 #ifdef NLMCONV_POWERPC
00412   /* For PowerPC NetWare we need to build stubs for calls to undefined
00413      symbols.  Because each stub requires an entry in the TOC section
00414      which must be at the same location as other entries in the TOC
00415      section, we must do this before determining where the TOC section
00416      goes in setup_sections.  */
00417   if (bfd_get_arch (inbfd) == bfd_arch_powerpc)
00418     powerpc_build_stubs (inbfd, outbfd, &symbols, &symcount);
00419 #endif
00420 
00421   /* Set up the sections.  */
00422   bfd_map_over_sections (inbfd, setup_sections, (void *) outbfd);
00423 
00424   text_sec = bfd_get_section_by_name (outbfd, NLM_CODE_NAME);
00425 
00426   /* The .bss section immediately follows the .data section.  */
00427   data_sec = bfd_get_section_by_name (outbfd, NLM_INITIALIZED_DATA_NAME);
00428   if (data_sec != NULL)
00429     {
00430       bfd_size_type add;
00431 
00432       vma = bfd_get_section_size (data_sec);
00433       align = 1 << bss_sec->alignment_power;
00434       add = ((vma + align - 1) &~ (align - 1)) - vma;
00435       vma += add;
00436       if (! bfd_set_section_vma (outbfd, bss_sec, vma))
00437        bfd_fatal (_("set .bss vma"));
00438       if (add != 0)
00439        {
00440          bfd_size_type data_size;
00441 
00442          data_size = bfd_get_section_size (data_sec);
00443          if (! bfd_set_section_size (outbfd, data_sec, data_size + add))
00444            bfd_fatal (_("set .data size"));
00445        }
00446     }
00447 
00448   /* Adjust symbol information.  */
00449   inlead = bfd_get_symbol_leading_char (inbfd);
00450   outlead = bfd_get_symbol_leading_char (outbfd);
00451   gotstart = FALSE;
00452   gotexit = FALSE;
00453   gotcheck = FALSE;
00454   newsymalloc = 10;
00455   newsyms = (asymbol **) xmalloc (newsymalloc * sizeof (asymbol *));
00456   newsymcount = 0;
00457   endsym = NULL;
00458   for (i = 0; i < symcount; i++)
00459     {
00460       asymbol *sym;
00461 
00462       sym = symbols[i];
00463 
00464       /* Add or remove a leading underscore.  */
00465       if (inlead != outlead)
00466        {
00467          if (inlead != '\0')
00468            {
00469              if (bfd_asymbol_name (sym)[0] == inlead)
00470               {
00471                 if (outlead == '\0')
00472                   ++sym->name;
00473                 else
00474                   {
00475                     char *new;
00476 
00477                     new = xmalloc (strlen (bfd_asymbol_name (sym)) + 1);
00478                     new[0] = outlead;
00479                     strcpy (new + 1, bfd_asymbol_name (sym) + 1);
00480                     sym->name = new;
00481                   }
00482               }
00483            }
00484          else
00485            {
00486              char *new;
00487 
00488              new = xmalloc (strlen (bfd_asymbol_name (sym)) + 2);
00489              new[0] = outlead;
00490              strcpy (new + 1, bfd_asymbol_name (sym));
00491              sym->name = new;
00492            }
00493        }
00494 
00495       /* NLM's have an uninitialized data section, but they do not
00496         have a common section in the Unix sense.  Move all common
00497         symbols into the .bss section, and mark them as exported.  */
00498       if (bfd_is_com_section (bfd_get_section (sym)))
00499        {
00500          bfd_vma size = sym->value;
00501 
00502          sym->section = bss_sec;
00503          sym->value = bfd_get_section_size (bss_sec);
00504          size += sym->value;
00505          align = 1 << bss_sec->alignment_power;
00506          size = (size + align - 1) & ~(align - 1);
00507          bfd_set_section_size (outbfd, bss_sec, size);
00508          sym->flags |= BSF_EXPORT | BSF_GLOBAL;
00509        }
00510       else if (bfd_get_section (sym)->output_section != NULL)
00511        {
00512          /* Move the symbol into the output section.  */
00513          sym->value += bfd_get_section (sym)->output_offset;
00514          sym->section = bfd_get_section (sym)->output_section;
00515          /* This is no longer a section symbol.  */
00516          sym->flags &=~ BSF_SECTION_SYM;
00517        }
00518 
00519       /* Force _edata and _end to be defined.  This would normally be
00520         done by the linker, but the manipulation of the common
00521         symbols will confuse it.  */
00522       if ((sym->flags & BSF_DEBUGGING) == 0
00523          && bfd_asymbol_name (sym)[0] == '_'
00524          && bfd_is_und_section (bfd_get_section (sym)))
00525        {
00526          if (strcmp (bfd_asymbol_name (sym), "_edata") == 0)
00527            {
00528              sym->section = bss_sec;
00529              sym->value = 0;
00530            }
00531          if (strcmp (bfd_asymbol_name (sym), "_end") == 0)
00532            {
00533              sym->section = bss_sec;
00534              endsym = sym;
00535            }
00536 
00537 #ifdef NLMCONV_POWERPC
00538          /* For PowerPC NetWare, we define __GOT0.  This is the start
00539             of the .got section.  */
00540          if (bfd_get_arch (inbfd) == bfd_arch_powerpc
00541              && strcmp (bfd_asymbol_name (sym), "__GOT0") == 0)
00542            {
00543              asection *got_sec;
00544 
00545              got_sec = bfd_get_section_by_name (inbfd, ".got");
00546              assert (got_sec != (asection *) NULL);
00547              sym->value = got_sec->output_offset;
00548              sym->section = got_sec->output_section;
00549            }
00550 #endif
00551        }
00552 
00553       /* If this is a global symbol, check the export list.  */
00554       if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) != 0)
00555        {
00556          struct string_list *l;
00557          int found_simple;
00558 
00559          /* Unfortunately, a symbol can appear multiple times on the
00560             export list, with and without prefixes.  */
00561          found_simple = 0;
00562          for (l = export_symbols; l != NULL; l = l->next)
00563            {
00564              if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
00565               found_simple = 1;
00566              else
00567               {
00568                 char *zbase;
00569 
00570                 zbase = strchr (l->string, '@');
00571                 if (zbase != NULL
00572                     && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
00573                   {
00574                     /* We must add a symbol with this prefix.  */
00575                     if (newsymcount >= newsymalloc)
00576                      {
00577                        newsymalloc += 10;
00578                        newsyms = ((asymbol **)
00579                                  xrealloc ((void *) newsyms,
00580                                           (newsymalloc
00581                                           * sizeof (asymbol *))));
00582                      }
00583                     newsyms[newsymcount] =
00584                      (asymbol *) xmalloc (sizeof (asymbol));
00585                     *newsyms[newsymcount] = *sym;
00586                     newsyms[newsymcount]->name = l->string;
00587                     ++newsymcount;
00588                   }
00589               }
00590            }
00591          if (! found_simple)
00592            {
00593              /* The unmodified symbol is actually not exported at
00594                all.  */
00595              sym->flags &=~ (BSF_GLOBAL | BSF_EXPORT);
00596              sym->flags |= BSF_LOCAL;
00597            }
00598        }
00599 
00600       /* If it's an undefined symbol, see if it's on the import list.
00601         Change the prefix if necessary.  */
00602       if (bfd_is_und_section (bfd_get_section (sym)))
00603        {
00604          struct string_list *l;
00605 
00606          for (l = import_symbols; l != NULL; l = l->next)
00607            {
00608              if (strcmp (l->string, bfd_asymbol_name (sym)) == 0)
00609               break;
00610              else
00611               {
00612                 char *zbase;
00613 
00614                 zbase = strchr (l->string, '@');
00615                 if (zbase != NULL
00616                     && strcmp (zbase + 1, bfd_asymbol_name (sym)) == 0)
00617                   {
00618                     sym->name = l->string;
00619                     break;
00620                   }
00621               }
00622            }
00623          if (l == NULL)
00624            non_fatal (_("warning: symbol %s imported but not in import list"),
00625                      bfd_asymbol_name (sym));
00626        }
00627 
00628       /* See if it's one of the special named symbols.  */
00629       if ((sym->flags & BSF_DEBUGGING) == 0)
00630        {
00631          bfd_vma val;
00632 
00633          /* FIXME: If these symbols are not in the .text section, we
00634             add the .text section size to the value.  This may not be
00635             correct for all targets.  I'm not sure how this should
00636             really be handled.  */
00637          if (strcmp (bfd_asymbol_name (sym), start_procedure) == 0)
00638            {
00639              val = bfd_asymbol_value (sym);
00640              if (bfd_get_section (sym) == data_sec
00641                 && text_sec != (asection *) NULL)
00642               val += bfd_section_size (outbfd, text_sec);
00643              if (! bfd_set_start_address (outbfd, val))
00644               bfd_fatal (_("set start address"));
00645              gotstart = TRUE;
00646            }
00647          if (strcmp (bfd_asymbol_name (sym), exit_procedure) == 0)
00648            {
00649              val = bfd_asymbol_value (sym);
00650              if (bfd_get_section (sym) == data_sec
00651                 && text_sec != (asection *) NULL)
00652               val += bfd_section_size (outbfd, text_sec);
00653              nlm_fixed_header (outbfd)->exitProcedureOffset = val;
00654              gotexit = TRUE;
00655            }
00656          if (check_procedure != NULL
00657              && strcmp (bfd_asymbol_name (sym), check_procedure) == 0)
00658            {
00659              val = bfd_asymbol_value (sym);
00660              if (bfd_get_section (sym) == data_sec
00661                 && text_sec != (asection *) NULL)
00662               val += bfd_section_size (outbfd, text_sec);
00663              nlm_fixed_header (outbfd)->checkUnloadProcedureOffset = val;
00664              gotcheck = TRUE;
00665            }
00666        }
00667     }
00668 
00669   if (endsym != NULL)
00670     {
00671       endsym->value = bfd_get_section_size (bss_sec);
00672 
00673       /* FIXME: If any relocs referring to _end use inplace addends,
00674         then I think they need to be updated.  This is handled by
00675         i386_mangle_relocs.  Is it needed for any other object
00676         formats?  */
00677     }
00678 
00679   if (newsymcount == 0)
00680     outsyms = symbols;
00681   else
00682     {
00683       outsyms = (asymbol **) xmalloc ((symcount + newsymcount + 1)
00684                                   * sizeof (asymbol *));
00685       memcpy (outsyms, symbols, symcount * sizeof (asymbol *));
00686       memcpy (outsyms + symcount, newsyms, newsymcount * sizeof (asymbol *));
00687       outsyms[symcount + newsymcount] = NULL;
00688     }
00689 
00690   bfd_set_symtab (outbfd, outsyms, symcount + newsymcount);
00691 
00692   if (! gotstart)
00693     non_fatal (_("warning: START procedure %s not defined"), start_procedure);
00694   if (! gotexit)
00695     non_fatal (_("warning: EXIT procedure %s not defined"), exit_procedure);
00696   if (check_procedure != NULL && ! gotcheck)
00697     non_fatal (_("warning: CHECK procedure %s not defined"), check_procedure);
00698 
00699   /* Add additional sections required for the header information.  */
00700   if (custom_file != NULL)
00701     {
00702       custom_data = fopen (custom_file, "r");
00703       if (custom_data == NULL
00704          || fstat (fileno (custom_data), &st) < 0)
00705        {
00706          fprintf (stderr, "%s:%s: %s\n", program_name, custom_file,
00707                  strerror (errno));
00708          custom_file = NULL;
00709        }
00710       else
00711        {
00712          custom_size = st.st_size;
00713          custom_section = bfd_make_section (outbfd, ".nlmcustom");
00714          if (custom_section == NULL
00715              || ! bfd_set_section_size (outbfd, custom_section, custom_size)
00716              || ! bfd_set_section_flags (outbfd, custom_section,
00717                                      SEC_HAS_CONTENTS))
00718            bfd_fatal (_("custom section"));
00719        }
00720     }
00721   if (help_file != NULL)
00722     {
00723       help_data = fopen (help_file, "r");
00724       if (help_data == NULL
00725          || fstat (fileno (help_data), &st) < 0)
00726        {
00727          fprintf (stderr, "%s:%s: %s\n", program_name, help_file,
00728                  strerror (errno));
00729          help_file = NULL;
00730        }
00731       else
00732        {
00733          help_size = st.st_size;
00734          help_section = bfd_make_section (outbfd, ".nlmhelp");
00735          if (help_section == NULL
00736              || ! bfd_set_section_size (outbfd, help_section, help_size)
00737              || ! bfd_set_section_flags (outbfd, help_section,
00738                                      SEC_HAS_CONTENTS))
00739            bfd_fatal (_("help section"));
00740          LITMEMCPY (nlm_extended_header (outbfd)->stamp, "MeSsAgEs");
00741        }
00742     }
00743   if (message_file != NULL)
00744     {
00745       message_data = fopen (message_file, "r");
00746       if (message_data == NULL
00747          || fstat (fileno (message_data), &st) < 0)
00748        {
00749          fprintf (stderr, "%s:%s: %s\n", program_name, message_file,
00750                  strerror (errno));
00751          message_file = NULL;
00752        }
00753       else
00754        {
00755          message_size = st.st_size;
00756          message_section = bfd_make_section (outbfd, ".nlmmessages");
00757          if (message_section == NULL
00758              || ! bfd_set_section_size (outbfd, message_section, message_size)
00759              || ! bfd_set_section_flags (outbfd, message_section,
00760                                      SEC_HAS_CONTENTS))
00761            bfd_fatal (_("message section"));
00762          LITMEMCPY (nlm_extended_header (outbfd)->stamp, "MeSsAgEs");
00763        }
00764     }
00765   if (modules != NULL)
00766     {
00767       struct string_list *l;
00768 
00769       module_size = 0;
00770       for (l = modules; l != NULL; l = l->next)
00771        module_size += strlen (l->string) + 1;
00772       module_section = bfd_make_section (outbfd, ".nlmmodules");
00773       if (module_section == NULL
00774          || ! bfd_set_section_size (outbfd, module_section, module_size)
00775          || ! bfd_set_section_flags (outbfd, module_section,
00776                                   SEC_HAS_CONTENTS))
00777        bfd_fatal (_("module section"));
00778     }
00779   if (rpc_file != NULL)
00780     {
00781       rpc_data = fopen (rpc_file, "r");
00782       if (rpc_data == NULL
00783          || fstat (fileno (rpc_data), &st) < 0)
00784        {
00785          fprintf (stderr, "%s:%s: %s\n", program_name, rpc_file,
00786                  strerror (errno));
00787          rpc_file = NULL;
00788        }
00789       else
00790        {
00791          rpc_size = st.st_size;
00792          rpc_section = bfd_make_section (outbfd, ".nlmrpc");
00793          if (rpc_section == NULL
00794              || ! bfd_set_section_size (outbfd, rpc_section, rpc_size)
00795              || ! bfd_set_section_flags (outbfd, rpc_section,
00796                                      SEC_HAS_CONTENTS))
00797            bfd_fatal (_("rpc section"));
00798          LITMEMCPY (nlm_extended_header (outbfd)->stamp, "MeSsAgEs");
00799        }
00800     }
00801   if (sharelib_file != NULL)
00802     {
00803       sharedbfd = bfd_openr (sharelib_file, output_format);
00804       if (sharedbfd == NULL
00805          || ! bfd_check_format (sharedbfd, bfd_object))
00806        {
00807          fprintf (stderr, "%s:%s: %s\n", program_name, sharelib_file,
00808                  bfd_errmsg (bfd_get_error ()));
00809          sharelib_file = NULL;
00810        }
00811       else
00812        {
00813          sharedhdr = *nlm_fixed_header (sharedbfd);
00814          bfd_close (sharedbfd);
00815          shared_data = fopen (sharelib_file, "r");
00816          if (shared_data == NULL
00817              || (fstat (fileno (shared_data), &st) < 0))
00818            {
00819              fprintf (stderr, "%s:%s: %s\n", program_name, sharelib_file,
00820                      strerror (errno));
00821              sharelib_file = NULL;
00822            }
00823          else
00824            {
00825              /* If we were clever, we could just copy out the
00826                sections of the shared library which we actually
00827                need.  However, we would have to figure out the sizes
00828                of the external and public information, and that can
00829                not be done without reading through them.  */
00830              if (sharedhdr.uninitializedDataSize > 0)
00831               {
00832                 /* There is no place to record this information.  */
00833                 non_fatal (_("%s: warning: shared libraries can not have uninitialized data"),
00834                           sharelib_file);
00835               }
00836              shared_offset = st.st_size;
00837              if (shared_offset > (size_t) sharedhdr.codeImageOffset)
00838               shared_offset = sharedhdr.codeImageOffset;
00839              if (shared_offset > (size_t) sharedhdr.dataImageOffset)
00840               shared_offset = sharedhdr.dataImageOffset;
00841              if (shared_offset > (size_t) sharedhdr.relocationFixupOffset)
00842               shared_offset = sharedhdr.relocationFixupOffset;
00843              if (shared_offset > (size_t) sharedhdr.externalReferencesOffset)
00844               shared_offset = sharedhdr.externalReferencesOffset;
00845              if (shared_offset > (size_t) sharedhdr.publicsOffset)
00846               shared_offset = sharedhdr.publicsOffset;
00847              shared_size = st.st_size - shared_offset;
00848              shared_section = bfd_make_section (outbfd, ".nlmshared");
00849              if (shared_section == NULL
00850                 || ! bfd_set_section_size (outbfd, shared_section,
00851                                         shared_size)
00852                 || ! bfd_set_section_flags (outbfd, shared_section,
00853                                          SEC_HAS_CONTENTS))
00854               bfd_fatal (_("shared section"));
00855              LITMEMCPY (nlm_extended_header (outbfd)->stamp, "MeSsAgEs");
00856            }
00857        }
00858     }
00859 
00860   /* Check whether a version was given.  */
00861   if (!CONST_STRNEQ (version_hdr->stamp, "VeRsIoN#"))
00862     non_fatal (_("warning: No version number given"));
00863 
00864   /* At least for now, always create an extended header, because that
00865      is what NLMLINK does.  */
00866   LITMEMCPY (nlm_extended_header (outbfd)->stamp, "MeSsAgEs");
00867 
00868   LITMEMCPY (nlm_cygnus_ext_header (outbfd)->stamp, "CyGnUsEx");
00869 
00870   /* If the date was not given, force it in.  */
00871   if (nlm_version_header (outbfd)->month == 0
00872       && nlm_version_header (outbfd)->day == 0
00873       && nlm_version_header (outbfd)->year == 0)
00874     {
00875       time_t now;
00876       struct tm *ptm;
00877 
00878       time (&now);
00879       ptm = localtime (&now);
00880       nlm_version_header (outbfd)->month = ptm->tm_mon + 1;
00881       nlm_version_header (outbfd)->day = ptm->tm_mday;
00882       nlm_version_header (outbfd)->year = ptm->tm_year + 1900;
00883       LITMEMCPY (version_hdr->stamp, "VeRsIoN#");
00884     }
00885 
00886 #ifdef NLMCONV_POWERPC
00887   /* Resolve the stubs we build for PowerPC NetWare.  */
00888   if (bfd_get_arch (inbfd) == bfd_arch_powerpc)
00889     powerpc_resolve_stubs (inbfd, outbfd);
00890 #endif
00891 
00892   /* Copy over the sections.  */
00893   bfd_map_over_sections (inbfd, copy_sections, (void *) outbfd);
00894 
00895   /* Finish up the header information.  */
00896   if (custom_file != NULL)
00897     {
00898       void *data;
00899 
00900       data = xmalloc (custom_size);
00901       if (fread (data, 1, custom_size, custom_data) != custom_size)
00902        non_fatal (_("%s: read: %s"), custom_file, strerror (errno));
00903       else
00904        {
00905          if (! bfd_set_section_contents (outbfd, custom_section, data,
00906                                      (file_ptr) 0, custom_size))
00907            bfd_fatal (_("custom section"));
00908          nlm_fixed_header (outbfd)->customDataOffset =
00909            custom_section->filepos;
00910          nlm_fixed_header (outbfd)->customDataSize = custom_size;
00911        }
00912       free (data);
00913     }
00914   if (! debug_info)
00915     {
00916       /* As a special hack, the backend recognizes a debugInfoOffset
00917         of -1 to mean that it should not output any debugging
00918         information.  This can not be handling by fiddling with the
00919         symbol table because exported symbols appear in both the
00920         export information and the debugging information.  */
00921       nlm_fixed_header (outbfd)->debugInfoOffset = (file_ptr) -1;
00922     }
00923   if (full_map)
00924     non_fatal (_("warning: FULLMAP is not supported; try ld -M"));
00925   if (help_file != NULL)
00926     {
00927       void *data;
00928 
00929       data = xmalloc (help_size);
00930       if (fread (data, 1, help_size, help_data) != help_size)
00931        non_fatal (_("%s: read: %s"), help_file, strerror (errno));
00932       else
00933        {
00934          if (! bfd_set_section_contents (outbfd, help_section, data,
00935                                      (file_ptr) 0, help_size))
00936            bfd_fatal (_("help section"));
00937          nlm_extended_header (outbfd)->helpFileOffset =
00938            help_section->filepos;
00939          nlm_extended_header (outbfd)->helpFileLength = help_size;
00940        }
00941       free (data);
00942     }
00943   if (message_file != NULL)
00944     {
00945       void *data;
00946 
00947       data = xmalloc (message_size);
00948       if (fread (data, 1, message_size, message_data) != message_size)
00949        non_fatal (_("%s: read: %s"), message_file, strerror (errno));
00950       else
00951        {
00952          if (! bfd_set_section_contents (outbfd, message_section, data,
00953                                      (file_ptr) 0, message_size))
00954            bfd_fatal (_("message section"));
00955          nlm_extended_header (outbfd)->messageFileOffset =
00956            message_section->filepos;
00957          nlm_extended_header (outbfd)->messageFileLength = message_size;
00958 
00959          /* FIXME: Are these offsets correct on all platforms?  Are
00960             they 32 bits on all platforms?  What endianness?  */
00961          nlm_extended_header (outbfd)->languageID =
00962            bfd_h_get_32 (outbfd, (bfd_byte *) data + 106);
00963          nlm_extended_header (outbfd)->messageCount =
00964            bfd_h_get_32 (outbfd, (bfd_byte *) data + 110);
00965        }
00966       free (data);
00967     }
00968   if (modules != NULL)
00969     {
00970       void *data;
00971       unsigned char *set;
00972       struct string_list *l;
00973       bfd_size_type c;
00974 
00975       data = xmalloc (module_size);
00976       c = 0;
00977       set = (unsigned char *) data;
00978       for (l = modules; l != NULL; l = l->next)
00979        {
00980          *set = strlen (l->string);
00981          strncpy ((char *) set + 1, l->string, *set);
00982          set += *set + 1;
00983          ++c;
00984        }
00985       if (! bfd_set_section_contents (outbfd, module_section, data,
00986                                   (file_ptr) 0, module_size))
00987        bfd_fatal (_("module section"));
00988       nlm_fixed_header (outbfd)->moduleDependencyOffset =
00989        module_section->filepos;
00990       nlm_fixed_header (outbfd)->numberOfModuleDependencies = c;
00991     }
00992   if (rpc_file != NULL)
00993     {
00994       void *data;
00995 
00996       data = xmalloc (rpc_size);
00997       if (fread (data, 1, rpc_size, rpc_data) != rpc_size)
00998        non_fatal (_("%s: read: %s"), rpc_file, strerror (errno));
00999       else
01000        {
01001          if (! bfd_set_section_contents (outbfd, rpc_section, data,
01002                                      (file_ptr) 0, rpc_size))
01003            bfd_fatal (_("rpc section"));
01004          nlm_extended_header (outbfd)->RPCDataOffset =
01005            rpc_section->filepos;
01006          nlm_extended_header (outbfd)->RPCDataLength = rpc_size;
01007        }
01008       free (data);
01009     }
01010   if (sharelib_file != NULL)
01011     {
01012       void *data;
01013 
01014       data = xmalloc (shared_size);
01015       if (fseek (shared_data, shared_offset, SEEK_SET) != 0
01016          || fread (data, 1, shared_size, shared_data) != shared_size)
01017        non_fatal (_("%s: read: %s"), sharelib_file, strerror (errno));
01018       else
01019        {
01020          if (! bfd_set_section_contents (outbfd, shared_section, data,
01021                                      (file_ptr) 0, shared_size))
01022            bfd_fatal (_("shared section"));
01023        }
01024       nlm_extended_header (outbfd)->sharedCodeOffset =
01025        sharedhdr.codeImageOffset - shared_offset + shared_section->filepos;
01026       nlm_extended_header (outbfd)->sharedCodeLength =
01027        sharedhdr.codeImageSize;
01028       nlm_extended_header (outbfd)->sharedDataOffset =
01029        sharedhdr.dataImageOffset - shared_offset + shared_section->filepos;
01030       nlm_extended_header (outbfd)->sharedDataLength =
01031        sharedhdr.dataImageSize;
01032       nlm_extended_header (outbfd)->sharedRelocationFixupOffset =
01033        (sharedhdr.relocationFixupOffset
01034         - shared_offset
01035         + shared_section->filepos);
01036       nlm_extended_header (outbfd)->sharedRelocationFixupCount =
01037        sharedhdr.numberOfRelocationFixups;
01038       nlm_extended_header (outbfd)->sharedExternalReferenceOffset =
01039        (sharedhdr.externalReferencesOffset
01040         - shared_offset
01041         + shared_section->filepos);
01042       nlm_extended_header (outbfd)->sharedExternalReferenceCount =
01043        sharedhdr.numberOfExternalReferences;
01044       nlm_extended_header (outbfd)->sharedPublicsOffset =
01045        sharedhdr.publicsOffset - shared_offset + shared_section->filepos;
01046       nlm_extended_header (outbfd)->sharedPublicsCount =
01047        sharedhdr.numberOfPublics;
01048       nlm_extended_header (outbfd)->sharedDebugRecordOffset =
01049        sharedhdr.debugInfoOffset - shared_offset + shared_section->filepos;
01050       nlm_extended_header (outbfd)->sharedDebugRecordCount =
01051        sharedhdr.numberOfDebugRecords;
01052       nlm_extended_header (outbfd)->SharedInitializationOffset =
01053        sharedhdr.codeStartOffset;
01054       nlm_extended_header (outbfd)->SharedExitProcedureOffset =
01055        sharedhdr.exitProcedureOffset;
01056       free (data);
01057     }
01058 
01059   {
01060     const int    max_len  = NLM_MODULE_NAME_SIZE - 2;
01061     const char * filename = lbasename (output_file);
01062     
01063     len = strlen (filename);
01064     if (len > max_len)
01065       len = max_len;
01066     nlm_fixed_header (outbfd)->moduleName[0] = len;
01067 
01068     strncpy (nlm_fixed_header (outbfd)->moduleName + 1, filename, max_len);
01069     nlm_fixed_header (outbfd)->moduleName[max_len + 1] = '\0';
01070 
01071     for (modname = nlm_fixed_header (outbfd)->moduleName;
01072         *modname != '\0';
01073         modname++)
01074       *modname = TOUPPER (*modname);
01075   }
01076 
01077   strncpy (nlm_variable_header (outbfd)->oldThreadName, " LONG",
01078           NLM_OLD_THREAD_NAME_LENGTH);
01079 
01080   nlm_cygnus_ext_header (outbfd)->offset = secsec->filepos;
01081   nlm_cygnus_ext_header (outbfd)->length = bfd_section_size (outbfd, secsec);
01082 
01083   if (! bfd_close (outbfd))
01084     bfd_fatal (output_file);
01085   if (! bfd_close (inbfd))
01086     bfd_fatal (input_file);
01087 
01088   if (unlink_on_exit != NULL)
01089     unlink (unlink_on_exit);
01090 
01091   return 0;
01092 }
01093 
01094 
01095 /* Show a usage message and exit.  */
01096 
01097 static void
01098 show_usage (FILE *file, int status)
01099 {
01100   fprintf (file, _("Usage: %s [option(s)] [in-file [out-file]]\n"), program_name);
01101   fprintf (file, _(" Convert an object file into a NetWare Loadable Module\n"));
01102   fprintf (file, _(" The options are:\n\
01103   -I --input-target=<bfdname>   Set the input binary file format\n\
01104   -O --output-target=<bfdname>  Set the output binary file format\n\
01105   -T --header-file=<file>       Read <file> for NLM header information\n\
01106   -l --linker=<linker>          Use <linker> for any linking\n\
01107   -d --debug                    Display on stderr the linker command line\n\
01108   @<file>                       Read options from <file>.\n\
01109   -h --help                     Display this information\n\
01110   -v --version                  Display the program's version\n\
01111 "));
01112   if (REPORT_BUGS_TO[0] && status == 0)
01113     fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
01114   exit (status);
01115 }
01116 
01117 /* Select the output format based on the input architecture, machine,
01118    and endianness.  This chooses the appropriate NLM target.  */
01119 
01120 static const char *
01121 select_output_format (enum bfd_architecture arch, unsigned long mach,
01122                     bfd_boolean bigendian ATTRIBUTE_UNUSED)
01123 {
01124   switch (arch)
01125     {
01126 #ifdef NLMCONV_I386
01127     case bfd_arch_i386:
01128       return "nlm32-i386";
01129 #endif
01130 #ifdef NLMCONV_SPARC
01131     case bfd_arch_sparc:
01132       return "nlm32-sparc";
01133 #endif
01134 #ifdef NLMCONV_ALPHA
01135     case bfd_arch_alpha:
01136       return "nlm32-alpha";
01137 #endif
01138 #ifdef NLMCONV_POWERPC
01139     case bfd_arch_powerpc:
01140       return "nlm32-powerpc";
01141 #endif
01142     default:
01143       fatal (_("support not compiled in for %s"),
01144             bfd_printable_arch_mach (arch, mach));
01145     }
01146   /*NOTREACHED*/
01147 }
01148 
01149 /* The BFD sections are copied in two passes.  This function selects
01150    the output section for each input section, and sets up the section
01151    name, size, etc.  */
01152 
01153 static void
01154 setup_sections (bfd *inbfd ATTRIBUTE_UNUSED, asection *insec, void *data_ptr)
01155 {
01156   bfd *outbfd = (bfd *) data_ptr;
01157   flagword f;
01158   const char *outname;
01159   asection *outsec;
01160   bfd_vma offset;
01161   bfd_size_type align;
01162   bfd_size_type add;
01163   bfd_size_type secsecsize;
01164 
01165   f = bfd_get_section_flags (inbfd, insec);
01166   if (f & SEC_CODE)
01167     outname = NLM_CODE_NAME;
01168   else if ((f & SEC_LOAD) && (f & SEC_HAS_CONTENTS))
01169     outname = NLM_INITIALIZED_DATA_NAME;
01170   else if (f & SEC_ALLOC)
01171     outname = NLM_UNINITIALIZED_DATA_NAME;
01172   else
01173     outname = bfd_section_name (inbfd, insec);
01174 
01175   outsec = bfd_get_section_by_name (outbfd, outname);
01176   if (outsec == NULL)
01177     {
01178       outsec = bfd_make_section (outbfd, outname);
01179       if (outsec == NULL)
01180        bfd_fatal (_("make section"));
01181     }
01182 
01183   insec->output_section = outsec;
01184 
01185   offset = bfd_section_size (outbfd, outsec);
01186   align = 1 << bfd_section_alignment (inbfd, insec);
01187   add = ((offset + align - 1) &~ (align - 1)) - offset;
01188   insec->output_offset = offset + add;
01189 
01190   if (! bfd_set_section_size (outbfd, outsec,
01191                            (bfd_section_size (outbfd, outsec)
01192                             + bfd_section_size (inbfd, insec)
01193                             + add)))
01194     bfd_fatal (_("set section size"));
01195 
01196   if ((bfd_section_alignment (inbfd, insec)
01197        > bfd_section_alignment (outbfd, outsec))
01198       && ! bfd_set_section_alignment (outbfd, outsec,
01199                                   bfd_section_alignment (inbfd, insec)))
01200     bfd_fatal (_("set section alignment"));
01201 
01202   if (! bfd_set_section_flags (outbfd, outsec,
01203                             f | bfd_get_section_flags (outbfd, outsec)))
01204     bfd_fatal (_("set section flags"));
01205 
01206   bfd_set_reloc (outbfd, outsec, (arelent **) NULL, 0);
01207 
01208   /* For each input section we allocate space for an entry in
01209      .nlmsections.  */
01210   secsecsize = bfd_section_size (outbfd, secsec);
01211   secsecsize += strlen (bfd_section_name (inbfd, insec)) + 1;
01212   secsecsize = (secsecsize + 3) &~ 3;
01213   secsecsize += 8;
01214   if (! bfd_set_section_size (outbfd, secsec, secsecsize))
01215     bfd_fatal (_("set .nlmsections size"));
01216 }
01217 
01218 /* Copy the section contents.  */
01219 
01220 static void
01221 copy_sections (bfd *inbfd, asection *insec, void *data_ptr)
01222 {
01223   static bfd_size_type secsecoff = 0;
01224   bfd *outbfd = (bfd *) data_ptr;
01225   const char *inname;
01226   asection *outsec;
01227   bfd_size_type size;
01228   void *contents;
01229   long reloc_size;
01230   bfd_byte buf[4];
01231   bfd_size_type add;
01232 
01233   inname = bfd_section_name (inbfd, insec);
01234 
01235   outsec = insec->output_section;
01236   assert (outsec != NULL);
01237 
01238   size = bfd_get_section_size (insec);
01239 
01240   if ((bfd_get_section_flags (inbfd, insec) & SEC_HAS_CONTENTS) == 0)
01241     contents = NULL;
01242   else
01243     {
01244       contents = xmalloc (size);
01245       if (! bfd_get_section_contents (inbfd, insec, contents,
01246                                   (file_ptr) 0, size))
01247        bfd_fatal (bfd_get_filename (inbfd));
01248     }
01249 
01250   reloc_size = bfd_get_reloc_upper_bound (inbfd, insec);
01251   if (reloc_size < 0)
01252     bfd_fatal (bfd_get_filename (inbfd));
01253   if (reloc_size != 0)
01254     {
01255       arelent **relocs;
01256       long reloc_count;
01257 
01258       relocs = (arelent **) xmalloc (reloc_size);
01259       reloc_count = bfd_canonicalize_reloc (inbfd, insec, relocs, symbols);
01260       if (reloc_count < 0)
01261        bfd_fatal (bfd_get_filename (inbfd));
01262       mangle_relocs (outbfd, insec, &relocs, &reloc_count, (char *) contents,
01263                    size);
01264 
01265       /* FIXME: refers to internal BFD fields.  */
01266       if (outsec->orelocation != (arelent **) NULL)
01267        {
01268          bfd_size_type total_count;
01269          arelent **combined;
01270 
01271          total_count = reloc_count + outsec->reloc_count;
01272          combined = (arelent **) xmalloc (total_count * sizeof (arelent *));
01273          memcpy (combined, outsec->orelocation,
01274                 outsec->reloc_count * sizeof (arelent *));
01275          memcpy (combined + outsec->reloc_count, relocs,
01276                 (size_t) (reloc_count * sizeof (arelent *)));
01277          free (outsec->orelocation);
01278          reloc_count = total_count;
01279          relocs = combined;
01280        }
01281 
01282       bfd_set_reloc (outbfd, outsec, relocs, reloc_count);
01283     }
01284 
01285   if (contents != NULL)
01286     {
01287       if (! bfd_set_section_contents (outbfd, outsec, contents,
01288                                   insec->output_offset, size))
01289        bfd_fatal (bfd_get_filename (outbfd));
01290       free (contents);
01291     }
01292 
01293   /* Add this section to .nlmsections.  */
01294   if (! bfd_set_section_contents (outbfd, secsec, (void *) inname, secsecoff,
01295                               strlen (inname) + 1))
01296     bfd_fatal (_("set .nlmsection contents"));
01297   secsecoff += strlen (inname) + 1;
01298 
01299   add = ((secsecoff + 3) &~ 3) - secsecoff;
01300   if (add != 0)
01301     {
01302       bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);
01303       if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, add))
01304        bfd_fatal (_("set .nlmsection contents"));
01305       secsecoff += add;
01306     }
01307 
01308   if (contents != NULL)
01309     bfd_h_put_32 (outbfd, (bfd_vma) outsec->filepos, buf);
01310   else
01311     bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);
01312   if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))
01313     bfd_fatal (_("set .nlmsection contents"));
01314   secsecoff += 4;
01315 
01316   bfd_h_put_32 (outbfd, (bfd_vma) size, buf);
01317   if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))
01318     bfd_fatal (_("set .nlmsection contents"));
01319   secsecoff += 4;
01320 }
01321 
01322 /* Some, perhaps all, NetWare targets require changing the relocs used
01323    by the input formats.  */
01324 
01325 static void
01326 mangle_relocs (bfd *outbfd, asection *insec, arelent ***relocs_ptr,
01327               long *reloc_count_ptr, char *contents,
01328               bfd_size_type contents_size)
01329 {
01330   switch (bfd_get_arch (outbfd))
01331     {
01332 #ifdef NLMCONV_I386
01333     case bfd_arch_i386:
01334       i386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
01335                        contents, contents_size);
01336       break;
01337 #endif
01338 #ifdef NLMCONV_ALPHA
01339     case bfd_arch_alpha:
01340       alpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
01341                         contents, contents_size);
01342       break;
01343 #endif
01344 #ifdef NLMCONV_POWERPC
01345     case bfd_arch_powerpc:
01346       powerpc_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
01347                           contents, contents_size);
01348       break;
01349 #endif
01350     default:
01351       default_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,
01352                           contents, contents_size);
01353       break;
01354     }
01355 }
01356 
01357 /* By default all we need to do for relocs is change the address by
01358    the output_offset.  */
01359 
01360 static void
01361 default_mangle_relocs (bfd *outbfd ATTRIBUTE_UNUSED, asection *insec,
01362                      arelent ***relocs_ptr, long *reloc_count_ptr,
01363                      char *contents ATTRIBUTE_UNUSED,
01364                      bfd_size_type contents_size ATTRIBUTE_UNUSED)
01365 {
01366   if (insec->output_offset != 0)
01367     {
01368       long reloc_count;
01369       arelent **relocs;
01370       long i;
01371 
01372       reloc_count = *reloc_count_ptr;
01373       relocs = *relocs_ptr;
01374       for (i = 0; i < reloc_count; i++, relocs++)
01375        (*relocs)->address += insec->output_offset;
01376     }
01377 }
01378 
01379 #ifdef NLMCONV_I386
01380 
01381 /* NetWare on the i386 supports a restricted set of relocs, which are
01382    different from those used on other i386 targets.  This routine
01383    converts the relocs.  It is, obviously, very target dependent.  At
01384    the moment, the nlm32-i386 backend performs similar translations;
01385    however, it is more reliable and efficient to do them here.  */
01386 
01387 static reloc_howto_type nlm_i386_pcrel_howto =
01388   HOWTO (1,                 /* type */
01389         0,                  /* rightshift */
01390         2,                  /* size (0 = byte, 1 = short, 2 = long) */
01391         32,                 /* bitsize */
01392         TRUE,               /* pc_relative */
01393         0,                  /* bitpos */
01394         complain_overflow_signed, /* complain_on_overflow */
01395         0,                  /* special_function */
01396         "DISP32",           /* name */
01397         TRUE,               /* partial_inplace */
01398         0xffffffff,         /* src_mask */
01399         0xffffffff,         /* dst_mask */
01400         TRUE);                     /* pcrel_offset */
01401 
01402 static void
01403 i386_mangle_relocs (bfd *outbfd, asection *insec, arelent ***relocs_ptr,
01404                   long *reloc_count_ptr, char *contents,
01405                   bfd_size_type contents_size)
01406 {
01407   long reloc_count, i;
01408   arelent **relocs;
01409 
01410   reloc_count = *reloc_count_ptr;
01411   relocs = *relocs_ptr;
01412   for (i = 0; i < reloc_count; i++)
01413     {
01414       arelent *rel;
01415       asymbol *sym;
01416       bfd_size_type address;
01417       bfd_vma addend;
01418 
01419       rel = *relocs++;
01420       sym = *rel->sym_ptr_ptr;
01421 
01422       /* We're moving the relocs from the input section to the output
01423         section, so we must adjust the address accordingly.  */
01424       address = rel->address;
01425       rel->address += insec->output_offset;
01426 
01427       /* Note that no serious harm will ensue if we fail to change a
01428         reloc.  The backend will fail when writing out the reloc.  */
01429 
01430       /* Make sure this reloc is within the data we have.  We use only
01431         4 byte relocs here, so we insist on having 4 bytes.  */
01432       if (address + 4 > contents_size)
01433        continue;
01434 
01435       /* A PC relative reloc entirely within a single section is
01436         completely unnecessary.  This can be generated by ld -r.  */
01437       if (sym == insec->symbol
01438          && rel->howto != NULL
01439          && rel->howto->pc_relative
01440          && ! rel->howto->pcrel_offset)
01441        {
01442          --*reloc_count_ptr;
01443          --relocs;
01444          memmove (relocs, relocs + 1,
01445                  (size_t) ((reloc_count - i) * sizeof (arelent *)));
01446          continue;
01447        }
01448 
01449       /* Get the amount the relocation will add in.  */
01450       addend = rel->addend + sym->value;
01451 
01452       /* NetWare doesn't support PC relative relocs against defined
01453         symbols, so we have to eliminate them by doing the relocation
01454         now.  We can only do this if the reloc is within a single
01455         section.  */
01456       if (rel->howto != NULL
01457          && rel->howto->pc_relative
01458          && bfd_get_section (sym) == insec->output_section)
01459        {
01460          bfd_vma val;
01461 
01462          if (rel->howto->pcrel_offset)
01463            addend -= address;
01464 
01465          val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);
01466          val += addend;
01467          bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);
01468 
01469          --*reloc_count_ptr;
01470          --relocs;
01471          memmove (relocs, relocs + 1,
01472                  (size_t) ((reloc_count - i) * sizeof (arelent *)));
01473          continue;
01474        }
01475 
01476       /* NetWare doesn't support reloc addends, so we get rid of them
01477         here by simply adding them into the object data.  We handle
01478         the symbol value, if any, the same way.  */
01479       if (addend != 0
01480          && rel->howto != NULL
01481          && rel->howto->rightshift == 0
01482          && rel->howto->size == 2
01483          && rel->howto->bitsize == 32
01484          && rel->howto->bitpos == 0
01485          && rel->howto->src_mask == 0xffffffff
01486          && rel->howto->dst_mask == 0xffffffff)
01487        {
01488          bfd_vma val;
01489 
01490          val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);
01491          val += addend;
01492          bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);
01493 
01494          /* Adjust the reloc for the changes we just made.  */
01495          rel->addend = 0;
01496          if (! bfd_is_und_section (bfd_get_section (sym)))
01497            rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
01498        }
01499 
01500       /* NetWare uses a reloc with pcrel_offset set.  We adjust
01501         pc_relative relocs accordingly.  We are going to change the
01502         howto field, so we can only do this if the current one is
01503         compatible.  We should check that special_function is NULL
01504         here, but at the moment coff-i386 uses a special_function
01505         which does not affect what we are doing here.  */
01506       if (rel->howto != NULL
01507          && rel->howto->pc_relative
01508          && ! rel->howto->pcrel_offset
01509          && rel->howto->rightshift == 0
01510          && rel->howto->size == 2
01511          && rel->howto->bitsize == 32
01512          && rel->howto->bitpos == 0
01513          && rel->howto->src_mask == 0xffffffff
01514          && rel->howto->dst_mask == 0xffffffff)
01515        {
01516          bfd_vma val;
01517 
01518          /* When pcrel_offset is not set, it means that the negative
01519             of the address of the memory location is stored in the
01520             memory location.  We must add it back in.  */
01521          val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);
01522          val += address;
01523          bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);
01524 
01525          /* We must change to a new howto.  */
01526          rel->howto = &nlm_i386_pcrel_howto;
01527        }
01528     }
01529 }
01530 
01531 #endif /* NLMCONV_I386 */
01532 
01533 #ifdef NLMCONV_ALPHA
01534 
01535 /* On the Alpha the first reloc for every section must be a special
01536    relocs which hold the GP address.  Also, the first reloc in the
01537    file must be a special reloc which holds the address of the .lita
01538    section.  */
01539 
01540 static reloc_howto_type nlm32_alpha_nw_howto =
01541   HOWTO (ALPHA_R_NW_RELOC,  /* type */
01542         0,                  /* rightshift */
01543         0,                  /* size (0 = byte, 1 = short, 2 = long) */
01544         0,                  /* bitsize */
01545         FALSE,                     /* pc_relative */
01546         0,                  /* bitpos */
01547         complain_overflow_dont, /* complain_on_overflow */
01548         0,                  /* special_function */
01549         "NW_RELOC",         /* name */
01550         FALSE,                     /* partial_inplace */
01551         0,                  /* src_mask */
01552         0,                  /* dst_mask */
01553         FALSE);             /* pcrel_offset */
01554 
01555 static void
01556 alpha_mangle_relocs (bfd *outbfd, asection *insec,
01557                    arelent ***relocs_ptr, long *reloc_count_ptr,
01558                    char *contents ATTRIBUTE_UNUSED,
01559                    bfd_size_type contents_size ATTRIBUTE_UNUSED)
01560 {
01561   long old_reloc_count;
01562   arelent **old_relocs;
01563   arelent **relocs;
01564 
01565   old_reloc_count = *reloc_count_ptr;
01566   old_relocs = *relocs_ptr;
01567   relocs = (arelent **) xmalloc ((old_reloc_count + 3) * sizeof (arelent *));
01568   *relocs_ptr = relocs;
01569 
01570   if (nlm_alpha_backend_data (outbfd)->lita_address == 0)
01571     {
01572       bfd *inbfd;
01573       asection *lita_section;
01574 
01575       inbfd = insec->owner;
01576       lita_section = bfd_get_section_by_name (inbfd, _LITA);
01577       if (lita_section != (asection *) NULL)
01578        {
01579          nlm_alpha_backend_data (outbfd)->lita_address =
01580            bfd_get_section_vma (inbfd, lita_section);
01581          nlm_alpha_backend_data (outbfd)->lita_size =
01582            bfd_section_size (inbfd, lita_section);
01583        }
01584       else
01585        {
01586          /* Avoid outputting this reloc again.  */
01587          nlm_alpha_backend_data (outbfd)->lita_address = 4;
01588        }
01589 
01590       *relocs = (arelent *) xmalloc (sizeof (arelent));
01591       (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
01592       (*relocs)->address = nlm_alpha_backend_data (outbfd)->lita_address;
01593       (*relocs)->addend = nlm_alpha_backend_data (outbfd)->lita_size + 1;
01594       (*relocs)->howto = &nlm32_alpha_nw_howto;
01595       ++relocs;
01596       ++(*reloc_count_ptr);
01597     }
01598 
01599   /* Get the GP value from bfd.  */
01600   if (nlm_alpha_backend_data (outbfd)->gp == 0)
01601     nlm_alpha_backend_data (outbfd)->gp =
01602       bfd_ecoff_get_gp_value (insec->owner);
01603 
01604   *relocs = (arelent *) xmalloc (sizeof (arelent));
01605   (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
01606   (*relocs)->address = nlm_alpha_backend_data (outbfd)->gp;
01607   (*relocs)->addend = 0;
01608   (*relocs)->howto = &nlm32_alpha_nw_howto;
01609   ++relocs;
01610   ++(*reloc_count_ptr);
01611 
01612   memcpy (relocs, old_relocs, (size_t) old_reloc_count * sizeof (arelent *));
01613   relocs[old_reloc_count] = (arelent *) NULL;
01614 
01615   free (old_relocs);
01616 
01617   if (insec->output_offset != 0)
01618     {
01619       bfd_size_type i;
01620 
01621       for (i = 0; i < (bfd_size_type) old_reloc_count; i++, relocs++)
01622        (*relocs)->address += insec->output_offset;
01623     }
01624 }
01625 
01626 #endif /* NLMCONV_ALPHA */
01627 
01628 #ifdef NLMCONV_POWERPC
01629 
01630 /* We keep a linked list of stubs which we must build.  Because BFD
01631    requires us to know the sizes of all sections before we can set the
01632    contents of any, we must figure out which stubs we want to build
01633    before we can actually build any of them.  */
01634 
01635 struct powerpc_stub
01636 {
01637   /* Next stub in linked list.  */
01638   struct powerpc_stub *next;
01639 
01640   /* Symbol whose value is the start of the stub.  This is a symbol
01641      whose name begins with `.'.  */
01642   asymbol *start;
01643 
01644   /* Symbol we are going to create a reloc against.  This is a symbol
01645      with the same name as START but without the leading `.'.  */
01646   asymbol *reloc;
01647 
01648   /* The TOC index for this stub.  This is the index into the TOC
01649      section at which the reloc is created.  */
01650   unsigned int toc_index;
01651 };
01652 
01653 /* The linked list of stubs.  */
01654 
01655 static struct powerpc_stub *powerpc_stubs;
01656 
01657 /* This is what a stub looks like.  The first instruction will get
01658    adjusted with the correct TOC index.  */
01659 
01660 static unsigned long powerpc_stub_insns[] =
01661 {
01662   0x81820000,        /* lwz  r12,0(r2) */
01663   0x90410014,        /* stw  r2,20(r1) */
01664   0x800c0000,        /* lwz  r0,0(r12) */
01665   0x804c0004,        /* lwz  r2,r(r12) */
01666   0x7c0903a6,        /* mtctr r0 */
01667   0x4e800420,        /* bctr */
01668   0,                 /* Traceback table.  */
01669   0xc8000,
01670   0
01671 };
01672 
01673 #define POWERPC_STUB_INSN_COUNT \
01674   (sizeof powerpc_stub_insns / sizeof powerpc_stub_insns[0])
01675 
01676 #define POWERPC_STUB_SIZE (4 * POWERPC_STUB_INSN_COUNT)
01677 
01678 /* Each stub uses a four byte TOC entry.  */
01679 #define POWERPC_STUB_TOC_ENTRY_SIZE (4)
01680 
01681 /* The original size of the .got section.  */
01682 static bfd_size_type powerpc_initial_got_size;
01683 
01684 /* Look for all undefined symbols beginning with `.', and prepare to
01685    build a stub for each one.  */
01686 
01687 static void
01688 powerpc_build_stubs (bfd *inbfd, bfd *outbfd ATTRIBUTE_UNUSED,
01689                    asymbol ***symbols_ptr, long *symcount_ptr)
01690 {
01691   asection *stub_sec;
01692   asection *got_sec;
01693   unsigned int got_base;
01694   long i;
01695   long symcount;
01696   long stubcount;
01697 
01698   /* Make a section to hold stubs.  We don't set SEC_HAS_CONTENTS for
01699      the section to prevent copy_sections from reading from it.  */
01700   stub_sec = bfd_make_section (inbfd, ".stubs");
01701   if (stub_sec == (asection *) NULL
01702       || ! bfd_set_section_flags (inbfd, stub_sec,
01703                               (SEC_CODE
01704                                | SEC_RELOC
01705                                | SEC_ALLOC
01706                                | SEC_LOAD))
01707       || ! bfd_set_section_alignment (inbfd, stub_sec, 2))
01708     bfd_fatal (".stubs");
01709 
01710   /* Get the TOC section, which is named .got.  */
01711   got_sec = bfd_get_section_by_name (inbfd, ".got");
01712   if (got_sec == (asection *) NULL)
01713     {
01714       got_sec = bfd_make_section (inbfd, ".got");
01715       if (got_sec == (asection *) NULL
01716          || ! bfd_set_section_flags (inbfd, got_sec,
01717                                   (SEC_DATA
01718                                    | SEC_RELOC
01719                                    | SEC_ALLOC
01720                                    | SEC_LOAD
01721                                    | SEC_HAS_CONTENTS))
01722          || ! bfd_set_section_alignment (inbfd, got_sec, 2))
01723        bfd_fatal (".got");
01724     }
01725 
01726   powerpc_initial_got_size = bfd_section_size (inbfd, got_sec);
01727   got_base = powerpc_initial_got_size;
01728   got_base = (got_base + 3) &~ 3;
01729 
01730   stubcount = 0;
01731 
01732   symcount = *symcount_ptr;
01733   for (i = 0; i < symcount; i++)
01734     {
01735       asymbol *sym;
01736       asymbol *newsym;
01737       char *newname;
01738       struct powerpc_stub *item;
01739 
01740       sym = (*symbols_ptr)[i];
01741 
01742       /* We must make a stub for every undefined symbol whose name
01743         starts with '.'.  */
01744       if (bfd_asymbol_name (sym)[0] != '.'
01745          || ! bfd_is_und_section (bfd_get_section (sym)))
01746        continue;
01747 
01748       /* Make a new undefined symbol with the same name but without
01749         the leading `.'.  */
01750       newsym = xmalloc (sizeof (asymbol));
01751       *newsym = *sym;
01752       newname = xmalloc (strlen (bfd_asymbol_name (sym)));
01753       strcpy (newname, bfd_asymbol_name (sym) + 1);
01754       newsym->name = newname;
01755 
01756       /* Define the `.' symbol to be in the stub section.  */
01757       sym->section = stub_sec;
01758       sym->value = stubcount * POWERPC_STUB_SIZE;
01759       /* We set the BSF_DYNAMIC flag here so that we can check it when
01760         we are mangling relocs.  FIXME: This is a hack.  */
01761       sym->flags = BSF_LOCAL | BSF_DYNAMIC;
01762 
01763       /* Add this stub to the linked list.  */
01764       item = (struct powerpc_stub *) xmalloc (sizeof (struct powerpc_stub));
01765       item->start = sym;
01766       item->reloc = newsym;
01767       item->toc_index = got_base + stubcount * POWERPC_STUB_TOC_ENTRY_SIZE;
01768 
01769       item->next = powerpc_stubs;
01770       powerpc_stubs = item;
01771 
01772       ++stubcount;
01773     }
01774 
01775   if (stubcount > 0)
01776     {
01777       asymbol **s;
01778       struct powerpc_stub *l;
01779 
01780       /* Add the new symbols we just created to the symbol table.  */
01781       *symbols_ptr = (asymbol **) xrealloc ((char *) *symbols_ptr,
01782                                        ((symcount + stubcount)
01783                                         * sizeof (asymbol)));
01784       *symcount_ptr += stubcount;
01785       s = &(*symbols_ptr)[symcount];
01786       for (l = powerpc_stubs; l != (struct powerpc_stub *) NULL; l = l->next)
01787        *s++ = l->reloc;
01788 
01789       /* Set the size of the .stubs section and increase the size of
01790         the .got section.  */
01791       if (! bfd_set_section_size (inbfd, stub_sec,
01792                               stubcount * POWERPC_STUB_SIZE)
01793          || ! bfd_set_section_size (inbfd, got_sec,
01794                                  (got_base
01795                                   + (stubcount
01796                                     * POWERPC_STUB_TOC_ENTRY_SIZE))))
01797        bfd_fatal (_("stub section sizes"));
01798     }
01799 }
01800 
01801 /* Resolve all the stubs for PowerPC NetWare.  We fill in the contents
01802    of the output section, and create new relocs in the TOC.  */
01803 
01804 static void
01805 powerpc_resolve_stubs (bfd *inbfd, bfd *outbfd)
01806 {
01807   bfd_byte buf[POWERPC_STUB_SIZE];
01808   unsigned int i;
01809   unsigned int stubcount;
01810   arelent **relocs;
01811   asection *got_sec;
01812   arelent **r;
01813   struct powerpc_stub *l;
01814 
01815   if (powerpc_stubs == (struct powerpc_stub *) NULL)
01816     return;
01817 
01818   for (i = 0; i < POWERPC_STUB_INSN_COUNT; i++)
01819     bfd_put_32 (outbfd, (bfd_vma) powerpc_stub_insns[i], buf + i * 4);
01820 
01821   got_sec = bfd_get_section_by_name (inbfd, ".got");
01822   assert (got_sec != (asection *) NULL);
01823   assert (got_sec->output_section->orelocation == (arelent **) NULL);
01824 
01825   stubcount = 0;
01826   for (l = powerpc_stubs; l != (struct powerpc_stub *) NULL; l = l->next)
01827     ++stubcount;
01828   relocs = (arelent **) xmalloc (stubcount * sizeof (arelent *));
01829 
01830   r = relocs;
01831   for (l = powerpc_stubs; l != (struct powerpc_stub *) NULL; l = l->next)
01832     {
01833       arelent *reloc;
01834 
01835       /* Adjust the first instruction to use the right TOC index.  */
01836       bfd_put_32 (outbfd, (bfd_vma) powerpc_stub_insns[0] + l->toc_index, buf);
01837 
01838       /* Write this stub out.  */
01839       if (! bfd_set_section_contents (outbfd,
01840                                   bfd_get_section (l->start),
01841                                   buf,
01842                                   l->start->value,
01843                                   POWERPC_STUB_SIZE))
01844        bfd_fatal (_("writing stub"));
01845 
01846       /* Create a new reloc for the TOC entry.  */
01847       reloc = (arelent *) xmalloc (sizeof (arelent));
01848       reloc->sym_ptr_ptr = &l->reloc;
01849       reloc->address = l->toc_index + got_sec->output_offset;
01850       reloc->addend = 0;
01851       reloc->howto = bfd_reloc_type_lookup (inbfd, BFD_RELOC_32);
01852 
01853       *r++ = reloc;
01854     }
01855 
01856   bfd_set_reloc (outbfd, got_sec->output_section, relocs, stubcount);
01857 }
01858 
01859 /* Adjust relocation entries for PowerPC NetWare.  We do not output
01860    TOC relocations.  The object code already contains the offset from
01861    the TOC pointer.  When the function is called, the TOC register,
01862    r2, will be set to the correct TOC value, so there is no need for
01863    any further reloc.  */
01864 
01865 static void
01866 powerpc_mangle_relocs (bfd *outbfd, asection *insec,
01867                      arelent ***relocs_ptr,
01868                      long *reloc_count_ptr, char *contents,
01869                      bfd_size_type contents_size ATTRIBUTE_UNUSED)
01870 {
01871   reloc_howto_type *toc_howto;
01872   long reloc_count;
01873   arelent **relocs;
01874   long i;
01875 
01876   toc_howto = bfd_reloc_type_lookup (insec->owner, BFD_RELOC_PPC_TOC16);
01877   if (toc_howto == (reloc_howto_type *) NULL)
01878     abort ();
01879 
01880   /* If this is the .got section, clear out all the contents beyond
01881      the initial size.  We must do this here because copy_sections is
01882      going to write out whatever we return in the contents field.  */
01883   if (strcmp (bfd_get_section_name (insec->owner, insec), ".got") == 0)
01884     memset (contents + powerpc_initial_got_size, 0,
01885            (size_t) (bfd_get_section_size (insec) - powerpc_initial_got_size));
01886 
01887   reloc_count = *reloc_count_ptr;
01888   relocs = *relocs_ptr;
01889   for (i = 0; i < reloc_count; i++)
01890     {
01891       arelent *rel;
01892       asymbol *sym;
01893       bfd_vma sym_value;
01894 
01895       rel = *relocs++;
01896       sym = *rel->sym_ptr_ptr;
01897 
01898       /* Convert any relocs against the .bss section into relocs
01899          against the .data section.  */
01900       if (strcmp (bfd_get_section_name (outbfd, bfd_get_section (sym)),
01901                 NLM_UNINITIALIZED_DATA_NAME) == 0)
01902        {
01903          asection *datasec;
01904 
01905          datasec = bfd_get_section_by_name (outbfd,
01906                                         NLM_INITIALIZED_DATA_NAME);
01907          if (datasec != NULL)
01908            {
01909              rel->addend += (bfd_get_section_vma (outbfd,
01910                                              bfd_get_section (sym))
01911                            + sym->value);
01912              rel->sym_ptr_ptr = datasec->symbol_ptr_ptr;
01913              sym = *rel->sym_ptr_ptr;
01914            }
01915        }
01916 
01917       /* We must be able to resolve all PC relative relocs at this
01918         point.  If we get a branch to an undefined symbol we build a
01919         stub, since NetWare will resolve undefined symbols into a
01920         pointer to a function descriptor.  */
01921       if (rel->howto->pc_relative)
01922        {
01923          /* This check for whether a symbol is in the same section as
01924             the reloc will be wrong if there is a PC relative reloc
01925             between two sections both of which were placed in the
01926             same output section.  This should not happen.  */
01927          if (bfd_get_section (sym) != insec->output_section)
01928            non_fatal (_("unresolved PC relative reloc against %s"),
01929                      bfd_asymbol_name (sym));
01930          else
01931            {
01932              bfd_vma val;
01933 
01934              assert (rel->howto->size == 2 && rel->howto->pcrel_offset);
01935              val = bfd_get_32 (outbfd, (bfd_byte *) contents + rel->address);
01936              val = ((val &~ rel->howto->dst_mask)
01937                    | (((val & rel->howto->src_mask)
01938                       + (sym->value - rel->address)
01939                       + rel->addend)
01940                      & rel->howto->dst_mask));
01941              bfd_put_32 (outbfd, val, (bfd_byte *) contents + rel->address);
01942 
01943              /* If this reloc is against an stubbed symbol and the
01944                next instruction is
01945                    cror 31,31,31
01946                then we replace the next instruction with
01947                    lwz  r2,20(r1)
01948                This reloads the TOC pointer after a stub call.  */
01949              if (bfd_asymbol_name (sym)[0] == '.'
01950                 && (sym->flags & BSF_DYNAMIC) != 0
01951                 && (bfd_get_32 (outbfd,
01952                               (bfd_byte *) contents + rel->address + 4)
01953                     == 0x4ffffb82)) /* cror 31,31,31 */
01954               bfd_put_32 (outbfd, (bfd_vma) 0x80410014, /* lwz r2,20(r1) */
01955                          (bfd_byte *) contents + rel->address + 4);
01956 
01957              --*reloc_count_ptr;
01958              --relocs;
01959              memmove (relocs, relocs + 1,
01960                      (size_t) ((reloc_count - 1) * sizeof (arelent *)));
01961              continue;
01962            }
01963        }
01964 
01965       /* When considering a TOC reloc, we do not want to include the
01966         symbol value.  The symbol will be start of the TOC section
01967         (which is named .got).  We do want to include the addend.  */
01968       if (rel->howto == toc_howto)
01969        sym_value = 0;
01970       else
01971        sym_value = sym->value;
01972 
01973       /* If this is a relocation against a symbol with a value, or
01974         there is a reloc addend, we need to update the addend in the
01975         object file.  */
01976       if (sym_value + rel->addend != 0)
01977        {
01978          bfd_vma val;
01979 
01980          switch (rel->howto->size)
01981            {
01982            case 1:
01983              val = bfd_get_16 (outbfd,
01984                             (bfd_byte *) contents + rel->address);
01985              val = ((val &~ rel->howto->dst_mask)
01986                    | (((val & rel->howto->src_mask)
01987                       + sym_value
01988                       + rel->addend)
01989                      & rel->howto->dst_mask));
01990              if ((bfd_signed_vma) val < - 0x8000
01991                 || (bfd_signed_vma) val >= 0x8000)
01992               non_fatal (_("overflow when adjusting relocation against %s"),
01993                         bfd_asymbol_name (sym));
01994              bfd_put_16 (outbfd, val, (bfd_byte *) contents + rel->address);
01995              break;
01996 
01997            case 2:
01998              val = bfd_get_32 (outbfd,
01999                             (bfd_byte *) contents + rel->address);
02000              val = ((val &~ rel->howto->dst_mask)
02001                    | (((val & rel->howto->src_mask)
02002                       + sym_value
02003                       + rel->addend)
02004                      & rel->howto->dst_mask));
02005              bfd_put_32 (outbfd, val, (bfd_byte *) contents + rel->address);
02006              break;
02007 
02008            default:
02009              abort ();
02010            }
02011 
02012          if (! bfd_is_und_section (bfd_get_section (sym)))
02013            rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;
02014          rel->addend = 0;
02015        }
02016 
02017       /* Now that we have incorporated the addend, remove any TOC
02018         relocs.  */
02019       if (rel->howto == toc_howto)
02020        {
02021          --*reloc_count_ptr;
02022          --relocs;
02023          memmove (relocs, relocs + 1,
02024                  (size_t) ((reloc_count - i) * sizeof (arelent *)));
02025          continue;
02026        }
02027 
02028       rel->address += insec->output_offset;
02029     }
02030 }
02031 
02032 #endif /* NLMCONV_POWERPC */
02033 
02034 /* Name of linker.  */
02035 #ifndef LD_NAME
02036 #define LD_NAME "ld"
02037 #endif
02038 
02039 /* The user has specified several input files.  Invoke the linker to
02040    link them all together, and convert and delete the resulting output
02041    file.  */
02042 
02043 static char *
02044 link_inputs (struct string_list *inputs, char *ld, char * map_file)
02045 {
02046   size_t c;
02047   struct string_list *q;
02048   char **argv;
02049   size_t i;
02050   int pid;
02051   int status;
02052   char *errfmt;
02053   char *errarg;
02054 
02055   c = 0;
02056   for (q = inputs; q != NULL; q = q->next)
02057     ++c;
02058 
02059   argv = (char **) alloca ((c + 7) * sizeof (char *));
02060 
02061 #ifndef __MSDOS__
02062   if (ld == NULL)
02063     {
02064       char *p;
02065 
02066       /* Find the linker to invoke based on how nlmconv was run.  */
02067       p = program_name + strlen (program_name);
02068       while (p != program_name)
02069        {
02070          if (p[-1] == '/')
02071            {
02072              ld = (char *) xmalloc (p - program_name + strlen (LD_NAME) + 1);
02073              memcpy (ld, program_name, p - program_name);
02074              strcpy (ld + (p - program_name), LD_NAME);
02075              break;
02076            }
02077          --p;
02078        }
02079     }
02080 #endif
02081 
02082   if (ld == NULL)
02083     ld = (char *) LD_NAME;
02084 
02085   unlink_on_exit = make_temp_file (".O");
02086 
02087   argv[0] = ld;
02088   argv[1] = (char *) "-Ur";
02089   argv[2] = (char *) "-o";
02090   argv[3] = unlink_on_exit;
02091   /* If we have been given the name of a mapfile and that
02092      name is not 'stderr' then pass it on to the linker.  */
02093   if (map_file
02094       && * map_file
02095       && strcmp (map_file, "stderr") == 0)
02096     {
02097       argv[4] = (char *) "-Map";
02098       argv[5] = map_file;
02099       i = 6;
02100     }
02101   else
02102     i = 4;
02103 
02104   for (q = inputs; q != NULL; q = q->next, i++)
02105     argv[i] = q->string;
02106   argv[i] = NULL;
02107 
02108   if (debug)
02109     {
02110       for (i = 0; argv[i] != NULL; i++)
02111        fprintf (stderr, " %s", argv[i]);
02112       fprintf (stderr, "\n");
02113     }
02114 
02115   pid = pexecute (ld, argv, program_name, (char *) NULL, &errfmt, &errarg,
02116                 PEXECUTE_SEARCH | PEXECUTE_ONE);
02117   if (pid == -1)
02118     {
02119       fprintf (stderr, _("%s: execution of %s failed: "), program_name, ld);
02120       fprintf (stderr, errfmt, errarg);
02121       unlink (unlink_on_exit);
02122       exit (1);
02123     }
02124 
02125   if (pwait (pid, &status, 0) < 0)
02126     {
02127       perror ("pwait");
02128       unlink (unlink_on_exit);
02129       exit (1);
02130     }
02131 
02132   if (status != 0)
02133     {
02134       non_fatal (_("Execution of %s failed"), ld);
02135       unlink (unlink_on_exit);
02136       exit (1);
02137     }
02138 
02139   return unlink_on_exit;
02140 }