diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index e37ff156614..6bd7b5010dd 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,14 @@
 Fri Mar 18 18:13:49 1994  Jeffrey A. Law  (law@snake.cs.utah.edu)
 
+	* libhppa.h (PA_PAGESIZE): Define.
+
+	* som.c (SOM_ALIGN): Define.
+	(som_begin_writing): If writing an executable, initialize all
+	fields in the exec header to zero.  Update fields in the exec
+	header as sizes of loadable subspaces are computed.  Carefully
+	preserve alignments when building executables.  Actually write the
+	exec after all the fields are filled in.
+
         * Better long-filename handling.  Reads SOM ABI compliant extended
 	names, but doesn't quite write compliant extended names yet.
 	* som.c (som_slurp_extended_name_table): Delete function.  The
diff --git a/bfd/som.c b/bfd/som.c
index 92b2e6fd478..630f7c8cfee 100644
--- a/bfd/som.c
+++ b/bfd/som.c
@@ -77,6 +77,10 @@
 /* Max number of SOMs to be found in an archive.  */
 #define SOM_LST_MODULE_LIMIT 1024
 
+/* Generic alignment macro.  */
+#define SOM_ALIGN(val, alignment) \
+  (((val) + (alignment) - 1) & ~((alignment) - 1))
+
 /* SOM allows any one of the four previous relocations to be reused
    with a "R_PREV_FIXUP" relocation entry.  Since R_PREV_FIXUP
    relocations are always a single byte, using a R_PREV_FIXUP instead
@@ -2654,6 +2658,7 @@ som_begin_writing (abfd)
   asection *section;
   asymbol **syms = bfd_get_outsymbols (abfd);
   unsigned int total_subspaces = 0;
+  struct som_exec_auxhdr exec_header;
 
   /* The file header will always be first in an object file, 
      everything else can be in random locations.  To keep things
@@ -2676,10 +2681,13 @@ som_begin_writing (abfd)
   if (abfd->flags & EXEC_P)
     {
       /* Parts of the exec header will be filled in later, so
-	 delay writing the header itself.  Just leave space for
-	 it.  */
-      current_offset += sizeof (struct som_exec_auxhdr);
-      obj_som_file_hdr (abfd)->aux_header_size += sizeof (struct som_exec_auxhdr);
+	 delay writing the header itself.  Fill in the defaults,
+	 and write it later.  */
+      current_offset += sizeof (exec_header);
+      obj_som_file_hdr (abfd)->aux_header_size += sizeof (exec_header);
+      memset (&exec_header, 0, sizeof (exec_header));
+      exec_header.som_auxhdr.type = HPUX_AUX_ID;
+      exec_header.som_auxhdr.length = 40;
     }
   if (obj_som_version_hdr (abfd) != NULL)
     {
@@ -2841,32 +2849,73 @@ som_begin_writing (abfd)
   obj_som_file_hdr (abfd)->compiler_location = current_offset;
   obj_som_file_hdr (abfd)->compiler_total = 0;
 
-  /* Now compute the file positions for the loadable subspaces.  */
+  /* Now compute the file positions for the loadable subspaces, taking
+     care to make sure everything stays properly aligned.  */
 
   section = abfd->sections;
   for (i = 0; i < num_spaces; i++)
     {
       asection *subsection;
+      int first_subspace;
 
       /* Find a space.  */
       while (som_section_data (section)->is_space == 0)
 	section = section->next;
 
+      first_subspace = 1;
       /* Now look for all its subspaces.  */
       for (subsection = abfd->sections;
 	   subsection != NULL;
 	   subsection = subsection->next)
 	{
-	  
+
 	  if (som_section_data (subsection)->is_subspace == 0
 	      || som_section_data (subsection)->containing_space != section
 	      || (subsection->flags & SEC_ALLOC) == 0)
 	    continue;
 
+	  /* If this is the first subspace in the space, and we are
+	     building an executable, then take care to make sure all
+	     the alignments are correct and update the exec header.  */
+	  if (first_subspace
+	      && (abfd->flags & EXEC_P))
+	    {
+	      /* Demand paged executables have each space aligned to a
+		 page boundary.  Sharable executables (write-protected
+		 text) have just the private (aka data & bss) space aligned
+		 to a page boundary.  */
+	      if (abfd->flags & D_PAGED
+		  || ((abfd->flags & WP_TEXT)
+		      && (subsection->flags & SEC_DATA)))
+		current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
+
+	      /* Update the exec header.  */
+	      if (subsection->flags & SEC_CODE && exec_header.exec_tfile == 0)
+		{
+		  exec_header.exec_tmem = section->vma;
+		  exec_header.exec_tfile = current_offset;
+		}
+	      if (subsection->flags & SEC_DATA && exec_header.exec_dfile == 0)
+		{
+		  exec_header.exec_dmem = section->vma;
+		  exec_header.exec_dfile = current_offset;
+		}
+
+	      /* Only do this for the first subspace within each space.  */
+	      first_subspace = 0;
+	    }
+
 	  som_section_data (subsection)->subspace_index = total_subspaces++;
 	  /* This is real data to be loaded from the file.  */
 	  if (subsection->flags & SEC_LOAD)
 	    {
+	      /* Update the size of the code & data.  */
+	      if (abfd->flags & EXEC_P
+		  && subsection->flags & SEC_CODE)
+		exec_header.exec_tsize += subsection->_cooked_size;
+	      else if (abfd->flags & EXEC_P
+		       && subsection->flags & SEC_DATA)
+		exec_header.exec_dsize += subsection->_cooked_size;
 	      som_section_data (subsection)->subspace_dict.file_loc_init_value
 		= current_offset;
 	      section->filepos = current_offset;
@@ -2875,6 +2924,10 @@ som_begin_writing (abfd)
 	  /* Looks like uninitialized data.  */
 	  else
 	    {
+	      /* Update the size of the bss section.  */
+	      if (abfd->flags & EXEC_P)
+		exec_header.exec_bsize += subsection->_cooked_size;
+
 	      som_section_data (subsection)->subspace_dict.file_loc_init_value
 		= 0;
 	      som_section_data (subsection)->subspace_dict.
@@ -2885,7 +2938,12 @@ som_begin_writing (abfd)
       section = section->next; 
     }
 
-  /* Finally compute the file positions for unloadable subspaces.  */
+  /* Finally compute the file positions for unloadable subspaces.
+     If building an executable, start the unloadable stuff on its
+     own page.  */
+
+  if (abfd->flags & EXEC_P)
+    current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
 
   obj_som_file_hdr (abfd)->unloadable_sp_location = current_offset;
   section = abfd->sections;
@@ -2897,6 +2955,8 @@ som_begin_writing (abfd)
       while (som_section_data (section)->is_space == 0)
 	section = section->next;
 
+      current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
+
       /* Now look for all its subspaces.  */
       for (subsection = abfd->sections;
 	   subsection != NULL;
@@ -2930,6 +2990,22 @@ som_begin_writing (abfd)
       section = section->next; 
     }
 
+  /* If building an executable, then make sure to seek to and write
+     one byte at the end of the file to make sure any necessary
+     zeros are filled in.  Ugh.  */
+  if (abfd->flags & EXEC_P)
+    current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE);
+  if (bfd_seek (abfd, current_offset, SEEK_SET) < 0)
+    {
+      bfd_set_error (bfd_error_system_call);
+      return false;
+    }
+  if (bfd_write ((PTR) "", 1, 1, abfd) != 1)
+    {
+      bfd_set_error (bfd_error_system_call);
+      return false;
+    }
+
   obj_som_file_hdr (abfd)->unloadable_sp_size
     = current_offset - obj_som_file_hdr (abfd)->unloadable_sp_location;
 
@@ -2939,6 +3015,29 @@ som_begin_writing (abfd)
 
   /* Done.  Store the total size of the SOM.  */
   obj_som_file_hdr (abfd)->som_length = current_offset;
+
+  /* Now write the exec header.  */
+  if (abfd->flags & EXEC_P)
+    {
+      long tmp;
+
+      /* Oh joys.  Ram some of the BSS data into the DATA section
+	 to be compatable with how the hp linker makes objects
+	 (saves memory space).  */
+      tmp = exec_header.exec_dsize;
+      tmp = SOM_ALIGN (tmp, PA_PAGESIZE);
+      exec_header.exec_bsize -= (tmp - exec_header.exec_dsize);
+      exec_header.exec_dsize = tmp;
+
+      bfd_seek (abfd, obj_som_file_hdr (abfd)->aux_header_location, SEEK_SET);
+
+      if (bfd_write ((PTR) &exec_header, AUX_HDR_SIZE, 1, abfd)
+	  != AUX_HDR_SIZE)
+	{
+	  bfd_set_error (bfd_error_system_call);
+	  return false;
+	}
+    }
   return true;
 }