+ else
+ {
+ memcpy (nlm_custom_header (abfd)->stamp, thdr.stamp,
+ sizeof (thdr.stamp));
+ nlm_custom_header (abfd)->hdrLength = hdrLength;
+ nlm_custom_header (abfd)->dataOffset = dataOffset;
+ nlm_custom_header (abfd)->dataLength = dataLength;
+ memcpy (nlm_custom_header (abfd)->dataStamp, dataStamp,
+ sizeof (dataStamp));
+ nlm_custom_header (abfd)->hdr = hdr;
+ }
+ }
+ else
+ break;
+ }
+ return TRUE;
+}
+
+const bfd_target *
+nlm_object_p (bfd *abfd)
+{
+ struct nlm_obj_tdata *preserved_tdata = nlm_tdata (abfd);
+ bfd_boolean (*backend_object_p) (bfd *);
+ void * x_fxdhdr = NULL;
+ Nlm_Internal_Fixed_Header *i_fxdhdrp;
+ struct nlm_obj_tdata *new_tdata = NULL;
+ const char *signature;
+ enum bfd_architecture arch;
+ bfd_size_type amt;
+
+ /* Some NLM formats have a prefix before the standard NLM fixed
+ header. */
+ backend_object_p = nlm_backend_object_p_func (abfd);
+ if (backend_object_p)
+ {
+ if (!(*backend_object_p) (abfd))
+ goto got_wrong_format_error;
+ }
+
+ /* Read in the fixed length portion of the NLM header in external format. */
+ amt = nlm_fixed_header_size (abfd);
+ x_fxdhdr = bfd_malloc (amt);
+ if (x_fxdhdr == NULL)
+ goto got_no_match;
+
+ if (bfd_bread ((void *) x_fxdhdr, amt, abfd) != amt)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ goto got_wrong_format_error;
+ else
+ goto got_no_match;
+ }
+
+ /* Allocate an instance of the nlm_obj_tdata structure and hook it up to
+ the tdata pointer in the bfd. */
+ amt = sizeof (struct nlm_obj_tdata);
+ new_tdata = bfd_zalloc (abfd, amt);
+ if (new_tdata == NULL)
+ goto got_no_match;
+
+ nlm_tdata (abfd) = new_tdata;
+
+ i_fxdhdrp = nlm_fixed_header (abfd);
+ nlm_swap_fixed_header_in (abfd, x_fxdhdr, i_fxdhdrp);
+ free (x_fxdhdr);
+ x_fxdhdr = NULL;
+
+ /* Check to see if we have an NLM file for this backend by matching
+ the NLM signature. */
+ signature = nlm_signature (abfd);
+ if (signature != NULL
+ && *signature != '\0'
+ && strncmp ((char *) i_fxdhdrp->signature, signature,
+ NLM_SIGNATURE_SIZE) != 0)
+ goto got_wrong_format_error;
+
+ /* There's no supported way to discover the endianess of an NLM, so test for
+ a sane version number after doing byte swapping appropriate for this
+ XVEC. (Hack alert!) */
+ if (i_fxdhdrp->version > 0xFFFF)
+ goto got_wrong_format_error;
+
+ /* There's no supported way to check for 32 bit versus 64 bit addresses,
+ so ignore this distinction for now. (FIXME) */
+ /* Swap in the rest of the required header. */
+ if (!nlm_swap_variable_header_in (abfd))
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ goto got_wrong_format_error;
+ else
+ goto got_no_match;
+ }
+
+ /* Add the sections supplied by all NLM's, and then read in the
+ auxiliary headers. Reading the auxiliary headers may create
+ additional sections described in the cygnus_ext header.
+ From this point on we assume that we have an NLM, and do not
+ treat errors as indicating the wrong format. */
+ if (!add_bfd_section (abfd, NLM_CODE_NAME,
+ i_fxdhdrp->codeImageOffset,
+ i_fxdhdrp->codeImageSize,
+ (SEC_CODE | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+ | SEC_RELOC))
+ || !add_bfd_section (abfd, NLM_INITIALIZED_DATA_NAME,
+ i_fxdhdrp->dataImageOffset,
+ i_fxdhdrp->dataImageSize,
+ (SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+ | SEC_RELOC))
+ || !add_bfd_section (abfd, NLM_UNINITIALIZED_DATA_NAME,
+ (file_ptr) 0,
+ i_fxdhdrp->uninitializedDataSize,
+ SEC_ALLOC))
+ goto got_no_match;
+
+ if (!nlm_swap_auxiliary_headers_in (abfd))
+ goto got_no_match;
+
+ if (nlm_fixed_header (abfd)->numberOfRelocationFixups != 0
+ || nlm_fixed_header (abfd)->numberOfExternalReferences != 0)
+ abfd->flags |= HAS_RELOC;
+ if (nlm_fixed_header (abfd)->numberOfPublics != 0
+ || nlm_fixed_header (abfd)->numberOfDebugRecords != 0
+ || nlm_fixed_header (abfd)->numberOfExternalReferences != 0)
+ abfd->flags |= HAS_SYMS;
+
+ arch = nlm_architecture (abfd);
+ if (arch != bfd_arch_unknown)
+ bfd_default_set_arch_mach (abfd, arch, (unsigned long) 0);
+
+ abfd->flags |= EXEC_P;
+ bfd_get_start_address (abfd) = nlm_fixed_header (abfd)->codeStartOffset;
+
+ return abfd->xvec;
+
+got_wrong_format_error:
+ bfd_set_error (bfd_error_wrong_format);
+got_no_match:
+ nlm_tdata (abfd) = preserved_tdata;
+ if (new_tdata != NULL)
+ bfd_release (abfd, new_tdata);
+ if (x_fxdhdr != NULL)
+ free (x_fxdhdr);
+
+ return NULL;
+}
+
+/* Swap and write out the variable length header. All the fields must
+ exist in the NLM, and must exist in this order. */
+
+static bfd_boolean
+nlm_swap_variable_header_out (bfd *abfd)
+{
+ bfd_byte temp[NLM_TARGET_LONG_SIZE];
+ bfd_size_type amt;
+
+ /* Write the description length and text members. */
+ amt = sizeof (nlm_variable_header (abfd)->descriptionLength);
+ if (bfd_bwrite (& nlm_variable_header (abfd)->descriptionLength, amt,
+ abfd) != amt)
+ return FALSE;
+ amt = nlm_variable_header (abfd)->descriptionLength + 1;
+ if (bfd_bwrite ((void *) nlm_variable_header (abfd)->descriptionText, amt,
+ abfd) != amt)
+ return FALSE;
+
+ /* Convert and write the stackSize field. */
+ put_word (abfd, (bfd_vma) nlm_variable_header (abfd)->stackSize, temp);
+ amt = sizeof (temp);
+ if (bfd_bwrite (temp, amt, abfd) != amt)
+ return FALSE;
+
+ /* Convert and write the reserved field. */
+ put_word (abfd, (bfd_vma) nlm_variable_header (abfd)->reserved, temp);
+ amt = sizeof (temp);
+ if (bfd_bwrite (temp, amt, abfd) != amt)
+ return FALSE;
+
+ /* Write the oldThreadName field. This field is a fixed length string. */
+ amt = sizeof (nlm_variable_header (abfd)->oldThreadName);
+ if (bfd_bwrite (nlm_variable_header (abfd)->oldThreadName, amt,
+ abfd) != amt)
+ return FALSE;
+
+ /* Write the screen name length and text members. */
+ amt = sizeof (nlm_variable_header (abfd)->screenNameLength);
+ if (bfd_bwrite (& nlm_variable_header (abfd)->screenNameLength, amt,
+ abfd) != amt)
+ return FALSE;
+ amt = nlm_variable_header (abfd)->screenNameLength + 1;
+ if (bfd_bwrite (nlm_variable_header (abfd)->screenName, amt, abfd) != amt)
+ return FALSE;
+
+ /* Write the thread name length and text members. */
+ amt = sizeof (nlm_variable_header (abfd)->threadNameLength);
+ if (bfd_bwrite (& nlm_variable_header (abfd)->threadNameLength, amt,
+ abfd) != amt)
+ return FALSE;
+ amt = nlm_variable_header (abfd)->threadNameLength + 1;
+ if (bfd_bwrite (nlm_variable_header (abfd)->threadName, amt, abfd) != amt)
+ return FALSE;
+ return TRUE;
+}
+
+/* Return whether there is a non-zero byte in a memory block. */
+
+static bfd_boolean
+find_nonzero (void * buf, size_t size)
+{
+ char *p = (char *) buf;
+
+ while (size-- != 0)
+ if (*p++ != 0)
+ return TRUE;
+ return FALSE;
+}
+
+/* Swap out the contents of the auxiliary headers. We create those
+ auxiliary headers which have been set non-zero. We do not require
+ the caller to set up the stamp fields. */
+
+static bfd_boolean
+nlm_swap_auxiliary_headers_out (bfd *abfd)
+{
+ bfd_size_type amt;
+
+ /* Write out the version header if there is one. */
+ if (find_nonzero (nlm_version_header (abfd),
+ sizeof (Nlm_Internal_Version_Header)))
+ {
+ Nlm_External_Version_Header thdr;
+
+ memcpy (thdr.stamp, "VeRsIoN#", 8);
+ put_word (abfd, (bfd_vma) nlm_version_header (abfd)->majorVersion,
+ (bfd_byte *) thdr.majorVersion);
+ put_word (abfd, (bfd_vma) nlm_version_header (abfd)->minorVersion,
+ (bfd_byte *) thdr.minorVersion);
+ put_word (abfd, (bfd_vma) nlm_version_header (abfd)->revision,
+ (bfd_byte *) thdr.revision);
+ put_word (abfd, (bfd_vma) nlm_version_header (abfd)->year,
+ (bfd_byte *) thdr.year);
+ put_word (abfd, (bfd_vma) nlm_version_header (abfd)->month,
+ (bfd_byte *) thdr.month);
+ put_word (abfd, (bfd_vma) nlm_version_header (abfd)->day,
+ (bfd_byte *) thdr.day);
+ if (bfd_bwrite ((void *) &thdr, (bfd_size_type) sizeof (thdr), abfd)
+ != sizeof (thdr))
+ return FALSE;
+ }
+
+ /* Note - the CoPyRiGhT tag is emitted before the MeSsAgEs
+ tag in order to make the NW4.x and NW5.x loaders happy. */
+
+ /* Write out the copyright header if there is one. */
+ if (find_nonzero (nlm_copyright_header (abfd),
+ sizeof (Nlm_Internal_Copyright_Header)))
+ {
+ Nlm_External_Copyright_Header thdr;
+
+ memcpy (thdr.stamp, "CoPyRiGhT=", 10);
+ amt = sizeof (thdr.stamp);
+ if (bfd_bwrite ((void *) thdr.stamp, amt, abfd) != amt)
+ return FALSE;
+ thdr.copyrightMessageLength[0] =
+ nlm_copyright_header (abfd)->copyrightMessageLength;
+ amt = 1;
+ if (bfd_bwrite ((void *) thdr.copyrightMessageLength, amt, abfd) != amt)
+ return FALSE;
+ /* The copyright message is a variable length string. */
+ amt = nlm_copyright_header (abfd)->copyrightMessageLength + 1;
+ if (bfd_bwrite ((void *) nlm_copyright_header (abfd)->copyrightMessage,
+ amt, abfd) != amt)
+ return FALSE;
+ }
+
+ /* Write out the extended header if there is one. */
+ if (find_nonzero (nlm_extended_header (abfd),
+ sizeof (Nlm_Internal_Extended_Header)))
+ {
+ Nlm_External_Extended_Header thdr;
+
+ memcpy (thdr.stamp, "MeSsAgEs", 8);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->languageID,
+ (bfd_byte *) thdr.languageID);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->messageFileOffset,
+ (bfd_byte *) thdr.messageFileOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->messageFileLength,
+ (bfd_byte *) thdr.messageFileLength);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->messageCount,
+ (bfd_byte *) thdr.messageCount);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->helpFileOffset,
+ (bfd_byte *) thdr.helpFileOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->helpFileLength,
+ (bfd_byte *) thdr.helpFileLength);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->RPCDataOffset,
+ (bfd_byte *) thdr.RPCDataOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->RPCDataLength,
+ (bfd_byte *) thdr.RPCDataLength);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedCodeOffset,
+ (bfd_byte *) thdr.sharedCodeOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedCodeLength,
+ (bfd_byte *) thdr.sharedCodeLength);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedDataOffset,
+ (bfd_byte *) thdr.sharedDataOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedDataLength,
+ (bfd_byte *) thdr.sharedDataLength);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedRelocationFixupOffset,
+ (bfd_byte *) thdr.sharedRelocationFixupOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedRelocationFixupCount,
+ (bfd_byte *) thdr.sharedRelocationFixupCount);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedExternalReferenceOffset,
+ (bfd_byte *) thdr.sharedExternalReferenceOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedExternalReferenceCount,
+ (bfd_byte *) thdr.sharedExternalReferenceCount);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedPublicsOffset,
+ (bfd_byte *) thdr.sharedPublicsOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedPublicsCount,
+ (bfd_byte *) thdr.sharedPublicsCount);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedDebugRecordOffset,
+ (bfd_byte *) thdr.sharedDebugRecordOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->sharedDebugRecordCount,
+ (bfd_byte *) thdr.sharedDebugRecordCount);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->SharedInitializationOffset,
+ (bfd_byte *) thdr.sharedInitializationOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->SharedExitProcedureOffset,
+ (bfd_byte *) thdr.SharedExitProcedureOffset);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->productID,
+ (bfd_byte *) thdr.productID);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->reserved0,
+ (bfd_byte *) thdr.reserved0);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->reserved1,
+ (bfd_byte *) thdr.reserved1);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->reserved2,
+ (bfd_byte *) thdr.reserved2);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->reserved3,
+ (bfd_byte *) thdr.reserved3);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->reserved4,
+ (bfd_byte *) thdr.reserved4);
+ put_word (abfd,
+ (bfd_vma) nlm_extended_header (abfd)->reserved5,
+ (bfd_byte *) thdr.reserved5);
+ if (bfd_bwrite ((void *) &thdr, (bfd_size_type) sizeof (thdr), abfd)
+ != sizeof (thdr))
+ return FALSE;
+ }
+
+ /* Write out the custom header if there is one. */
+ if (find_nonzero (nlm_custom_header (abfd),
+ sizeof (Nlm_Internal_Custom_Header)))
+ {
+ Nlm_External_Custom_Header thdr;
+ bfd_boolean ds;
+ bfd_size_type hdrLength;
+
+ ds = find_nonzero (nlm_custom_header (abfd)->dataStamp,
+ sizeof (nlm_custom_header (abfd)->dataStamp));
+ memcpy (thdr.stamp, "CuStHeAd", 8);
+ hdrLength = (2 * NLM_TARGET_LONG_SIZE + (ds ? 8 : 0)
+ + nlm_custom_header (abfd)->hdrLength);
+ put_word (abfd, hdrLength, thdr.length);
+ put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataOffset,
+ thdr.dataOffset);
+ put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataLength,
+ thdr.dataLength);
+ if (! ds)
+ {
+ BFD_ASSERT (nlm_custom_header (abfd)->hdrLength == 0);
+ amt = sizeof (thdr) - sizeof (thdr.dataStamp);
+ if (bfd_bwrite ((void *) &thdr, amt, abfd) != amt)
+ return FALSE;