Back to index

cell-binutils  2.17cvs20070401
nlmcode.h
Go to the documentation of this file.
00001 /* NLM (NetWare Loadable Module) executable support for BFD.
00002    Copyright 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
00003    2005, 2006 Free Software Foundation, Inc.
00004 
00005    Written by Fred Fish @ Cygnus Support, using ELF support as the
00006    template.
00007 
00008    This file is part of BFD, the Binary File Descriptor library.
00009 
00010    This program is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2 of the License, or
00013    (at your option) any later version.
00014 
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019 
00020    You should have received a copy of the GNU General Public License
00021    along with this program; if not, write to the Free Software
00022    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00023 
00024 #include "bfd.h"
00025 #include "sysdep.h"
00026 #include "libbfd.h"
00027 #include "libnlm.h"
00028 
00029 /* The functions in this file do not use the names they appear to use.
00030    This file is actually compiled multiple times, once for each size
00031    of NLM target we are using.  At each size we use a different name,
00032    constructed by the macro nlmNAME.  For example, the function which
00033    is named nlm_symbol_type below is actually named nlm32_symbol_type
00034    in the final executable.  */
00035 
00036 #define Nlm_External_Fixed_Header  NlmNAME (External_Fixed_Header)
00037 #define Nlm_External_Version_Header       NlmNAME (External_Version_Header)
00038 #define Nlm_External_Copyright_Header     NlmNAME (External_Copyright_Header)
00039 #define Nlm_External_Extended_Header      NlmNAME (External_Extended_Header)
00040 #define Nlm_External_Custom_Header NlmNAME (External_Custom_Header)
00041 #define Nlm_External_Cygnus_Ext_Header    NlmNAME (External_Cygnus_Ext_Header)
00042 
00043 #define nlm_symbol_type                   nlmNAME (symbol_type)
00044 #define nlm_get_symtab_upper_bound nlmNAME (get_symtab_upper_bound)
00045 #define nlm_canonicalize_symtab           nlmNAME (canonicalize_symtab)
00046 #define nlm_make_empty_symbol             nlmNAME (make_empty_symbol)
00047 #define nlm_print_symbol           nlmNAME (print_symbol)
00048 #define nlm_get_symbol_info        nlmNAME (get_symbol_info)
00049 #define nlm_get_reloc_upper_bound  nlmNAME (get_reloc_upper_bound)
00050 #define nlm_canonicalize_reloc            nlmNAME (canonicalize_reloc)
00051 #define nlm_object_p               nlmNAME (object_p)
00052 #define nlm_set_section_contents   nlmNAME (set_section_contents)
00053 #define nlm_write_object_contents  nlmNAME (write_object_contents)
00054 
00055 #define nlm_swap_fixed_header_in(abfd,src,dst) \
00056   (nlm_swap_fixed_header_in_func (abfd)) (abfd, src, dst)
00057 #define nlm_swap_fixed_header_out(abfd,src,dst) \
00058   (nlm_swap_fixed_header_out_func (abfd)) (abfd, src, dst)
00059 
00060 /* Should perhaps use put_offset, put_word, etc.  For now, the two versions
00061    can be handled by explicitly specifying 32 bits or "the long type".  */
00062 #if ARCH_SIZE == 64
00063 #define put_word     H_PUT_64
00064 #define get_word     H_GET_64
00065 #endif
00066 #if ARCH_SIZE == 32
00067 #define put_word     H_PUT_32
00068 #define get_word     H_GET_32
00069 #endif
00070 
00071 /* Read and swap in the variable length header.  All the fields must
00072    exist in the NLM, and must exist in the order they are read here.  */
00073 
00074 static bfd_boolean
00075 nlm_swap_variable_header_in (bfd *abfd)
00076 {
00077   unsigned char temp[NLM_TARGET_LONG_SIZE];
00078   bfd_size_type amt;
00079 
00080   /* Read the description length and text members.  */
00081   amt = sizeof (nlm_variable_header (abfd)->descriptionLength);
00082   if (bfd_bread ((void *) &nlm_variable_header (abfd)->descriptionLength,
00083               amt, abfd) != amt)
00084     return FALSE;
00085   amt = nlm_variable_header (abfd)->descriptionLength + 1;
00086   if (bfd_bread ((void *) nlm_variable_header (abfd)->descriptionText,
00087               amt, abfd) != amt)
00088     return FALSE;
00089 
00090   /* Read and convert the stackSize field.  */
00091   amt = sizeof (temp);
00092   if (bfd_bread ((void *) temp, amt, abfd) != amt)
00093     return FALSE;
00094   nlm_variable_header (abfd)->stackSize = get_word (abfd, (bfd_byte *) temp);
00095 
00096   /* Read and convert the reserved field.  */
00097   amt = sizeof (temp);
00098   if (bfd_bread ((void *) temp, amt, abfd) != amt)
00099     return FALSE;
00100   nlm_variable_header (abfd)->reserved = get_word (abfd, (bfd_byte *) temp);
00101 
00102   /* Read the oldThreadName field.  This field is a fixed length string.  */
00103   amt = sizeof (nlm_variable_header (abfd)->oldThreadName);
00104   if (bfd_bread ((void *) nlm_variable_header (abfd)->oldThreadName,
00105               amt, abfd) != amt)
00106     return FALSE;
00107 
00108   /* Read the screen name length and text members.  */
00109   amt = sizeof (nlm_variable_header (abfd)->screenNameLength);
00110   if (bfd_bread ((void *) & nlm_variable_header (abfd)->screenNameLength,
00111               amt, abfd) != amt)
00112     return FALSE;
00113   amt = nlm_variable_header (abfd)->screenNameLength + 1;
00114   if (bfd_bread ((void *) nlm_variable_header (abfd)->screenName,
00115               amt, abfd) != amt)
00116     return FALSE;
00117 
00118   /* Read the thread name length and text members.  */
00119   amt = sizeof (nlm_variable_header (abfd)->threadNameLength);
00120   if (bfd_bread ((void *) & nlm_variable_header (abfd)->threadNameLength,
00121               amt, abfd) != amt)
00122     return FALSE;
00123   amt = nlm_variable_header (abfd)->threadNameLength + 1;
00124   if (bfd_bread ((void *) nlm_variable_header (abfd)->threadName,
00125               amt, abfd) != amt)
00126     return FALSE;
00127   return TRUE;
00128 }
00129 
00130 /* Add a section to the bfd.  */
00131 
00132 static bfd_boolean
00133 add_bfd_section (bfd *abfd,
00134                char *name,
00135                file_ptr offset,
00136                bfd_size_type size,
00137                flagword flags)
00138 {
00139   asection *newsect;
00140 
00141   newsect = bfd_make_section_with_flags (abfd, name, flags);
00142   if (newsect == NULL)
00143     return FALSE;
00144 
00145   newsect->vma = 0;         /* NLM's are relocatable.  */
00146   newsect->size = size;
00147   newsect->filepos = offset;
00148   newsect->alignment_power = bfd_log2 ((bfd_vma) 0);    /* FIXME */
00149 
00150   return TRUE;
00151 }
00152 
00153 /* Read and swap in the contents of all the auxiliary headers.  Because of
00154    the braindead design, we have to do strcmps on strings of indeterminate
00155    length to figure out what each auxiliary header is.  Even worse, we have
00156    no way of knowing how many auxiliary headers there are or where the end
00157    of the auxiliary headers are, except by finding something that doesn't
00158    look like a known auxiliary header.  This means that the first new type
00159    of auxiliary header added will break all existing tools that don't
00160    recognize it.  */
00161 
00162 static bfd_boolean
00163 nlm_swap_auxiliary_headers_in (bfd *abfd)
00164 {
00165   char tempstr[16];
00166   file_ptr position;
00167   bfd_size_type amt;
00168 
00169   for (;;)
00170     {
00171       position = bfd_tell (abfd);
00172       amt = sizeof (tempstr);
00173       if (bfd_bread ((void *) tempstr, amt, abfd) != amt)
00174        return FALSE;
00175       if (bfd_seek (abfd, position, SEEK_SET) != 0)
00176        return FALSE;
00177       if (CONST_STRNEQ (tempstr, "VeRsIoN#"))
00178        {
00179          Nlm_External_Version_Header thdr;
00180 
00181          amt = sizeof (thdr);
00182          if (bfd_bread ((void *) &thdr, amt, abfd) != amt)
00183            return FALSE;
00184          memcpy (nlm_version_header (abfd)->stamp, thdr.stamp,
00185                 sizeof (thdr.stamp));
00186          nlm_version_header (abfd)->majorVersion =
00187            get_word (abfd, (bfd_byte *) thdr.majorVersion);
00188          nlm_version_header (abfd)->minorVersion =
00189            get_word (abfd, (bfd_byte *) thdr.minorVersion);
00190          nlm_version_header (abfd)->revision =
00191            get_word (abfd, (bfd_byte *) thdr.revision);
00192          nlm_version_header (abfd)->year =
00193            get_word (abfd, (bfd_byte *) thdr.year);
00194          nlm_version_header (abfd)->month =
00195            get_word (abfd, (bfd_byte *) thdr.month);
00196          nlm_version_header (abfd)->day =
00197            get_word (abfd, (bfd_byte *) thdr.day);
00198        }
00199       else if (CONST_STRNEQ (tempstr, "MeSsAgEs"))
00200        {
00201          Nlm_External_Extended_Header thdr;
00202 
00203          amt = sizeof (thdr);
00204          if (bfd_bread ((void *) &thdr, amt, abfd) != amt)
00205            return FALSE;
00206          memcpy (nlm_extended_header (abfd)->stamp, thdr.stamp,
00207                 sizeof (thdr.stamp));
00208          nlm_extended_header (abfd)->languageID =
00209            get_word (abfd, (bfd_byte *) thdr.languageID);
00210          nlm_extended_header (abfd)->messageFileOffset =
00211            get_word (abfd, (bfd_byte *) thdr.messageFileOffset);
00212          nlm_extended_header (abfd)->messageFileLength =
00213            get_word (abfd, (bfd_byte *) thdr.messageFileLength);
00214          nlm_extended_header (abfd)->messageCount =
00215            get_word (abfd, (bfd_byte *) thdr.messageCount);
00216          nlm_extended_header (abfd)->helpFileOffset =
00217            get_word (abfd, (bfd_byte *) thdr.helpFileOffset);
00218          nlm_extended_header (abfd)->helpFileLength =
00219            get_word (abfd, (bfd_byte *) thdr.helpFileLength);
00220          nlm_extended_header (abfd)->RPCDataOffset =
00221            get_word (abfd, (bfd_byte *) thdr.RPCDataOffset);
00222          nlm_extended_header (abfd)->RPCDataLength =
00223            get_word (abfd, (bfd_byte *) thdr.RPCDataLength);
00224          nlm_extended_header (abfd)->sharedCodeOffset =
00225            get_word (abfd, (bfd_byte *) thdr.sharedCodeOffset);
00226          nlm_extended_header (abfd)->sharedCodeLength =
00227            get_word (abfd, (bfd_byte *) thdr.sharedCodeLength);
00228          nlm_extended_header (abfd)->sharedDataOffset =
00229            get_word (abfd, (bfd_byte *) thdr.sharedDataOffset);
00230          nlm_extended_header (abfd)->sharedDataLength =
00231            get_word (abfd, (bfd_byte *) thdr.sharedDataLength);
00232          nlm_extended_header (abfd)->sharedRelocationFixupOffset =
00233            get_word (abfd, (bfd_byte *) thdr.sharedRelocationFixupOffset);
00234          nlm_extended_header (abfd)->sharedRelocationFixupCount =
00235            get_word (abfd, (bfd_byte *) thdr.sharedRelocationFixupCount);
00236          nlm_extended_header (abfd)->sharedExternalReferenceOffset =
00237            get_word (abfd, (bfd_byte *) thdr.sharedExternalReferenceOffset);
00238          nlm_extended_header (abfd)->sharedExternalReferenceCount =
00239            get_word (abfd, (bfd_byte *) thdr.sharedExternalReferenceCount);
00240          nlm_extended_header (abfd)->sharedPublicsOffset =
00241            get_word (abfd, (bfd_byte *) thdr.sharedPublicsOffset);
00242          nlm_extended_header (abfd)->sharedPublicsCount =
00243            get_word (abfd, (bfd_byte *) thdr.sharedPublicsCount);
00244          nlm_extended_header (abfd)->sharedDebugRecordOffset =
00245            get_word (abfd, (bfd_byte *) thdr.sharedDebugRecordOffset);
00246          nlm_extended_header (abfd)->sharedDebugRecordCount =
00247            get_word (abfd, (bfd_byte *) thdr.sharedDebugRecordCount);
00248          nlm_extended_header (abfd)->SharedInitializationOffset =
00249            get_word (abfd, (bfd_byte *) thdr.sharedInitializationOffset);
00250          nlm_extended_header (abfd)->SharedExitProcedureOffset =
00251            get_word (abfd, (bfd_byte *) thdr.SharedExitProcedureOffset);
00252          nlm_extended_header (abfd)->productID =
00253            get_word (abfd, (bfd_byte *) thdr.productID);
00254          nlm_extended_header (abfd)->reserved0 =
00255            get_word (abfd, (bfd_byte *) thdr.reserved0);
00256          nlm_extended_header (abfd)->reserved1 =
00257            get_word (abfd, (bfd_byte *) thdr.reserved1);
00258          nlm_extended_header (abfd)->reserved2 =
00259            get_word (abfd, (bfd_byte *) thdr.reserved2);
00260          nlm_extended_header (abfd)->reserved3 =
00261            get_word (abfd, (bfd_byte *) thdr.reserved3);
00262          nlm_extended_header (abfd)->reserved4 =
00263            get_word (abfd, (bfd_byte *) thdr.reserved4);
00264          nlm_extended_header (abfd)->reserved5 =
00265            get_word (abfd, (bfd_byte *) thdr.reserved5);
00266        }
00267       else if (CONST_STRNEQ (tempstr, "CoPyRiGhT="))
00268        {
00269          amt = sizeof (nlm_copyright_header (abfd)->stamp);
00270          if (bfd_bread ((void *) nlm_copyright_header (abfd)->stamp,
00271                      amt, abfd) != amt)
00272            return FALSE;
00273          if (bfd_bread ((void *) &(nlm_copyright_header (abfd)
00274                             ->copyrightMessageLength),
00275                      (bfd_size_type) 1, abfd) != 1)
00276            return FALSE;
00277          /* The copyright message is a variable length string.  */
00278          amt = nlm_copyright_header (abfd)->copyrightMessageLength + 1;
00279          if (bfd_bread ((void *) nlm_copyright_header (abfd)->copyrightMessage,
00280                      amt, abfd) != amt)
00281            return FALSE;
00282        }
00283       else if (CONST_STRNEQ (tempstr, "CuStHeAd"))
00284        {
00285          Nlm_External_Custom_Header thdr;
00286          bfd_size_type hdrLength;
00287          file_ptr dataOffset;
00288          bfd_size_type dataLength;
00289          char dataStamp[8];
00290          void * hdr;
00291 
00292          /* Read the stamp ("CuStHeAd").  */
00293          amt = sizeof (thdr.stamp);
00294          if (bfd_bread ((void *) thdr.stamp, amt, abfd) != amt)
00295            return FALSE;
00296          /* Read the length of this custom header.  */
00297          amt = sizeof (thdr.length);
00298          if (bfd_bread ((void *) thdr.length, amt, abfd) != amt)
00299            return FALSE;
00300          hdrLength = get_word (abfd, (bfd_byte *) thdr.length);
00301          /* Read further fields if we have them.  */
00302          if (hdrLength < NLM_TARGET_LONG_SIZE)
00303            dataOffset = 0;
00304          else
00305            {
00306              amt = sizeof (thdr.dataOffset);
00307              if (bfd_bread ((void *) thdr.dataOffset, amt, abfd) != amt)
00308               return FALSE;
00309              dataOffset = get_word (abfd, (bfd_byte *) thdr.dataOffset);
00310            }
00311          if (hdrLength < 2 * NLM_TARGET_LONG_SIZE)
00312            dataLength = 0;
00313          else
00314            {
00315              amt = sizeof (thdr.dataLength);
00316              if (bfd_bread ((void *) thdr.dataLength, amt, abfd) != amt)
00317               return FALSE;
00318              dataLength = get_word (abfd, (bfd_byte *) thdr.dataLength);
00319            }
00320          if (hdrLength < 2 * NLM_TARGET_LONG_SIZE + 8)
00321            memset (dataStamp, 0, sizeof (dataStamp));
00322          else
00323            {
00324              amt = sizeof (dataStamp);
00325              if (bfd_bread ((void *) dataStamp, amt, abfd) != amt)
00326               return FALSE;
00327            }
00328 
00329          /* Read the rest of the header, if any.  */
00330          if (hdrLength <= 2 * NLM_TARGET_LONG_SIZE + 8)
00331            {
00332              hdr = NULL;
00333              hdrLength = 0;
00334            }
00335          else
00336            {
00337              hdrLength -= 2 * NLM_TARGET_LONG_SIZE + 8;
00338              hdr = bfd_alloc (abfd, hdrLength);
00339              if (hdr == NULL)
00340               return FALSE;
00341              if (bfd_bread (hdr, hdrLength, abfd) != hdrLength)
00342               return FALSE;
00343            }
00344 
00345          /* If we have found a Cygnus header, process it.  Otherwise,
00346             just save the associated data without trying to interpret
00347             it.  */
00348          if (CONST_STRNEQ (dataStamp, "CyGnUsEx"))
00349            {
00350              file_ptr pos;
00351              bfd_byte *contents;
00352              bfd_byte *p, *pend;
00353 
00354              BFD_ASSERT (hdrLength == 0 && hdr == NULL);
00355 
00356              pos = bfd_tell (abfd);
00357              if (bfd_seek (abfd, dataOffset, SEEK_SET) != 0)
00358               return FALSE;
00359              contents = bfd_alloc (abfd, dataLength);
00360              if (contents == NULL)
00361               return FALSE;
00362              if (bfd_bread (contents, dataLength, abfd) != dataLength)
00363               return FALSE;
00364              if (bfd_seek (abfd, pos, SEEK_SET) != 0)
00365               return FALSE;
00366 
00367              LITMEMCPY (nlm_cygnus_ext_header (abfd), "CyGnUsEx");
00368              nlm_cygnus_ext_header (abfd)->offset = dataOffset;
00369              nlm_cygnus_ext_header (abfd)->length = dataLength;
00370 
00371              /* This data this header points to provides a list of
00372                the sections which were in the original object file
00373                which was converted to become an NLM.  We locate
00374                those sections and add them to the BFD.  Note that
00375                this is likely to create a second .text, .data and
00376                .bss section; retrieving the sections by name will
00377                get the actual NLM sections, which is what we want to
00378                happen.  The sections from the original file, which
00379                may be subsets of the NLM section, can only be found
00380                using bfd_map_over_sections.  */
00381              p = contents;
00382              pend = p + dataLength;
00383              while (p < pend)
00384               {
00385                 char *name;
00386                 size_t l;
00387                 file_ptr filepos;
00388                 bfd_size_type size;
00389                 asection *newsec;
00390 
00391                 /* The format of this information is
00392                    null terminated section name
00393                    zeroes to adjust to 4 byte boundary
00394                    4 byte section data file pointer
00395                    4 byte section size.  */
00396 
00397                 name = (char *) p;
00398                 l = strlen (name) + 1;
00399                 l = (l + 3) &~ (size_t) 3;
00400                 p += l;
00401                 filepos = H_GET_32 (abfd, p);
00402                 p += 4;
00403                 size = H_GET_32 (abfd, p);
00404                 p += 4;
00405 
00406                 newsec = bfd_make_section_anyway (abfd, name);
00407                 if (newsec == NULL)
00408                   return FALSE;
00409                 newsec->size = size;
00410                 if (filepos != 0)
00411                   {
00412                     newsec->filepos = filepos;
00413                     newsec->flags |= SEC_HAS_CONTENTS;
00414                   }
00415               }
00416            }
00417          else
00418            {
00419              memcpy (nlm_custom_header (abfd)->stamp, thdr.stamp,
00420                     sizeof (thdr.stamp));
00421              nlm_custom_header (abfd)->hdrLength = hdrLength;
00422              nlm_custom_header (abfd)->dataOffset = dataOffset;
00423              nlm_custom_header (abfd)->dataLength = dataLength;
00424              memcpy (nlm_custom_header (abfd)->dataStamp, dataStamp,
00425                     sizeof (dataStamp));
00426              nlm_custom_header (abfd)->hdr = hdr;
00427            }
00428        }
00429       else
00430        break;
00431     }
00432   return TRUE;
00433 }
00434 
00435 const bfd_target *
00436 nlm_object_p (bfd *abfd)
00437 {
00438   struct nlm_obj_tdata *preserved_tdata = nlm_tdata (abfd);
00439   bfd_boolean (*backend_object_p) (bfd *);
00440   void * x_fxdhdr = NULL;
00441   Nlm_Internal_Fixed_Header *i_fxdhdrp;
00442   struct nlm_obj_tdata *new_tdata = NULL;
00443   const char *signature;
00444   enum bfd_architecture arch;
00445   bfd_size_type amt;
00446 
00447   /* Some NLM formats have a prefix before the standard NLM fixed
00448      header.  */
00449   backend_object_p = nlm_backend_object_p_func (abfd);
00450   if (backend_object_p)
00451     {
00452       if (!(*backend_object_p) (abfd))
00453        goto got_wrong_format_error;
00454     }
00455 
00456   /* Read in the fixed length portion of the NLM header in external format.  */
00457   amt = nlm_fixed_header_size (abfd);
00458   x_fxdhdr = bfd_malloc (amt);
00459   if (x_fxdhdr == NULL)
00460     goto got_no_match;
00461 
00462   if (bfd_bread ((void *) x_fxdhdr, amt, abfd) != amt)
00463     {
00464       if (bfd_get_error () != bfd_error_system_call)
00465        goto got_wrong_format_error;
00466       else
00467        goto got_no_match;
00468     }
00469 
00470   /* Allocate an instance of the nlm_obj_tdata structure and hook it up to
00471      the tdata pointer in the bfd.  */
00472   amt = sizeof (struct nlm_obj_tdata);
00473   new_tdata = bfd_zalloc (abfd, amt);
00474   if (new_tdata == NULL)
00475     goto got_no_match;
00476 
00477   nlm_tdata (abfd) = new_tdata;
00478 
00479   i_fxdhdrp = nlm_fixed_header (abfd);
00480   nlm_swap_fixed_header_in (abfd, x_fxdhdr, i_fxdhdrp);
00481   free (x_fxdhdr);
00482   x_fxdhdr = NULL;
00483 
00484   /* Check to see if we have an NLM file for this backend by matching
00485      the NLM signature.  */
00486   signature = nlm_signature (abfd);
00487   if (signature != NULL
00488       && *signature != '\0'
00489       && strncmp ((char *) i_fxdhdrp->signature, signature,
00490                 NLM_SIGNATURE_SIZE) != 0)
00491     goto got_wrong_format_error;
00492 
00493   /* There's no supported way to discover the endianess of an NLM, so test for
00494      a sane version number after doing byte swapping appropriate for this
00495      XVEC.  (Hack alert!)  */
00496   if (i_fxdhdrp->version > 0xFFFF)
00497     goto got_wrong_format_error;
00498 
00499   /* There's no supported way to check for 32 bit versus 64 bit addresses,
00500      so ignore this distinction for now.  (FIXME) */
00501   /* Swap in the rest of the required header.  */
00502   if (!nlm_swap_variable_header_in (abfd))
00503     {
00504       if (bfd_get_error () != bfd_error_system_call)
00505        goto got_wrong_format_error;
00506       else
00507        goto got_no_match;
00508     }
00509 
00510   /* Add the sections supplied by all NLM's, and then read in the
00511      auxiliary headers.  Reading the auxiliary headers may create
00512      additional sections described in the cygnus_ext header.
00513      From this point on we assume that we have an NLM, and do not
00514      treat errors as indicating the wrong format.  */
00515   if (!add_bfd_section (abfd, NLM_CODE_NAME,
00516                      i_fxdhdrp->codeImageOffset,
00517                      i_fxdhdrp->codeImageSize,
00518                      (SEC_CODE | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
00519                       | SEC_RELOC))
00520       || !add_bfd_section (abfd, NLM_INITIALIZED_DATA_NAME,
00521                         i_fxdhdrp->dataImageOffset,
00522                         i_fxdhdrp->dataImageSize,
00523                         (SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
00524                          | SEC_RELOC))
00525       || !add_bfd_section (abfd, NLM_UNINITIALIZED_DATA_NAME,
00526                         (file_ptr) 0,
00527                         i_fxdhdrp->uninitializedDataSize,
00528                         SEC_ALLOC))
00529     goto got_no_match;
00530 
00531   if (!nlm_swap_auxiliary_headers_in (abfd))
00532     goto got_no_match;
00533 
00534   if (nlm_fixed_header (abfd)->numberOfRelocationFixups != 0
00535       || nlm_fixed_header (abfd)->numberOfExternalReferences != 0)
00536     abfd->flags |= HAS_RELOC;
00537   if (nlm_fixed_header (abfd)->numberOfPublics != 0
00538       || nlm_fixed_header (abfd)->numberOfDebugRecords != 0
00539       || nlm_fixed_header (abfd)->numberOfExternalReferences != 0)
00540     abfd->flags |= HAS_SYMS;
00541 
00542   arch = nlm_architecture (abfd);
00543   if (arch != bfd_arch_unknown)
00544     bfd_default_set_arch_mach (abfd, arch, (unsigned long) 0);
00545 
00546   abfd->flags |= EXEC_P;
00547   bfd_get_start_address (abfd) = nlm_fixed_header (abfd)->codeStartOffset;
00548 
00549   return abfd->xvec;
00550 
00551 got_wrong_format_error:
00552   bfd_set_error (bfd_error_wrong_format);
00553 got_no_match:
00554   nlm_tdata (abfd) = preserved_tdata;
00555   if (new_tdata != NULL)
00556     bfd_release (abfd, new_tdata);
00557   if (x_fxdhdr != NULL)
00558     free (x_fxdhdr);
00559 
00560   return NULL;
00561 }
00562 
00563 /* Swap and write out the variable length header.  All the fields must
00564    exist in the NLM, and must exist in this order.  */
00565 
00566 static bfd_boolean
00567 nlm_swap_variable_header_out (bfd *abfd)
00568 {
00569   bfd_byte temp[NLM_TARGET_LONG_SIZE];
00570   bfd_size_type amt;
00571 
00572   /* Write the description length and text members.  */
00573   amt = sizeof (nlm_variable_header (abfd)->descriptionLength);
00574   if (bfd_bwrite (& nlm_variable_header (abfd)->descriptionLength, amt,
00575                 abfd) != amt)
00576     return FALSE;
00577   amt = nlm_variable_header (abfd)->descriptionLength + 1;
00578   if (bfd_bwrite ((void *) nlm_variable_header (abfd)->descriptionText, amt,
00579                 abfd) != amt)
00580     return FALSE;
00581 
00582   /* Convert and write the stackSize field.  */
00583   put_word (abfd, (bfd_vma) nlm_variable_header (abfd)->stackSize, temp);
00584   amt = sizeof (temp);
00585   if (bfd_bwrite (temp, amt, abfd) != amt)
00586     return FALSE;
00587 
00588   /* Convert and write the reserved field.  */
00589   put_word (abfd, (bfd_vma) nlm_variable_header (abfd)->reserved, temp);
00590   amt = sizeof (temp);
00591   if (bfd_bwrite (temp, amt, abfd) != amt)
00592     return FALSE;
00593 
00594   /* Write the oldThreadName field.  This field is a fixed length string.  */
00595   amt = sizeof (nlm_variable_header (abfd)->oldThreadName);
00596   if (bfd_bwrite (nlm_variable_header (abfd)->oldThreadName, amt,
00597                 abfd) != amt)
00598     return FALSE;
00599 
00600   /* Write the screen name length and text members.  */
00601   amt = sizeof (nlm_variable_header (abfd)->screenNameLength);
00602   if (bfd_bwrite (& nlm_variable_header (abfd)->screenNameLength, amt,
00603                abfd) != amt)
00604     return FALSE;
00605   amt = nlm_variable_header (abfd)->screenNameLength + 1;
00606   if (bfd_bwrite (nlm_variable_header (abfd)->screenName, amt, abfd) != amt)
00607     return FALSE;
00608 
00609   /* Write the thread name length and text members.  */
00610   amt = sizeof (nlm_variable_header (abfd)->threadNameLength);
00611   if (bfd_bwrite (& nlm_variable_header (abfd)->threadNameLength, amt,
00612                abfd) != amt)
00613     return FALSE;
00614   amt = nlm_variable_header (abfd)->threadNameLength + 1;
00615   if (bfd_bwrite (nlm_variable_header (abfd)->threadName, amt, abfd) != amt)
00616     return FALSE;
00617   return TRUE;
00618 }
00619 
00620 /* Return whether there is a non-zero byte in a memory block.  */
00621 
00622 static bfd_boolean
00623 find_nonzero (void * buf, size_t size)
00624 {
00625   char *p = (char *) buf;
00626 
00627   while (size-- != 0)
00628     if (*p++ != 0)
00629       return TRUE;
00630   return FALSE;
00631 }
00632 
00633 /* Swap out the contents of the auxiliary headers.  We create those
00634    auxiliary headers which have been set non-zero.  We do not require
00635    the caller to set up the stamp fields.  */
00636 
00637 static bfd_boolean
00638 nlm_swap_auxiliary_headers_out (bfd *abfd)
00639 {
00640   bfd_size_type amt;
00641 
00642   /* Write out the version header if there is one.  */
00643   if (find_nonzero (nlm_version_header (abfd),
00644                   sizeof (Nlm_Internal_Version_Header)))
00645     {
00646       Nlm_External_Version_Header thdr;
00647 
00648       LITMEMCPY (thdr.stamp, "VeRsIoN#");
00649       put_word (abfd, (bfd_vma) nlm_version_header (abfd)->majorVersion,
00650               (bfd_byte *) thdr.majorVersion);
00651       put_word (abfd, (bfd_vma) nlm_version_header (abfd)->minorVersion,
00652               (bfd_byte *) thdr.minorVersion);
00653       put_word (abfd, (bfd_vma) nlm_version_header (abfd)->revision,
00654               (bfd_byte *) thdr.revision);
00655       put_word (abfd, (bfd_vma) nlm_version_header (abfd)->year,
00656               (bfd_byte *) thdr.year);
00657       put_word (abfd, (bfd_vma) nlm_version_header (abfd)->month,
00658               (bfd_byte *) thdr.month);
00659       put_word (abfd, (bfd_vma) nlm_version_header (abfd)->day,
00660               (bfd_byte *) thdr.day);
00661       if (bfd_bwrite ((void *) &thdr, (bfd_size_type) sizeof (thdr), abfd)
00662          != sizeof (thdr))
00663        return FALSE;
00664     }
00665 
00666   /* Note - the CoPyRiGhT tag is emitted before the MeSsAgEs
00667      tag in order to make the NW4.x and NW5.x loaders happy.  */
00668 
00669   /* Write out the copyright header if there is one.  */
00670   if (find_nonzero (nlm_copyright_header (abfd),
00671                   sizeof (Nlm_Internal_Copyright_Header)))
00672     {
00673       Nlm_External_Copyright_Header thdr;
00674 
00675       LITMEMCPY (thdr.stamp, "CoPyRiGhT=");
00676       amt = sizeof (thdr.stamp);
00677       if (bfd_bwrite ((void *) thdr.stamp, amt, abfd) != amt)
00678        return FALSE;
00679       thdr.copyrightMessageLength[0] =
00680        nlm_copyright_header (abfd)->copyrightMessageLength;
00681       amt = 1;
00682       if (bfd_bwrite ((void *) thdr.copyrightMessageLength, amt, abfd) != amt)
00683        return FALSE;
00684       /* The copyright message is a variable length string.  */
00685       amt = nlm_copyright_header (abfd)->copyrightMessageLength + 1;
00686       if (bfd_bwrite ((void *) nlm_copyright_header (abfd)->copyrightMessage,
00687                    amt, abfd) != amt)
00688        return FALSE;
00689     }
00690 
00691   /* Write out the extended header if there is one.  */
00692   if (find_nonzero (nlm_extended_header (abfd),
00693                   sizeof (Nlm_Internal_Extended_Header)))
00694     {
00695       Nlm_External_Extended_Header thdr;
00696 
00697       LITMEMCPY (thdr.stamp, "MeSsAgEs");
00698       put_word (abfd,
00699               (bfd_vma) nlm_extended_header (abfd)->languageID,
00700               (bfd_byte *) thdr.languageID);
00701       put_word (abfd,
00702               (bfd_vma) nlm_extended_header (abfd)->messageFileOffset,
00703               (bfd_byte *) thdr.messageFileOffset);
00704       put_word (abfd,
00705               (bfd_vma) nlm_extended_header (abfd)->messageFileLength,
00706               (bfd_byte *) thdr.messageFileLength);
00707       put_word (abfd,
00708               (bfd_vma) nlm_extended_header (abfd)->messageCount,
00709               (bfd_byte *) thdr.messageCount);
00710       put_word (abfd,
00711               (bfd_vma) nlm_extended_header (abfd)->helpFileOffset,
00712               (bfd_byte *) thdr.helpFileOffset);
00713       put_word (abfd,
00714               (bfd_vma) nlm_extended_header (abfd)->helpFileLength,
00715               (bfd_byte *) thdr.helpFileLength);
00716       put_word (abfd,
00717               (bfd_vma) nlm_extended_header (abfd)->RPCDataOffset,
00718               (bfd_byte *) thdr.RPCDataOffset);
00719       put_word (abfd,
00720               (bfd_vma) nlm_extended_header (abfd)->RPCDataLength,
00721               (bfd_byte *) thdr.RPCDataLength);
00722       put_word (abfd,
00723               (bfd_vma) nlm_extended_header (abfd)->sharedCodeOffset,
00724               (bfd_byte *) thdr.sharedCodeOffset);
00725       put_word (abfd,
00726               (bfd_vma) nlm_extended_header (abfd)->sharedCodeLength,
00727               (bfd_byte *) thdr.sharedCodeLength);
00728       put_word (abfd,
00729               (bfd_vma) nlm_extended_header (abfd)->sharedDataOffset,
00730               (bfd_byte *) thdr.sharedDataOffset);
00731       put_word (abfd,
00732               (bfd_vma) nlm_extended_header (abfd)->sharedDataLength,
00733               (bfd_byte *) thdr.sharedDataLength);
00734       put_word (abfd,
00735          (bfd_vma) nlm_extended_header (abfd)->sharedRelocationFixupOffset,
00736               (bfd_byte *) thdr.sharedRelocationFixupOffset);
00737       put_word (abfd,
00738           (bfd_vma) nlm_extended_header (abfd)->sharedRelocationFixupCount,
00739               (bfd_byte *) thdr.sharedRelocationFixupCount);
00740       put_word (abfd,
00741        (bfd_vma) nlm_extended_header (abfd)->sharedExternalReferenceOffset,
00742               (bfd_byte *) thdr.sharedExternalReferenceOffset);
00743       put_word (abfd,
00744         (bfd_vma) nlm_extended_header (abfd)->sharedExternalReferenceCount,
00745               (bfd_byte *) thdr.sharedExternalReferenceCount);
00746       put_word (abfd,
00747               (bfd_vma) nlm_extended_header (abfd)->sharedPublicsOffset,
00748               (bfd_byte *) thdr.sharedPublicsOffset);
00749       put_word (abfd,
00750               (bfd_vma) nlm_extended_header (abfd)->sharedPublicsCount,
00751               (bfd_byte *) thdr.sharedPublicsCount);
00752       put_word (abfd,
00753              (bfd_vma) nlm_extended_header (abfd)->sharedDebugRecordOffset,
00754               (bfd_byte *) thdr.sharedDebugRecordOffset);
00755       put_word (abfd,
00756               (bfd_vma) nlm_extended_header (abfd)->sharedDebugRecordCount,
00757               (bfd_byte *) thdr.sharedDebugRecordCount);
00758       put_word (abfd,
00759           (bfd_vma) nlm_extended_header (abfd)->SharedInitializationOffset,
00760               (bfd_byte *) thdr.sharedInitializationOffset);
00761       put_word (abfd,
00762            (bfd_vma) nlm_extended_header (abfd)->SharedExitProcedureOffset,
00763               (bfd_byte *) thdr.SharedExitProcedureOffset);
00764       put_word (abfd,
00765               (bfd_vma) nlm_extended_header (abfd)->productID,
00766               (bfd_byte *) thdr.productID);
00767       put_word (abfd,
00768               (bfd_vma) nlm_extended_header (abfd)->reserved0,
00769               (bfd_byte *) thdr.reserved0);
00770       put_word (abfd,
00771               (bfd_vma) nlm_extended_header (abfd)->reserved1,
00772               (bfd_byte *) thdr.reserved1);
00773       put_word (abfd,
00774               (bfd_vma) nlm_extended_header (abfd)->reserved2,
00775               (bfd_byte *) thdr.reserved2);
00776       put_word (abfd,
00777               (bfd_vma) nlm_extended_header (abfd)->reserved3,
00778               (bfd_byte *) thdr.reserved3);
00779       put_word (abfd,
00780               (bfd_vma) nlm_extended_header (abfd)->reserved4,
00781               (bfd_byte *) thdr.reserved4);
00782       put_word (abfd,
00783               (bfd_vma) nlm_extended_header (abfd)->reserved5,
00784               (bfd_byte *) thdr.reserved5);
00785       if (bfd_bwrite ((void *) &thdr, (bfd_size_type) sizeof (thdr), abfd)
00786          != sizeof (thdr))
00787        return FALSE;
00788     }
00789 
00790   /* Write out the custom header if there is one.   */
00791   if (find_nonzero (nlm_custom_header (abfd),
00792                   sizeof (Nlm_Internal_Custom_Header)))
00793     {
00794       Nlm_External_Custom_Header thdr;
00795       bfd_boolean ds;
00796       bfd_size_type hdrLength;
00797 
00798       ds = find_nonzero (nlm_custom_header (abfd)->dataStamp,
00799                       sizeof (nlm_custom_header (abfd)->dataStamp));
00800       LITMEMCPY (thdr.stamp, "CuStHeAd");
00801       hdrLength = (2 * NLM_TARGET_LONG_SIZE + (ds ? 8 : 0)
00802                  + nlm_custom_header (abfd)->hdrLength);
00803       put_word (abfd, hdrLength, thdr.length);
00804       put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataOffset,
00805               thdr.dataOffset);
00806       put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataLength,
00807               thdr.dataLength);
00808       if (! ds)
00809        {
00810          BFD_ASSERT (nlm_custom_header (abfd)->hdrLength == 0);
00811          amt = sizeof (thdr) - sizeof (thdr.dataStamp);
00812          if (bfd_bwrite ((void *) &thdr, amt, abfd) != amt)
00813            return FALSE;
00814        }
00815       else
00816        {
00817          memcpy (thdr.dataStamp, nlm_custom_header (abfd)->dataStamp,
00818                 sizeof (thdr.dataStamp));
00819          amt = sizeof (thdr);
00820          if (bfd_bwrite ((void *) &thdr, amt, abfd) != amt)
00821            return FALSE;
00822          amt = nlm_custom_header (abfd)->hdrLength;
00823          if (bfd_bwrite (nlm_custom_header (abfd)->hdr, amt, abfd) != amt)
00824            return FALSE;
00825        }
00826     }
00827 
00828   /* Write out the Cygnus debugging header if there is one.  */
00829   if (find_nonzero (nlm_cygnus_ext_header (abfd),
00830                   sizeof (Nlm_Internal_Cygnus_Ext_Header)))
00831     {
00832       Nlm_External_Custom_Header thdr;
00833 
00834       LITMEMCPY (thdr.stamp, "CuStHeAd");
00835       put_word (abfd, (bfd_vma) 2 * NLM_TARGET_LONG_SIZE + 8,
00836               (bfd_byte *) thdr.length);
00837       put_word (abfd, (bfd_vma) nlm_cygnus_ext_header (abfd)->offset,
00838               (bfd_byte *) thdr.dataOffset);
00839       put_word (abfd, (bfd_vma) nlm_cygnus_ext_header (abfd)->length,
00840               (bfd_byte *) thdr.dataLength);
00841       LITMEMCPY (thdr.dataStamp, "CyGnUsEx");
00842       amt = sizeof (thdr);
00843       if (bfd_bwrite ((void *) &thdr, amt, abfd) != amt)
00844        return FALSE;
00845     }
00846 
00847   return TRUE;
00848 }
00849 
00850 /* We read the NLM's public symbols and use it to generate a bfd symbol
00851    table (hey, it's better than nothing) on a one-for-one basis.  Thus
00852    use the number of public symbols as the number of bfd symbols we will
00853    have once we actually get around to reading them in.
00854 
00855    Return the number of bytes required to hold the symtab vector, based on
00856    the count plus 1, since we will NULL terminate the vector allocated based
00857    on this size.  */
00858 
00859 long
00860 nlm_get_symtab_upper_bound (bfd *abfd)
00861 {
00862   Nlm_Internal_Fixed_Header *i_fxdhdrp;   /* Nlm file header, internal form.  */
00863   long symcount;
00864   long symtab_size = 0;
00865 
00866   i_fxdhdrp = nlm_fixed_header (abfd);
00867   symcount = (i_fxdhdrp->numberOfPublics
00868              + i_fxdhdrp->numberOfDebugRecords
00869              + i_fxdhdrp->numberOfExternalReferences);
00870   symtab_size = (symcount + 1) * (sizeof (asymbol));
00871   return symtab_size;
00872 }
00873 
00874 /* Slurp in nlm symbol table.
00875 
00876    In the external (in-file) form, NLM export records are variable length,
00877    with the following form:
00878 
00879        1 byte        length of the symbol name (N)
00880        N bytes              the symbol name
00881        4 bytes              the symbol offset from start of it's section
00882 
00883    We also read in the debugging symbols and import records.  Import
00884    records are treated as undefined symbols.  As we read the import
00885    records we also read in the associated reloc information, which is
00886    attached to the symbol.
00887 
00888    The bfd symbols are copied to SYMvoid *S.
00889 
00890    When we return, the bfd symcount is either zero or contains the correct
00891    number of symbols.  */
00892 
00893 static bfd_boolean
00894 nlm_slurp_symbol_table (bfd *abfd)
00895 {
00896   Nlm_Internal_Fixed_Header *i_fxdhdrp;   /* Nlm file header, internal form.  */
00897   bfd_size_type totsymcount;       /* Number of NLM symbols.  */
00898   bfd_size_type symcount;   /* Counter of NLM symbols.  */
00899   nlm_symbol_type *sym;            /* Pointer to current bfd symbol.  */
00900   unsigned char symlength;  /* Symbol length read into here.  */
00901   unsigned char symtype;    /* Type of debugging symbol.  */
00902   bfd_byte temp[NLM_TARGET_LONG_SIZE];    /* Symbol offsets read into here.  */
00903   bfd_boolean (*read_import_func) (bfd *, nlm_symbol_type *);
00904   bfd_boolean (*set_public_section_func) (bfd *, nlm_symbol_type *);
00905   bfd_size_type amt;
00906 
00907   if (nlm_get_symbols (abfd) != NULL)
00908     return TRUE;
00909 
00910   /* Read each raw NLM symbol, using the information to create a canonical bfd
00911      symbol table entry.
00912 
00913      Note that we allocate the initial bfd canonical symbol buffer based on a
00914      one-to-one mapping of the NLM symbols to canonical symbols.  We actually
00915      use all the NLM symbols, so there will be no space left over at the end.
00916      When we have all the symbols, we build the caller's pointer vector.  */
00917 
00918   abfd->symcount = 0;
00919   i_fxdhdrp = nlm_fixed_header (abfd);
00920   totsymcount = (i_fxdhdrp->numberOfPublics
00921                + i_fxdhdrp->numberOfDebugRecords
00922                + i_fxdhdrp->numberOfExternalReferences);
00923   if (totsymcount == 0)
00924     return TRUE;
00925 
00926   if (bfd_seek (abfd, i_fxdhdrp->publicsOffset, SEEK_SET) != 0)
00927     return FALSE;
00928 
00929   amt = totsymcount * sizeof (nlm_symbol_type);
00930   sym = bfd_zalloc (abfd, amt);
00931   if (!sym)
00932     return FALSE;
00933   nlm_set_symbols (abfd, sym);
00934 
00935   /* We use the bfd's symcount directly as the control count, so that early
00936      termination of the loop leaves the symcount correct for the symbols that
00937      were read.  */
00938 
00939   set_public_section_func = nlm_set_public_section_func (abfd);
00940   symcount = i_fxdhdrp->numberOfPublics;
00941   while (abfd->symcount < symcount)
00942     {
00943       amt = sizeof (symlength);
00944       if (bfd_bread ((void *) &symlength, amt, abfd) != amt)
00945        return FALSE;
00946       amt = symlength;
00947       sym->symbol.the_bfd = abfd;
00948       sym->symbol.name = bfd_alloc (abfd, amt + 1);
00949       if (!sym->symbol.name)
00950        return FALSE;
00951       if (bfd_bread ((void *) sym->symbol.name, amt, abfd) != amt)
00952        return FALSE;
00953       /* Cast away const.  */
00954       ((char *) (sym->symbol.name))[symlength] = '\0';
00955       amt = sizeof (temp);
00956       if (bfd_bread ((void *) temp, amt, abfd) != amt)
00957        return FALSE;
00958       sym->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
00959       sym->symbol.value = get_word (abfd, temp);
00960       if (set_public_section_func)
00961        {
00962          /* Most backends can use the code below, but unfortunately
00963             some use a different scheme.  */
00964          if (! (*set_public_section_func) (abfd, sym))
00965            return FALSE;
00966        }
00967       else
00968        {
00969          if (sym->symbol.value & NLM_HIBIT)
00970            {
00971              sym->symbol.value &= ~NLM_HIBIT;
00972              sym->symbol.flags |= BSF_FUNCTION;
00973              sym->symbol.section =
00974               bfd_get_section_by_name (abfd, NLM_CODE_NAME);
00975            }
00976          else
00977            sym->symbol.section =
00978              bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
00979        }
00980       sym->rcnt = 0;
00981       abfd->symcount++;
00982       sym++;
00983     }
00984 
00985   /* Read the debugging records.  */
00986 
00987   if (i_fxdhdrp->numberOfDebugRecords > 0)
00988     {
00989       if (bfd_seek (abfd, i_fxdhdrp->debugInfoOffset, SEEK_SET) != 0)
00990        return FALSE;
00991 
00992       symcount += i_fxdhdrp->numberOfDebugRecords;
00993       while (abfd->symcount < symcount)
00994        {
00995          amt = sizeof (symtype);
00996          if (bfd_bread ((void *) &symtype, amt, abfd) != amt)
00997            return FALSE;
00998          amt = sizeof (temp);
00999          if (bfd_bread ((void *) temp, amt, abfd) != amt)
01000            return FALSE;
01001          amt = sizeof (symlength);
01002          if (bfd_bread ((void *) &symlength, amt, abfd) != amt)
01003            return FALSE;
01004          amt = symlength;
01005          sym->symbol.the_bfd = abfd;
01006          sym->symbol.name = bfd_alloc (abfd, amt + 1);
01007          if (!sym->symbol.name)
01008            return FALSE;
01009          if (bfd_bread ((void *) sym->symbol.name, amt, abfd) != amt)
01010            return FALSE;
01011          /* Cast away const.  */
01012          ((char *) (sym->symbol.name))[symlength] = '\0';
01013          sym->symbol.flags = BSF_LOCAL;
01014          sym->symbol.value = get_word (abfd, temp);
01015 
01016          if (symtype == 0)
01017            sym->symbol.section =
01018              bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
01019          else if (symtype == 1)
01020            {
01021              sym->symbol.flags |= BSF_FUNCTION;
01022              sym->symbol.section =
01023               bfd_get_section_by_name (abfd, NLM_CODE_NAME);
01024            }
01025          else
01026            sym->symbol.section = bfd_abs_section_ptr;
01027 
01028          sym->rcnt = 0;
01029          abfd->symcount++;
01030          sym++;
01031        }
01032     }
01033 
01034   /* Read in the import records.  We can only do this if we know how
01035      to read relocs for this target.  */
01036   read_import_func = nlm_read_import_func (abfd);
01037   if (read_import_func != NULL)
01038     {
01039       if (bfd_seek (abfd, i_fxdhdrp->externalReferencesOffset, SEEK_SET) != 0)
01040        return FALSE;
01041 
01042       symcount += i_fxdhdrp->numberOfExternalReferences;
01043       while (abfd->symcount < symcount)
01044        {
01045          if (! (*read_import_func) (abfd, sym))
01046            return FALSE;
01047          sym++;
01048          abfd->symcount++;
01049        }
01050     }
01051 
01052   return TRUE;
01053 }
01054 
01055 /* Note that bfd_get_symcount is guaranteed to be zero if slurping the
01056    symbol table fails.  */
01057 
01058 long
01059 nlm_canonicalize_symtab (bfd *abfd, asymbol **alocation)
01060 {
01061   nlm_symbol_type *symbase;
01062   bfd_size_type counter = 0;
01063 
01064   if (! nlm_slurp_symbol_table (abfd))
01065     return -1;
01066   symbase = nlm_get_symbols (abfd);
01067   while (counter < bfd_get_symcount (abfd))
01068     {
01069       *alocation++ = &symbase->symbol;
01070       symbase++;
01071       counter++;
01072     }
01073   *alocation = NULL;
01074   return bfd_get_symcount (abfd);
01075 }
01076 
01077 /* Make an NLM symbol.  There is nothing special to do here.  */
01078 
01079 asymbol *
01080 nlm_make_empty_symbol (bfd *abfd)
01081 {
01082   bfd_size_type amt = sizeof (nlm_symbol_type);
01083   nlm_symbol_type *new = bfd_zalloc (abfd, amt);
01084 
01085   if (new == NULL)
01086     return NULL;
01087   new->symbol.the_bfd = abfd;
01088   return & new->symbol;
01089 }
01090 
01091 /* Get symbol information.  */
01092 
01093 void
01094 nlm_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
01095                    asymbol *symbol,
01096                    symbol_info *ret)
01097 {
01098   bfd_symbol_info (symbol, ret);
01099 }
01100 
01101 /* Print symbol information.  */
01102 
01103 void
01104 nlm_print_symbol (bfd *abfd,
01105                 void * afile,
01106                 asymbol *symbol,
01107                 bfd_print_symbol_type how)
01108 {
01109   FILE *file = (FILE *) afile;
01110 
01111   switch (how)
01112     {
01113     case bfd_print_symbol_name:
01114     case bfd_print_symbol_more:
01115       if (symbol->name)
01116        fprintf (file, "%s", symbol->name);
01117       break;
01118     case bfd_print_symbol_all:
01119       bfd_print_symbol_vandf (abfd, (void *) file, symbol);
01120       fprintf (file, " %-5s", symbol->section->name);
01121       if (symbol->name)
01122        fprintf (file, " %s", symbol->name);
01123       break;
01124     }
01125 }
01126 
01127 /* Get the relocs for an NLM file.  There are two types of relocs.
01128    Imports are relocs against symbols defined in other NLM files.  We
01129    treat these as relocs against global symbols.  Relocation fixups
01130    are internal relocs.
01131 
01132    The actual format used to store the relocs is machine specific.  */
01133 
01134 /* Read in the relocation fixup information.  This is stored in
01135    nlm_relocation_fixups, an array of arelent structures, and
01136    nlm_relocation_fixup_secs, an array of section pointers.  The
01137    section pointers are needed because the relocs are not sorted by
01138    section.  */
01139 
01140 static bfd_boolean
01141 nlm_slurp_reloc_fixups (bfd *abfd)
01142 {
01143   bfd_boolean (*read_func) (bfd *, nlm_symbol_type *, asection **, arelent *);
01144   bfd_size_type count, amt;
01145   arelent *rels;
01146   asection **secs;
01147 
01148   if (nlm_relocation_fixups (abfd) != NULL)
01149     return TRUE;
01150   read_func = nlm_read_reloc_func (abfd);
01151   if (read_func == NULL)
01152     return TRUE;
01153 
01154   if (bfd_seek (abfd, nlm_fixed_header (abfd)->relocationFixupOffset,
01155               SEEK_SET) != 0)
01156     return FALSE;
01157 
01158   count = nlm_fixed_header (abfd)->numberOfRelocationFixups;
01159   amt = count * sizeof (arelent);
01160   rels = bfd_alloc (abfd, amt);
01161   amt = count * sizeof (asection *);
01162   secs = bfd_alloc (abfd, amt);
01163   if ((rels == NULL || secs == NULL) && count != 0)
01164     return FALSE;
01165   nlm_relocation_fixups (abfd) = rels;
01166   nlm_relocation_fixup_secs (abfd) = secs;
01167 
01168   /* We have to read piece by piece, because we don't know how large
01169      the machine specific reloc information is.  */
01170   while (count-- != 0)
01171     {
01172       if (! (*read_func) (abfd, NULL, secs, rels))
01173        {
01174          nlm_relocation_fixups (abfd) = NULL;
01175          nlm_relocation_fixup_secs (abfd) = NULL;
01176          return FALSE;
01177        }
01178       ++secs;
01179       ++rels;
01180     }
01181 
01182   return TRUE;
01183 }
01184 
01185 /* Get the number of relocs.  This really just returns an upper bound,
01186    since it does not attempt to distinguish them based on the section.
01187    That will be handled when they are actually read.  */
01188 
01189 long
01190 nlm_get_reloc_upper_bound (bfd *abfd, asection *sec)
01191 {
01192   nlm_symbol_type *syms;
01193   bfd_size_type count;
01194   unsigned int ret;
01195 
01196   /* If we don't know how to read relocs, just return 0.  */
01197   if (nlm_read_reloc_func (abfd) == NULL)
01198     return -1;
01199   /* Make sure we have either the code or the data section.  */
01200   if ((bfd_get_section_flags (abfd, sec) & (SEC_CODE | SEC_DATA)) == 0)
01201     return 0;
01202 
01203   syms = nlm_get_symbols (abfd);
01204   if (syms == NULL)
01205     {
01206       if (! nlm_slurp_symbol_table (abfd))
01207        return -1;
01208       syms = nlm_get_symbols (abfd);
01209     }
01210 
01211   ret = nlm_fixed_header (abfd)->numberOfRelocationFixups;
01212 
01213   count = bfd_get_symcount (abfd);
01214   while (count-- != 0)
01215     {
01216       ret += syms->rcnt;
01217       ++syms;
01218     }
01219 
01220   return (ret + 1) * sizeof (arelent *);
01221 }
01222 
01223 /* Get the relocs themselves.  */
01224 
01225 long
01226 nlm_canonicalize_reloc (bfd *abfd,
01227                      asection *sec,
01228                      arelent **relptr,
01229                      asymbol **symbols)
01230 {
01231   arelent *rels;
01232   asection **secs;
01233   bfd_size_type count, i;
01234   long ret;
01235 
01236   /* Get the relocation fixups.  */
01237   rels = nlm_relocation_fixups (abfd);
01238   if (rels == NULL)
01239     {
01240       if (! nlm_slurp_reloc_fixups (abfd))
01241        return -1;
01242       rels = nlm_relocation_fixups (abfd);
01243     }
01244   secs = nlm_relocation_fixup_secs (abfd);
01245 
01246   ret = 0;
01247   count = nlm_fixed_header (abfd)->numberOfRelocationFixups;
01248   for (i = 0; i < count; i++, rels++, secs++)
01249     {
01250       if (*secs == sec)
01251        {
01252          *relptr++ = rels;
01253          ++ret;
01254        }
01255     }
01256 
01257   /* Get the import symbols.  */
01258   count = bfd_get_symcount (abfd);
01259   for (i = 0; i < count; i++, symbols++)
01260     {
01261       asymbol *sym;
01262 
01263       sym = *symbols;
01264       if (bfd_asymbol_flavour (sym) == bfd_target_nlm_flavour)
01265        {
01266          nlm_symbol_type *nlm_sym;
01267          bfd_size_type j;
01268 
01269          nlm_sym = (nlm_symbol_type *) sym;
01270          for (j = 0; j < nlm_sym->rcnt; j++)
01271            {
01272              if (nlm_sym->relocs[j].section == sec)
01273               {
01274                 *relptr = &nlm_sym->relocs[j].reloc;
01275                 (*relptr)->sym_ptr_ptr = symbols;
01276                 ++relptr;
01277                 ++ret;
01278               }
01279            }
01280        }
01281     }
01282 
01283   *relptr = NULL;
01284 
01285   return ret;
01286 }
01287 
01288 /* Compute the section file positions for an NLM file.  All variable
01289    length data in the file headers must be set before this function is
01290    called.  If the variable length data is changed later, the
01291    resulting object file will be incorrect.  Unfortunately, there is
01292    no way to check this.
01293 
01294    This routine also sets the Size and Offset fields in the fixed
01295    header.
01296 
01297    It also looks over the symbols and moves any common symbols into
01298    the .bss section; NLM has no way to represent a common symbol.
01299    This approach means that either the symbols must already have been
01300    set at this point, or there must be no common symbols.  We need to
01301    move the symbols at this point so that mangle_relocs can see the
01302    final values.  */
01303 
01304 static bfd_boolean
01305 nlm_compute_section_file_positions (bfd *abfd)
01306 {
01307   file_ptr sofar;
01308   asection *sec;
01309   bfd_vma text, data, bss;
01310   bfd_vma text_low, data_low;
01311   unsigned int text_align, data_align, other_align;
01312   file_ptr text_ptr, data_ptr, other_ptr;
01313   asection *bss_sec;
01314   asymbol **sym_ptr_ptr;
01315 
01316   if (abfd->output_has_begun)
01317     return TRUE;
01318 
01319   /* Make sure we have a section to hold uninitialized data.  */
01320   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
01321   if (bss_sec == NULL)
01322     {
01323       if (!add_bfd_section (abfd, NLM_UNINITIALIZED_DATA_NAME,
01324                          (file_ptr) 0, (bfd_size_type) 0,
01325                          SEC_ALLOC))
01326        return FALSE;
01327       bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
01328     }
01329 
01330   abfd->output_has_begun = TRUE;
01331 
01332   /* The fixed header.  */
01333   sofar = nlm_optional_prefix_size (abfd) + nlm_fixed_header_size (abfd);
01334 
01335   /* The variable header.  */
01336   sofar += (sizeof (nlm_variable_header (abfd)->descriptionLength)
01337            + nlm_variable_header (abfd)->descriptionLength + 1
01338            + NLM_TARGET_LONG_SIZE  /* stackSize */
01339            + NLM_TARGET_LONG_SIZE  /* reserved */
01340            + sizeof (nlm_variable_header (abfd)->oldThreadName)
01341            + sizeof (nlm_variable_header (abfd)->screenNameLength)
01342            + nlm_variable_header (abfd)->screenNameLength + 1
01343            + sizeof (nlm_variable_header (abfd)->threadNameLength)
01344            + nlm_variable_header (abfd)->threadNameLength + 1);
01345 
01346   /* The auxiliary headers.  */
01347   if (find_nonzero (nlm_version_header (abfd),
01348                   sizeof (Nlm_Internal_Version_Header)))
01349     sofar += sizeof (Nlm_External_Version_Header);
01350   if (find_nonzero (nlm_extended_header (abfd),
01351                   sizeof (Nlm_Internal_Extended_Header)))
01352     sofar += sizeof (Nlm_External_Extended_Header);
01353   if (find_nonzero (nlm_copyright_header (abfd),
01354                   sizeof (Nlm_Internal_Copyright_Header)))
01355     sofar += (sizeof (Nlm_External_Copyright_Header)
01356              + nlm_copyright_header (abfd)->copyrightMessageLength + 1);
01357   if (find_nonzero (nlm_custom_header (abfd),
01358                   sizeof (Nlm_Internal_Custom_Header)))
01359     sofar += (sizeof (Nlm_External_Custom_Header)
01360              + nlm_custom_header (abfd)->hdrLength);
01361   if (find_nonzero (nlm_cygnus_ext_header (abfd),
01362                   sizeof (Nlm_Internal_Cygnus_Ext_Header)))
01363     sofar += sizeof (Nlm_External_Custom_Header);
01364 
01365   /* Compute the section file positions in two passes.  First get the
01366      sizes of the text and data sections, and then set the file
01367      positions.  This code aligns the sections in the file using the
01368      same alignment restrictions that apply to the sections in memory;
01369      this may not be necessary.  */
01370   text = 0;
01371   text_low = (bfd_vma) - 1;
01372   text_align = 0;
01373   data = 0;
01374   data_low = (bfd_vma) - 1;
01375   data_align = 0;
01376   bss = 0;
01377   other_align = 0;
01378   for (sec = abfd->sections; sec != NULL; sec = sec->next)
01379     {
01380       flagword f;
01381 
01382       sec->size = BFD_ALIGN (sec->size, 1 << sec->alignment_power);
01383 
01384       f = bfd_get_section_flags (abfd, sec);
01385       if (f & SEC_CODE)
01386        {
01387          text += sec->size;
01388          if (bfd_get_section_vma (abfd, sec) < text_low)
01389            text_low = bfd_get_section_vma (abfd, sec);
01390          if (sec->alignment_power > text_align)
01391            text_align = sec->alignment_power;
01392        }
01393       else if (f & SEC_DATA)
01394        {
01395          data += sec->size;
01396          if (bfd_get_section_vma (abfd, sec) < data_low)
01397            data_low = bfd_get_section_vma (abfd, sec);
01398          if (sec->alignment_power > data_align)
01399            data_align = sec->alignment_power;
01400        }
01401       else if (f & SEC_HAS_CONTENTS)
01402        {
01403          if (sec->alignment_power > other_align)
01404            other_align = sec->alignment_power;
01405        }
01406       else if (f & SEC_ALLOC)
01407        bss += sec->size;
01408     }
01409 
01410   nlm_set_text_low (abfd, text_low);
01411   nlm_set_data_low (abfd, data_low);
01412 
01413   if (nlm_no_uninitialized_data (abfd))
01414     {
01415       /* This NetWare format does not use uninitialized data.  We must
01416         increase the size of the data section.  We will never wind up
01417         writing those file locations, so they will remain zero.  */
01418       data += bss;
01419       bss = 0;
01420     }
01421 
01422   text_ptr = BFD_ALIGN (sofar, 1 << text_align);
01423   data_ptr = BFD_ALIGN (text_ptr + text, 1 << data_align);
01424   other_ptr = BFD_ALIGN (data_ptr + data, 1 << other_align);
01425 
01426   /* Fill in some fields in the header for which we now have the
01427      information.  */
01428   nlm_fixed_header (abfd)->codeImageOffset = text_ptr;
01429   nlm_fixed_header (abfd)->codeImageSize = text;
01430   nlm_fixed_header (abfd)->dataImageOffset = data_ptr;
01431   nlm_fixed_header (abfd)->dataImageSize = data;
01432   nlm_fixed_header (abfd)->uninitializedDataSize = bss;
01433 
01434   for (sec = abfd->sections; sec != NULL; sec = sec->next)
01435     {
01436       flagword f;
01437 
01438       f = bfd_get_section_flags (abfd, sec);
01439 
01440       if (f & SEC_CODE)
01441        {
01442          sec->filepos = text_ptr;
01443          text_ptr += sec->size;
01444        }
01445       else if (f & SEC_DATA)
01446        {
01447          sec->filepos = data_ptr;
01448          data_ptr += sec->size;
01449        }
01450       else if (f & SEC_HAS_CONTENTS)
01451        {
01452          sec->filepos = other_ptr;
01453          other_ptr += sec->size;
01454        }
01455     }
01456 
01457   nlm_fixed_header (abfd)->relocationFixupOffset = other_ptr;
01458 
01459   /* Move all common symbols into the .bss section.  */
01460 
01461   sym_ptr_ptr = bfd_get_outsymbols (abfd);
01462   if (sym_ptr_ptr != NULL)
01463     {
01464       asymbol **sym_end;
01465       bfd_vma add;
01466 
01467       sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
01468       add = 0;
01469       for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
01470        {
01471          asymbol *sym;
01472          bfd_vma size;
01473 
01474          sym = *sym_ptr_ptr;
01475 
01476          if (!bfd_is_com_section (bfd_get_section (sym)))
01477            continue;
01478 
01479          /* Put the common symbol in the .bss section, and increase
01480             the size of the .bss section by the size of the common
01481             symbol (which is the old value of the symbol).  */
01482          sym->section = bss_sec;
01483          size = sym->value;
01484          sym->value = bss_sec->size + add;
01485          add += size;
01486          add = BFD_ALIGN (add, 1 << bss_sec->alignment_power);
01487        }
01488       if (add != 0)
01489        {
01490          if (nlm_no_uninitialized_data (abfd))
01491            {
01492              /* We could handle this case, but so far it hasn't been
01493                necessary.  */
01494              abort ();
01495            }
01496          nlm_fixed_header (abfd)->uninitializedDataSize += add;
01497          bss_sec->size += add;
01498        }
01499     }
01500 
01501   return TRUE;
01502 }
01503 
01504 /* Set the contents of a section.  To do this we need to know where
01505    the section is going to be located in the output file.  That means
01506    that the sizes of all the sections must be set, and all the
01507    variable size header information must be known.  */
01508 
01509 bfd_boolean
01510 nlm_set_section_contents (bfd *abfd,
01511                        asection *section,
01512                        const void * location,
01513                        file_ptr offset,
01514                        bfd_size_type count)
01515 {
01516   if (! abfd->output_has_begun
01517       && ! nlm_compute_section_file_positions (abfd))
01518     return FALSE;
01519 
01520   if (count == 0)
01521     return TRUE;
01522 
01523   /* i386 NetWare has a very restricted set of relocs.  In order for
01524      objcopy to work, the NLM i386 backend needs a chance to rework
01525      the section contents so that its set of relocs will work.  If all
01526      the relocs are already acceptable, this will not do anything.  */
01527   if (section->reloc_count != 0)
01528     {
01529       bfd_boolean (*mangle_relocs_func)
01530        (bfd *, asection *, const void *, bfd_vma, bfd_size_type);
01531 
01532       mangle_relocs_func = nlm_mangle_relocs_func (abfd);
01533       if (mangle_relocs_func != NULL)
01534        {
01535          if (!(*mangle_relocs_func) (abfd, section, location,
01536                                   (bfd_vma) offset, count))
01537            return FALSE;
01538        }
01539     }
01540 
01541   if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
01542       || bfd_bwrite (location, count, abfd) != count)
01543     return FALSE;
01544 
01545   return TRUE;
01546 }
01547 
01548 /* We need to sort a list of relocs associated with sections when we
01549    write out the external relocs.  */
01550 
01551 static int
01552 nlm_external_reloc_compare (const void *p1, const void *p2)
01553 {
01554   const struct reloc_and_sec *r1 = (const struct reloc_and_sec *) p1;
01555   const struct reloc_and_sec *r2 = (const struct reloc_and_sec *) p2;
01556   int cmp;
01557 
01558   cmp = strcmp ((*r1->rel->sym_ptr_ptr)->name,
01559               (*r2->rel->sym_ptr_ptr)->name);
01560   if (cmp != 0)
01561     return cmp;
01562 
01563   /* We sort by address within symbol to make the sort more stable and
01564      increase the chances that different hosts will generate bit for
01565      bit equivalent results.  */
01566   return (int) (r1->rel->address - r2->rel->address);
01567 }
01568 
01569 /* Write out an NLM file.  We write out the information in this order:
01570      fixed header
01571      variable header
01572      auxiliary headers
01573      code sections
01574      data sections
01575      other sections (custom data, messages, help, shared NLM, RPC,
01576                    module dependencies)
01577      relocation fixups
01578      external references (imports)
01579      public symbols (exports)
01580      debugging records
01581    This is similar to the order used by the NetWare tools; the
01582    difference is that NetWare puts the sections other than code, data
01583    and custom data at the end of the NLM.  It is convenient for us to
01584    know where the sections are going to be before worrying about the
01585    size of the other information.
01586 
01587    By the time this function is called, all the section data should
01588    have been output using set_section_contents.  Note that custom
01589    data, the message file, the help file, the shared NLM file, the RPC
01590    data, and the module dependencies are all considered to be
01591    sections; the caller is responsible for filling in the offset and
01592    length fields in the NLM headers.  The relocation fixups and
01593    imports are both obtained from the list of relocs attached to each
01594    section.  The exports and debugging records are obtained from the
01595    list of outsymbols.  */
01596 
01597 bfd_boolean
01598 nlm_write_object_contents (bfd *abfd)
01599 {
01600   asection *sec;
01601   bfd_boolean (*write_import_func) (bfd *, asection *, arelent *);
01602   bfd_size_type external_reloc_count, internal_reloc_count, i, c;
01603   struct reloc_and_sec *external_relocs;
01604   asymbol **sym_ptr_ptr;
01605   file_ptr last;
01606   bfd_boolean (*write_prefix_func) (bfd *);
01607   unsigned char *fixed_header = NULL;
01608   file_ptr pos;
01609   bfd_size_type amt;
01610 
01611   fixed_header = bfd_malloc (nlm_fixed_header_size (abfd));
01612   if (fixed_header == NULL)
01613     goto error_return;
01614 
01615   if (! abfd->output_has_begun
01616       && ! nlm_compute_section_file_positions (abfd))
01617     goto error_return;
01618 
01619   /* Write out the variable length headers.  */
01620   pos = nlm_optional_prefix_size (abfd) + nlm_fixed_header_size (abfd);
01621   if (bfd_seek (abfd, pos, SEEK_SET) != 0)
01622     goto error_return;
01623   if (! nlm_swap_variable_header_out (abfd)
01624       || ! nlm_swap_auxiliary_headers_out (abfd))
01625     {
01626       bfd_set_error (bfd_error_system_call);
01627       goto error_return;
01628     }
01629 
01630   /* A weak check on whether the section file positions were
01631      reasonable.  */
01632   if (bfd_tell (abfd) > nlm_fixed_header (abfd)->codeImageOffset)
01633     {
01634       bfd_set_error (bfd_error_invalid_operation);
01635       goto error_return;
01636     }
01637 
01638   /* Advance to the relocs.  */
01639   if (bfd_seek (abfd, nlm_fixed_header (abfd)->relocationFixupOffset,
01640               SEEK_SET) != 0)
01641     goto error_return;
01642 
01643   /* The format of the relocation entries is dependent upon the
01644      particular target.  We use an external routine to write the reloc
01645      out.  */
01646   write_import_func = nlm_write_import_func (abfd);
01647 
01648   /* Write out the internal relocation fixups.  While we're looping
01649      over the relocs, we also count the external relocs, which is
01650      needed when they are written out below.  */
01651   internal_reloc_count = 0;
01652   external_reloc_count = 0;
01653   for (sec = abfd->sections; sec != NULL; sec = sec->next)
01654     {
01655       arelent **rel_ptr_ptr, **rel_end;
01656 
01657       if (sec->reloc_count == 0)
01658        continue;
01659 
01660       /* We can only represent relocs within a code or data
01661         section.  We ignore them for a debugging section.  */
01662       if ((bfd_get_section_flags (abfd, sec) & (SEC_CODE | SEC_DATA)) == 0)
01663        continue;
01664 
01665       /* We need to know how to write out imports */
01666       if (write_import_func == NULL)
01667        {
01668          bfd_set_error (bfd_error_invalid_operation);
01669          goto error_return;
01670        }
01671 
01672       rel_ptr_ptr = sec->orelocation;
01673       rel_end = rel_ptr_ptr + sec->reloc_count;
01674       for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++)
01675        {
01676          arelent *rel;
01677          asymbol *sym;
01678 
01679          rel = *rel_ptr_ptr;
01680          sym = *rel->sym_ptr_ptr;
01681 
01682          if (! bfd_is_und_section (bfd_get_section (sym)))
01683            {
01684              ++internal_reloc_count;
01685              if (! (*write_import_func) (abfd, sec, rel))
01686               goto error_return;
01687            }
01688          else
01689            ++external_reloc_count;
01690        }
01691     }
01692   nlm_fixed_header (abfd)->numberOfRelocationFixups = internal_reloc_count;
01693 
01694   /* Write out the imports (relocs against external symbols).  These
01695      are output as a symbol name followed by all the relocs for that
01696      symbol, so we must first gather together all the relocs against
01697      external symbols and sort them.  */
01698   amt = external_reloc_count * sizeof (struct reloc_and_sec);
01699   external_relocs = bfd_alloc (abfd, amt);
01700   if (external_relocs == NULL)
01701     goto error_return;
01702   i = 0;
01703   for (sec = abfd->sections; sec != NULL; sec = sec->next)
01704     {
01705       arelent **rel_ptr_ptr, **rel_end;
01706 
01707       if (sec->reloc_count == 0)
01708        continue;
01709 
01710       rel_ptr_ptr = sec->orelocation;
01711       rel_end = rel_ptr_ptr + sec->reloc_count;
01712       for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++)
01713        {
01714          arelent *rel;
01715          asymbol *sym;
01716 
01717          rel = *rel_ptr_ptr;
01718          sym = *rel->sym_ptr_ptr;
01719 
01720          if (! bfd_is_und_section (bfd_get_section (sym)))
01721            continue;
01722 
01723          external_relocs[i].rel = rel;
01724          external_relocs[i].sec = sec;
01725          ++i;
01726        }
01727     }
01728 
01729   BFD_ASSERT (i == external_reloc_count);
01730 
01731   /* Sort the external relocs by name.  */
01732   qsort (external_relocs, (size_t) external_reloc_count,
01733         sizeof (struct reloc_and_sec), nlm_external_reloc_compare);
01734 
01735   /* Write out the external relocs.  */
01736   nlm_fixed_header (abfd)->externalReferencesOffset = bfd_tell (abfd);
01737   c = 0;
01738   i = 0;
01739   while (i < external_reloc_count)
01740     {
01741       arelent *rel;
01742       asymbol *sym;
01743       bfd_size_type j, cnt;
01744 
01745       ++c;
01746 
01747       rel = external_relocs[i].rel;
01748       sym = *rel->sym_ptr_ptr;
01749 
01750       cnt = 0;
01751       for (j = i;
01752           (j < external_reloc_count
01753            && *external_relocs[j].rel->sym_ptr_ptr == sym);
01754           j++)
01755        ++cnt;
01756 
01757       if (! (*nlm_write_external_func (abfd)) (abfd, cnt, sym,
01758                                           &external_relocs[i]))
01759        goto error_return;
01760 
01761       i += cnt;
01762     }
01763 
01764   nlm_fixed_header (abfd)->numberOfExternalReferences = c;
01765 
01766   /* Write out the public symbols (exports).  */
01767   sym_ptr_ptr = bfd_get_outsymbols (abfd);
01768   if (sym_ptr_ptr != NULL)
01769     {
01770       bfd_vma (*get_public_offset_func) (bfd *, asymbol *);
01771       bfd_boolean (*write_export_func) (bfd *, asymbol *, bfd_vma);
01772 
01773       asymbol **sym_end;
01774 
01775       nlm_fixed_header (abfd)->publicsOffset = bfd_tell (abfd);
01776       get_public_offset_func = nlm_get_public_offset_func (abfd);
01777       write_export_func = nlm_write_export_func (abfd);
01778       c = 0;
01779       sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
01780       for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
01781        {
01782          asymbol *sym;
01783          bfd_byte len;
01784          bfd_vma offset;
01785          bfd_byte temp[NLM_TARGET_LONG_SIZE];
01786 
01787          sym = *sym_ptr_ptr;
01788 
01789          if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) == 0
01790              || bfd_is_und_section (bfd_get_section (sym)))
01791            continue;
01792 
01793          ++c;
01794 
01795          if (get_public_offset_func)
01796            {
01797              /* Most backends can use the code below, but
01798                unfortunately some use a different scheme.  */
01799              offset = (*get_public_offset_func) (abfd, sym);
01800            }
01801          else
01802            {
01803              offset = bfd_asymbol_value (sym);
01804              sec = sym->section;
01805              if (sec->flags & SEC_CODE)
01806               {
01807                 offset -= nlm_get_text_low (abfd);
01808                 offset |= NLM_HIBIT;
01809               }
01810              else if (sec->flags & (SEC_DATA | SEC_ALLOC))
01811               {
01812                 /* SEC_ALLOC is for the .bss section.  */
01813                 offset -= nlm_get_data_low (abfd);
01814               }
01815              else
01816               {
01817                 /* We can't handle an exported symbol that is not in
01818                    the code or data segment.  */
01819                 bfd_set_error (bfd_error_invalid_operation);
01820                 goto error_return;
01821               }
01822            }
01823 
01824          if (write_export_func)
01825            {
01826              if (! (*write_export_func) (abfd, sym, offset))
01827               goto error_return;
01828            }
01829          else
01830            {
01831              len = strlen (sym->name);
01832              if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
01833                  != sizeof (bfd_byte))
01834                 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
01835               goto error_return;
01836 
01837              put_word (abfd, offset, temp);
01838              if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd)
01839                 != sizeof (temp))
01840               goto error_return;
01841            }
01842        }
01843       nlm_fixed_header (abfd)->numberOfPublics = c;
01844 
01845       /* Write out the debugging records.  The NLM conversion program
01846         wants to be able to inhibit this, so as a special hack if
01847         debugInfoOffset is set to -1 we don't write any debugging
01848         information.  This can not be handled by fiddling with the
01849         symbol table, because exported symbols appear in both the
01850         exported symbol list and the debugging information.  */
01851       if (nlm_fixed_header (abfd)->debugInfoOffset == (file_ptr) - 1)
01852        {
01853          nlm_fixed_header (abfd)->debugInfoOffset = 0;
01854          nlm_fixed_header (abfd)->numberOfDebugRecords = 0;
01855        }
01856       else
01857        {
01858          nlm_fixed_header (abfd)->debugInfoOffset = bfd_tell (abfd);
01859          c = 0;
01860          sym_ptr_ptr = bfd_get_outsymbols (abfd);
01861          sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
01862          for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
01863            {
01864              asymbol *sym;
01865              bfd_byte type, len;
01866              bfd_vma offset;
01867              bfd_byte temp[NLM_TARGET_LONG_SIZE];
01868 
01869              sym = *sym_ptr_ptr;
01870 
01871              /* The NLM notion of a debugging symbol is actually what
01872                BFD calls a local or global symbol.  What BFD calls a
01873                debugging symbol NLM does not understand at all.  */
01874              if ((sym->flags & (BSF_LOCAL | BSF_GLOBAL | BSF_EXPORT)) == 0
01875                 || (sym->flags & BSF_DEBUGGING) != 0
01876                 || bfd_is_und_section (bfd_get_section (sym)))
01877               continue;
01878 
01879              ++c;
01880 
01881              offset = bfd_asymbol_value (sym);
01882              sec = sym->section;
01883              if (sec->flags & SEC_CODE)
01884               {
01885                 offset -= nlm_get_text_low (abfd);
01886                 type = 1;
01887               }
01888              else if (sec->flags & (SEC_DATA | SEC_ALLOC))
01889               {
01890                 /* SEC_ALLOC is for the .bss section.  */
01891                 offset -= nlm_get_data_low (abfd);
01892                 type = 0;
01893               }
01894              else
01895               type = 2;
01896 
01897              /* The type is 0 for data, 1 for code, 2 for absolute.  */
01898              if (bfd_bwrite (&type, (bfd_size_type) sizeof (bfd_byte), abfd)
01899                 != sizeof (bfd_byte))
01900               goto error_return;
01901 
01902              put_word (abfd, offset, temp);
01903              if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd)
01904                 != sizeof (temp))
01905               goto error_return;
01906 
01907              len = strlen (sym->name);
01908              if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
01909                  != sizeof (bfd_byte))
01910                 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
01911               goto error_return;
01912            }
01913          nlm_fixed_header (abfd)->numberOfDebugRecords = c;
01914        }
01915     }
01916 
01917   /* NLMLINK fills in offset values even if there is no data, so we do
01918      the same.  */
01919   last = bfd_tell (abfd);
01920   if (nlm_fixed_header (abfd)->codeImageOffset == 0)
01921     nlm_fixed_header (abfd)->codeImageOffset = last;
01922   if (nlm_fixed_header (abfd)->dataImageOffset == 0)
01923     nlm_fixed_header (abfd)->dataImageOffset = last;
01924   if (nlm_fixed_header (abfd)->customDataOffset == 0)
01925     nlm_fixed_header (abfd)->customDataOffset = last;
01926   if (nlm_fixed_header (abfd)->moduleDependencyOffset == 0)
01927     nlm_fixed_header (abfd)->moduleDependencyOffset = last;
01928   if (nlm_fixed_header (abfd)->relocationFixupOffset == 0)
01929     nlm_fixed_header (abfd)->relocationFixupOffset = last;
01930   if (nlm_fixed_header (abfd)->externalReferencesOffset == 0)
01931     nlm_fixed_header (abfd)->externalReferencesOffset = last;
01932   if (nlm_fixed_header (abfd)->publicsOffset == 0)
01933     nlm_fixed_header (abfd)->publicsOffset = last;
01934   if (nlm_fixed_header (abfd)->debugInfoOffset == 0)
01935     nlm_fixed_header (abfd)->debugInfoOffset = last;
01936 
01937   /* At this point everything has been written out except the fixed
01938      header.  */
01939   memcpy (nlm_fixed_header (abfd)->signature, nlm_signature (abfd),
01940          NLM_SIGNATURE_SIZE);
01941   nlm_fixed_header (abfd)->version = NLM_HEADER_VERSION;
01942   nlm_fixed_header (abfd)->codeStartOffset =
01943     (bfd_get_start_address (abfd)
01944      - nlm_get_text_low (abfd));
01945 
01946   /* We have no convenient way for the caller to pass in the exit
01947      procedure or the check unload procedure, so the caller must set
01948      the values in the header to the values of the symbols.  */
01949   nlm_fixed_header (abfd)->exitProcedureOffset -= nlm_get_text_low (abfd);
01950   if (nlm_fixed_header (abfd)->checkUnloadProcedureOffset != 0)
01951     nlm_fixed_header (abfd)->checkUnloadProcedureOffset -=
01952       nlm_get_text_low (abfd);
01953 
01954   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
01955     goto error_return;
01956 
01957   write_prefix_func = nlm_write_prefix_func (abfd);
01958   if (write_prefix_func)
01959     {
01960       if (! (*write_prefix_func) (abfd))
01961        goto error_return;
01962     }
01963 
01964   BFD_ASSERT ((bfd_size_type) bfd_tell (abfd)
01965              == nlm_optional_prefix_size (abfd));
01966 
01967   nlm_swap_fixed_header_out (abfd, nlm_fixed_header (abfd), fixed_header);
01968   if (bfd_bwrite (fixed_header, nlm_fixed_header_size (abfd), abfd)
01969       != nlm_fixed_header_size (abfd))
01970     goto error_return;
01971 
01972   if (fixed_header != NULL)
01973     free (fixed_header);
01974   return TRUE;
01975 
01976 error_return:
01977   if (fixed_header != NULL)
01978     free (fixed_header);
01979   return FALSE;
01980 }