+ return TRUE;
+}
+
+/* Cleanup function, returned from check_format hook. */
+
+static void
+go32exe_cleanup (bfd *abfd)
+{
+ abfd->origin = 0;
+
+ free (go32exe_temp_stub);
+ go32exe_temp_stub = NULL;
+ go32exe_temp_stub_size = 0;
+}
+
+/* Check that there is a GO32 stub and read it to go32exe_temp_stub.
+ Then set abfd->origin so that the COFF image is read at the correct
+ file offset. */
+
+static bfd_cleanup
+go32exe_check_format (bfd *abfd)
+{
+ struct external_DOS_hdr filehdr_dos;
+ uint16_t num_pages;
+ uint16_t last_page_size;
+ uint32_t header_end;
+ bfd_size_type stubsize;
+
+ /* This format can not appear in an archive. */
+ if (abfd->origin != 0)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ bfd_set_error (bfd_error_system_call);
+
+ /* Read in the stub file header, which is a DOS MZ executable. */
+ if (bfd_bread (&filehdr_dos, DOS_HDR_SIZE, abfd) != DOS_HDR_SIZE)
+ goto fail;
+
+ /* Make sure that this is an MZ executable. */
+ if (H_GET_16 (abfd, filehdr_dos.e_magic) != IMAGE_DOS_SIGNATURE)
+ goto fail_format;
+
+ /* Determine the size of the stub */
+ num_pages = H_GET_16 (abfd, filehdr_dos.e_cp);
+ last_page_size = H_GET_16 (abfd, filehdr_dos.e_cblp);
+ stubsize = num_pages * 512;
+ if (last_page_size != 0)
+ stubsize += last_page_size - 512;
+
+ /* Save now the stub to be used later. Put the stub data to a temporary
+ location first as tdata still does not exist. It may not even
+ be ever created if we are just checking the file format of ABFD. */
+ bfd_seek (abfd, 0, SEEK_SET);
+ go32exe_temp_stub = bfd_malloc (stubsize);
+ if (go32exe_temp_stub == NULL)
+ goto fail;
+ if (bfd_bread (go32exe_temp_stub, stubsize, abfd) != stubsize)
+ goto fail;
+ go32exe_temp_stub_size = stubsize;
+
+ /* Confirm that this is a go32stub. */
+ header_end = H_GET_16 (abfd, filehdr_dos.e_cparhdr) * 16UL;
+ if (! CONST_STRNEQ (go32exe_temp_stub + header_end, "go32stub"))
+ goto fail_format;
+
+ /* Set origin to where the COFF header starts and seek there. */
+ abfd->origin = stubsize;
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0)
+ goto fail;
+
+ /* Call coff_object_p to read the COFF image. If this fails then the file
+ must be just a stub with no COFF data attached. */
+ bfd_cleanup cleanup = coff_object_p (abfd);
+ if (cleanup == NULL)
+ goto fail;
+ BFD_ASSERT (cleanup == _bfd_no_cleanup);
+
+ return go32exe_cleanup;
+
+ fail_format:
+ bfd_set_error (bfd_error_wrong_format);
+ fail:
+ go32exe_cleanup (abfd);
+ return NULL;
+}
+
+/* Write the stub to the output file, then call coff_write_object_contents. */
+
+static bfd_boolean
+go32exe_write_object_contents (bfd *abfd)
+{
+ const bfd_size_type pos = bfd_tell (abfd);
+ const bfd_size_type stubsize = coff_data (abfd)->stub_size;
+
+ BFD_ASSERT (stubsize != 0);
+
+ bfd_set_error (bfd_error_system_call);
+
+ /* Write the stub. */
+ abfd->origin = 0;
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0)
+ return FALSE;
+ if (bfd_bwrite (coff_data (abfd)->stub, stubsize, abfd) != stubsize)
+ return FALSE;
+
+ /* Seek back to where we were. */
+ abfd->origin = stubsize;
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0)
+ return FALSE;
+
+ return coff_write_object_contents (abfd);
+}
+
+/* mkobject hook. Called directly through bfd_set_format or via
+ coff_mkobject_hook etc from bfd_check_format. */
+
+static bfd_boolean
+go32exe_mkobject (bfd *abfd)
+{
+ /* Don't output to an archive. */
+ if (abfd->my_archive != NULL)
+ return FALSE;
+
+ if (!_bfd_go32_mkobject (abfd))
+ return FALSE;
+
+ go32exe_create_stub (abfd);
+ if (coff_data (abfd)->stub == NULL)
+ {
+ bfd_release (abfd, coff_data (abfd));
+ return FALSE;
+ }
+ abfd->origin = coff_data (abfd)->stub_size;