* som.c (som_write_fixups): New function.
authorJeff Law <law@redhat.com>
Sun, 14 Nov 1993 00:00:05 +0000 (00:00 +0000)
committerJeff Law <law@redhat.com>
Sun, 14 Nov 1993 00:00:05 +0000 (00:00 +0000)
bfd/ChangeLog
bfd/som.c

index 85327496ca9bf651e6fc45fab50810b8b377124d..7db37cd3ada287f864989fb088c0ba287cb1a412 100644 (file)
@@ -1,6 +1,7 @@
 Sat Nov 13 15:27:15 1993  Jeffrey A. Law  (law@snake.cs.utah.edu)
 
        * som.c (som_prep_for_fixups): New function.
+       (som_write_fixups): New function.
 
 Fri Nov 12 15:29:36 1993  Jeffrey A. Law  (law@snake.cs.utah.edu)
 
index e63d7d5200383922a2fc37eea9f3c24ef1815460..f2aa2ca7ab6b3ef5585403e5bfffd67aacabe62a 100644 (file)
--- a/bfd/som.c
+++ b/bfd/som.c
      ((__m_num) >= _PA_RISC1_1_ID && (__m_num) <= _PA_RISC_MAXID))
 #endif /* _PA_RISC_ID */
 
+/* Size (in chars) of the temporary buffers used during fixup and string
+   table writes.   */
+   
+#define SOM_TMP_BUFSIZE 8192
+
+
 /* 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
@@ -162,7 +168,7 @@ static int som_sizeof_headers PARAMS ((bfd *, boolean));
 static boolean som_write_headers PARAMS ((bfd *));
 static boolean som_build_and_write_symbol_table PARAMS ((bfd *));
 static void som_prep_for_fixups PARAMS ((bfd *, asymbol **, unsigned long));
-
+static boolean som_write_fixups PARAMS ((bfd *, unsigned long, unsigned int *));
 
 static reloc_howto_type som_hppa_howto_table[] =
 {
@@ -1540,6 +1546,255 @@ som_prep_for_fixups (abfd, syms, num_syms)
     }
 }
 
+static boolean
+som_write_fixups (abfd, current_offset, total_reloc_sizep)
+     bfd *abfd;
+     unsigned long current_offset;
+     unsigned int *total_reloc_sizep;
+{
+  unsigned int i, j;
+  unsigned char *tmp_space, *p;
+  unsigned int total_reloc_size = 0;
+  unsigned int subspace_reloc_size = 0;
+  unsigned int num_spaces = obj_som_file_hdr (abfd)->space_total;
+  asection *section = abfd->sections;
+
+  /* Get a chunk of memory that we can use as buffer space, then throw
+     away.  */
+  tmp_space = alloca (SOM_TMP_BUFSIZE);
+  bzero (tmp_space, SOM_TMP_BUFSIZE);
+  p = tmp_space;
+
+  /* All the fixups for a particular subspace are emitted in a single
+     stream.  All the subspaces for a particular space are emitted
+     as a single stream.
+
+     So, to get all the locations correct one must iterate through all the
+     spaces, for each space iterate through its subspaces and output a
+     fixups stream.  */
+  for (i = 0; i < num_spaces; i++)
+    {
+      asection *subsection;
+
+      /* Find a space.  */
+      while (som_section_data (section)->is_space == 0)
+       section = section->next;
+
+      /* Now iterate through each of its subspaces.  */
+      for (subsection = abfd->sections;
+          subsection != NULL;
+          subsection = subsection->next)
+       {
+         int reloc_offset;
+
+         /* Find a subspace of this space.  */
+         if (som_section_data (subsection)->is_subspace == 0
+             || som_section_data (subsection)->containing_space != section)
+           continue;
+
+         /* If this subspace had no relocations, then we're finished 
+            with it.  */
+         if (subsection->reloc_count <= 0)
+           {
+             som_section_data (subsection)->subspace_dict.fixup_request_index
+               = -1;
+             continue;
+           }
+
+         /* This subspace has some relocations.  Put the relocation stream
+            index into the subspace record.  */
+         som_section_data (subsection)->subspace_dict.fixup_request_index
+           = total_reloc_size;
+
+         /* To make life easier start over with a clean slate for 
+            each subspace.  Seek to the start of the relocation stream
+            for this subspace in preparation for writing out its fixup
+            stream.  */
+         if (bfd_seek (abfd, current_offset + total_reloc_size, SEEK_SET) != 0)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+
+         /* Buffer space has already been allocated.  Just perform some
+            initialization here.  */
+         p = tmp_space;
+         subspace_reloc_size = 0;
+         reloc_offset = 0;
+         som_initialize_reloc_queue (reloc_queue);
+
+         /* Translate each BFD relocation into one or more SOM 
+            relocations.  */
+         for (j = 0; j < subsection->reloc_count; j++)
+           {
+             arelent *bfd_reloc = subsection->orelocation[j];
+             unsigned int skip;
+             int sym_num;
+
+             /* Get the symbol number.  Remember it's stored in a 
+                special place for section symbols.  */
+             if ((*bfd_reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM)
+               sym_num = (int) (*bfd_reloc->sym_ptr_ptr)->udata;
+             else
+               sym_num  = (*som_symbol_data ((*bfd_reloc->sym_ptr_ptr)))->index;
+             
+             /* If there is not enough room for the next couple relocations,
+                then dump the current buffer contents now.  Also reinitialize
+                the relocation queue. 
+
+                FIXME.  We assume here that no BFD relocation will expand
+                to more than 100 bytes of SOM relocations.  This should (?!?)
+                be quite safe.  */
+             if (p - tmp_space + 100 > SOM_TMP_BUFSIZE)
+               {
+                 if (bfd_write ((PTR) tmp_space, p - tmp_space, 1, abfd)
+                     != p - tmp_space)
+                   {
+                     bfd_error = system_call_error;
+                     return false;
+                   }
+                 p = tmp_space;
+                 som_initialize_reloc_queue (reloc_queue);
+               }
+
+             /* Emit R_NO_RELOCATION fixups to map any bytes which were
+                skipped.  */
+             skip = bfd_reloc->address - reloc_offset;
+             p = som_reloc_skip (abfd, skip, p,
+                                 &subspace_reloc_size, reloc_queue);
+
+             /* Update reloc_offset for the next iteration.
+
+                Note R_ENTRY and R_EXIT relocations are just markers,
+                they do not consume input bytes.  */ 
+             if (bfd_reloc->howto->type != R_ENTRY
+                 && bfd_reloc->howto->type != R_EXIT)
+               reloc_offset = bfd_reloc->address + 4;
+             else
+               reloc_offset = bfd_reloc->address;
+
+
+             /* Now the actual relocation we care about.  */
+             switch (bfd_reloc->howto->type)
+               {
+               case R_PCREL_CALL:
+               case R_ABS_CALL:
+                 p = som_reloc_call (abfd, p, &subspace_reloc_size,
+                                     bfd_reloc, sym_num, reloc_queue);
+                 break;
+
+               case R_CODE_ONE_SYMBOL:
+               case R_DP_RELATIVE:
+                 /* Account for any addend.  */
+                 if (bfd_reloc->addend)
+                   p = som_reloc_addend (abfd, bfd_reloc->addend, p, 
+                                         &subspace_reloc_size, reloc_queue);
+
+                 if (sym_num < 0x20)
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type + sym_num, p);
+                     subspace_reloc_size += 1;
+                     p += 1;
+                   }
+                 else if (sym_num < 0x100)
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type + 32, p);
+                     bfd_put_8 (abfd, sym_num, p + 1);
+                     p = try_prev_fixup (abfd, &subspace_reloc_size, p,
+                                         2, reloc_queue);
+                   }
+                 else if (sym_num < 0x10000000)
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type + 33, p);
+                     bfd_put_8 (abfd, sym_num >> 16, p + 1);
+                     bfd_put_16 (abfd, sym_num, p + 2); 
+                     p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                         p, 4, reloc_queue);
+                   }
+                 else
+                   abort ();
+                 break;
+
+               case R_DATA_ONE_SYMBOL:
+               case R_DATA_PLABEL:
+               case R_CODE_PLABEL:
+                 /* Account for any addend.  */
+                 if (bfd_reloc->addend)
+                   p = som_reloc_addend (abfd, bfd_reloc->addend, p, 
+                                         &subspace_reloc_size, reloc_queue);
+
+                 if (sym_num < 0x100)
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type, p);
+                     bfd_put_8 (abfd, sym_num, p + 1);
+                     p = try_prev_fixup (abfd, &subspace_reloc_size, p,
+                                         2, reloc_queue);
+                   }
+                 else if (sym_num < 0x10000000)
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type + 1, p);
+                     bfd_put_8 (abfd, sym_num >> 16, p + 1);
+                     bfd_put_16 (abfd, sym_num, p + 2); 
+                     p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                         p, 4, reloc_queue);
+                   }
+                 else
+                   abort ();
+                 break;
+
+               case R_ENTRY:
+                 {
+                   int *descp
+                      = (int *) (*som_symbol_data ((*bfd_reloc->sym_ptr_ptr)))->unwind;
+                   bfd_put_8 (abfd, R_ENTRY, p);
+                   bfd_put_32 (abfd, descp[0], p + 1);
+                   bfd_put_32 (abfd, descp[1], p + 5);
+                   p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                       p, 9, reloc_queue);
+                   break;
+                 }
+                 
+               case R_EXIT:
+                 bfd_put_8 (abfd, R_EXIT, p);
+                 subspace_reloc_size += 1;
+                 p += 1;
+                 break;
+
+               /* Put a "R_RESERVED" relocation in the stream if
+                  we hit something we do not understand.  The linker
+                  will complain loudly if this ever happens.  */
+               default:
+                 bfd_put_8 (abfd, 0xff, p);
+                 subspace_reloc_size += 1;
+                 p += 1;
+               }
+           }
+
+         /* Last BFD relocation for a subspace has been processed.
+            Map the rest of the subspace with R_NO_RELOCATION fixups.  */
+         p = som_reloc_skip (abfd, bfd_section_size (abfd, subsection) 
+                                     - reloc_offset,
+                             p, &subspace_reloc_size, reloc_queue);
+
+         /* Scribble out the relocations.  */
+         if (bfd_write ((PTR) tmp_space, p - tmp_space, 1, abfd)
+             != p - tmp_space)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+         p = tmp_space;
+
+         total_reloc_size += subspace_reloc_size;
+         som_section_data (subsection)->subspace_dict.fixup_request_quantity
+           = subspace_reloc_size;
+       }
+      section = section->next;
+    }
+  *total_reloc_sizep = total_reloc_size;
+  return true;
+}
+
 /* Finally, scribble out the various headers to the disk.  */
 
 static boolean