* som.c (som_write_fixups): New function.

This commit is contained in:
Jeff Law 1993-11-14 00:00:05 +00:00
parent aff9779048
commit 9d0dea6fca
2 changed files with 257 additions and 1 deletions

View 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)

257
bfd/som.c
View File

@ -67,6 +67,12 @@
((__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