aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/som.c246
2 files changed, 218 insertions, 42 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f06535d..074bf3b 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+Wed Feb 1 01:32:14 1995 Jeff Law (law@snake.cs.utah.edu)
+
+ * som.c (som_object_setup): More heruistics to detect the
+ braindamaged HP OSF1 linker.
+ (setup_sections): Don't forget to free subspace_sections if we get
+ an error.
+ (som_slurp_string_table): Allocate strings on this bfd's obstack
+ rather than directly out of the heap.
+ (som_slurp_symbol_table): Likewise for the saved copy of the
+ canonical symbols.
+ (som_slurp_reloc_table): Likewise for the saved copy of the
+ canonical relocations. Free the native relocations when we're
+ done with them.
+
Tue Jan 31 21:53:28 1995 Doug Evans <dje@canuck.cygnus.com>
* libelf.h (struct elf_obj_tdata): New member program_header_size.
diff --git a/bfd/som.c b/bfd/som.c
index 214a312..f6e9c6a 100644
--- a/bfd/som.c
+++ b/bfd/som.c
@@ -213,10 +213,11 @@ static unsigned char * som_reloc_call PARAMS ((bfd *, unsigned char *,
static unsigned long som_count_spaces PARAMS ((bfd *));
static unsigned long som_count_subspaces PARAMS ((bfd *));
static int compare_syms PARAMS ((const void *, const void *));
+static int compare_subspaces PARAMS ((const void *, const void *));
static unsigned long som_compute_checksum PARAMS ((bfd *));
static boolean som_prep_headers PARAMS ((bfd *));
static int som_sizeof_headers PARAMS ((bfd *, boolean));
-static boolean som_write_headers PARAMS ((bfd *));
+static boolean som_finish_writing 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 *));
@@ -1571,6 +1572,9 @@ som_object_setup (abfd, file_hdrp, aux_hdrp)
struct header *file_hdrp;
struct som_exec_auxhdr *aux_hdrp;
{
+ asection *section;
+ int found;
+
/* som_mkobject will set bfd_error if som_mkobject fails. */
if (som_mkobject (abfd) != true)
return 0;
@@ -1627,7 +1631,18 @@ som_object_setup (abfd, file_hdrp, aux_hdrp)
The new approach examines the entry field. If it's zero or not 4
byte aligned then it's not a proper code address and we guess it's
really the executable flags. */
- if (aux_hdrp->exec_entry == 0 || (aux_hdrp->exec_entry & 0x3) != 0)
+ found = 0;
+ for (section = abfd->sections; section; section = section->next)
+ {
+ if ((section->flags & SEC_CODE) == 0)
+ continue;
+ if (aux_hdrp->exec_entry >= section->vma
+ && aux_hdrp->exec_entry < section->vma + section->_cooked_size)
+ found = 1;
+ }
+ if (aux_hdrp->exec_entry == 0
+ || (aux_hdrp->exec_entry & 0x3) != 0
+ || ! found)
{
bfd_get_start_address (abfd) = aux_hdrp->exec_flags;
obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_entry;
@@ -1668,8 +1683,9 @@ setup_sections (abfd, file_hdr)
struct header *file_hdr;
{
char *space_strings;
- int space_index;
+ unsigned int space_index, i;
unsigned int total_subspaces = 0;
+ asection **subspace_sections, *section;
/* First, read in space names */
@@ -1779,8 +1795,17 @@ setup_sections (abfd, file_hdr)
subspace.quadrant) == false)
goto error_return;
- /* Keep an easy mapping between subspaces and sections. */
- subspace_asect->target_index = total_subspaces++;
+ /* Keep an easy mapping between subspaces and sections.
+ Note we do not necessarily read the subspaces in the
+ same order in which they appear in the object file.
+
+ So to make the target index come out correctly, we
+ store the location of the subspace header in target
+ index, then sort using the location of the subspace
+ header as the key. Then we can assign correct
+ subspace indices. */
+ total_subspaces++;
+ subspace_asect->target_index = bfd_tell (abfd) - sizeof (subspace);
/* Set SEC_READONLY and SEC_CODE/SEC_DATA as specified
by the access_control_bits in the subspace header. */
@@ -1873,13 +1898,43 @@ setup_sections (abfd, file_hdr)
space_asect->_raw_size = save_subspace.file_loc_init_value
- space_asect->filepos + save_subspace.initialization_length;
}
+ /* Now that we've read in all the subspace records, we need to assign
+ a target index to each subspace. */
+ subspace_sections = (asection **) malloc (total_subspaces
+ * sizeof (asection *));
+ if (subspace_sections == NULL)
+ goto error_return;
+
+ for (i = 0, section = abfd->sections; section; section = section->next)
+ {
+ if (!som_is_subspace (section))
+ continue;
+
+ subspace_sections[i] = section;
+ i++;
+ }
+ qsort (subspace_sections, total_subspaces,
+ sizeof (asection *), compare_subspaces);
+
+ /* subspace_sections is now sorted in the order in which the subspaces
+ appear in the object file. Assign an index to each one now. */
+ for (i = 0; i < total_subspaces; i++)
+ subspace_sections[i]->target_index = i;
+
if (space_strings != NULL)
free (space_strings);
+
+ if (subspace_sections != NULL)
+ free (subspace_sections);
+
return true;
error_return:
if (space_strings != NULL)
free (space_strings);
+
+ if (subspace_sections != NULL)
+ free (subspace_sections);
return false;
}
@@ -2136,7 +2191,9 @@ som_is_space (section)
/* If the containing space isn't the same as the given section,
then this isn't a space. */
- if (som_section_data (section)->copy_data->container != section)
+ if (som_section_data (section)->copy_data->container != section
+ && (som_section_data (section)->copy_data->container->output_section
+ != section))
return false;
/* OK. Must be a space. */
@@ -2156,7 +2213,9 @@ som_is_subspace (section)
/* If the containing space is the same as the given section,
then this isn't a subspace. */
- if (som_section_data (section)->copy_data->container == section)
+ if (som_section_data (section)->copy_data->container == section
+ || (som_section_data (section)->copy_data->container->output_section
+ == section))
return false;
/* OK. Must be a subspace. */
@@ -2171,7 +2230,9 @@ static boolean
som_is_container (space, subspace)
asection *space, *subspace;
{
- return som_section_data (subspace)->copy_data->container == space;
+ return (som_section_data (subspace)->copy_data->container == space
+ || (som_section_data (subspace)->copy_data->container->output_section
+ == space));
}
/* Count and return the number of spaces attached to the given BFD. */
@@ -2240,6 +2301,27 @@ compare_syms (arg1, arg2)
return 0;
}
+/* Return -1, 0, 1 indicating the relative ordering of subspace1
+ and subspace. */
+
+static int
+compare_subspaces (arg1, arg2)
+ const PTR arg1;
+ const PTR arg2;
+
+{
+ asection **subspace1 = (asection **) arg1;
+ asection **subspace2 = (asection **) arg2;
+ unsigned int count1, count2;
+
+ if ((*subspace1)->target_index < (*subspace2)->target_index)
+ return -1;
+ else if ((*subspace2)->target_index < (*subspace1)->target_index)
+ return 1;
+ else
+ return 0;
+}
+
/* Perform various work in preparation for emitting the fixup stream. */
static void
@@ -2953,23 +3035,6 @@ som_begin_writing (abfd)
obj_som_file_hdr (abfd)->symbol_total = num_syms;
current_offset += num_syms * sizeof (struct symbol_dictionary_record);
- /* Do prep work before handling fixups. */
- som_prep_for_fixups (abfd, syms, num_syms);
-
- /* Next comes the fixup stream which starts on a word boundary. */
- if (current_offset % 4)
- current_offset += (4 - (current_offset % 4));
- obj_som_file_hdr (abfd)->fixup_request_location = current_offset;
-
- /* Write the fixups and update fields in subspace headers which
- relate to the fixup stream. */
- if (som_write_fixups (abfd, current_offset, &total_reloc_size) == false)
- return false;
-
- /* Record the total size of the fixup stream in the file header. */
- obj_som_file_hdr (abfd)->fixup_request_total = total_reloc_size;
- current_offset += total_reloc_size;
-
/* Next are the symbol strings.
Align them to a word boundary. */
if (current_offset % 4)
@@ -2977,8 +3042,7 @@ som_begin_writing (abfd)
obj_som_file_hdr (abfd)->symbol_strings_location = current_offset;
/* Scribble out the symbol strings. */
- if (som_write_symbol_strings (abfd, current_offset,
- obj_som_sorted_syms (abfd),
+ if (som_write_symbol_strings (abfd, current_offset, syms,
num_syms, &strings_size)
== false)
return false;
@@ -3185,7 +3249,7 @@ som_begin_writing (abfd)
obj_som_file_hdr (abfd)->loader_fixup_location = 0;
obj_som_file_hdr (abfd)->loader_fixup_total = 0;
- /* Done. Store the total size of the SOM. */
+ /* Done. Store the total size of the SOM so far. */
obj_som_file_hdr (abfd)->som_length = current_offset;
return true;
@@ -3194,7 +3258,7 @@ som_begin_writing (abfd)
/* Finally, scribble out the various headers to the disk. */
static boolean
-som_write_headers (abfd)
+som_finish_writing (abfd)
bfd *abfd;
{
int num_spaces = som_count_spaces (abfd);
@@ -3202,6 +3266,36 @@ som_write_headers (abfd)
int subspace_index = 0;
file_ptr location;
asection *section;
+ unsigned long current_offset;
+ unsigned int total_reloc_size;
+
+ /* Do prep work before handling fixups. */
+ som_prep_for_fixups (abfd,
+ bfd_get_outsymbols (abfd),
+ bfd_get_symcount (abfd));
+
+ current_offset = obj_som_file_hdr (abfd)->som_length;
+
+ /* At the end of the file is the fixup stream which starts on a
+ word boundary. */
+ if (current_offset % 4)
+ current_offset += (4 - (current_offset % 4));
+ obj_som_file_hdr (abfd)->fixup_request_location = current_offset;
+
+ /* Write the fixups and update fields in subspace headers which
+ relate to the fixup stream. */
+ if (som_write_fixups (abfd, current_offset, &total_reloc_size) == false)
+ return false;
+
+ /* Record the total size of the fixup stream in the file header. */
+ obj_som_file_hdr (abfd)->fixup_request_total = total_reloc_size;
+
+ obj_som_file_hdr (abfd)->som_length += total_reloc_size;
+
+ /* Now that the symbol table information is complete, build and
+ write the symbol table. */
+ if (som_build_and_write_symbol_table (abfd) == false)
+ return false;
/* Subspaces are written first so that we can set up information
about them in their containing spaces as the subspace is written. */
@@ -3503,11 +3597,10 @@ som_bfd_derive_misc_symbol_info (abfd, sym, info)
/* Now handle the symbol's scope. Exported data which is not
in the common section has scope SS_UNIVERSAL. Note scope
of common symbols was handled earlier! */
- if (sym->flags & BSF_EXPORT && ! bfd_is_com_section (sym->section))
- info->symbol_scope = SS_UNIVERSAL;
- /* Any undefined symbol at this point has a scope SS_UNSAT. */
- else if (bfd_is_und_section (sym->section))
+ if (bfd_is_und_section (sym->section))
info->symbol_scope = SS_UNSAT;
+ else if (sym->flags & BSF_EXPORT && ! bfd_is_com_section (sym->section))
+ info->symbol_scope = SS_UNIVERSAL;
/* Anything else which is not in the common section has scope
SS_LOCAL. */
else if (! bfd_is_com_section (sym->section))
@@ -3609,12 +3702,7 @@ som_write_object_contents (abfd)
som_begin_writing (abfd);
}
- /* Now that the symbol table information is complete, build and
- write the symbol table. */
- if (som_build_and_write_symbol_table (abfd) == false)
- return false;
-
- return (som_write_headers (abfd));
+ return (som_finish_writing (abfd));
}
@@ -3640,7 +3728,7 @@ som_slurp_string_table (abfd)
}
/* Allocate and read in the string table. */
- stringtab = malloc (obj_som_stringtab_size (abfd));
+ stringtab = bfd_zalloc (abfd, obj_som_stringtab_size (abfd));
if (stringtab == NULL)
{
bfd_set_error (bfd_error_no_memory);
@@ -3747,7 +3835,7 @@ som_slurp_symbol_table (abfd)
stringtab = obj_som_stringtab (abfd);
symbase = (som_symbol_type *)
- malloc (symbol_count * sizeof (som_symbol_type));
+ bfd_zalloc (abfd, symbol_count * sizeof (som_symbol_type));
if (symbase == NULL)
{
bfd_set_error (bfd_error_no_memory);
@@ -4158,6 +4246,73 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
if (! just_count)
rptr->sym_ptr_ptr = &symbols[c];
break;
+ /* Argument relocation bits for a function call. */
+ case 'R':
+ if (! just_count)
+ {
+ unsigned int tmp = var ('R');
+ rptr->addend = 0;
+
+ if ((som_hppa_howto_table[op].type == R_PCREL_CALL
+ && R_PCREL_CALL + 10 > op)
+ || (som_hppa_howto_table[op].type == R_ABS_CALL
+ && R_ABS_CALL + 10 > op))
+ {
+ /* Simple encoding. */
+ if (tmp > 4)
+ {
+ tmp -= 5;
+ rptr->addend |= 1;
+ }
+ if (tmp == 4)
+ rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2;
+ else if (tmp == 3)
+ rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4;
+ else if (tmp == 2)
+ rptr->addend |= 1 << 8 | 1 << 6;
+ else if (tmp == 1)
+ rptr->addend |= 1 << 8;
+ }
+ else
+ {
+ unsigned int tmp1, tmp2;
+
+ /* First part is easy -- low order two bits are
+ directly copied, then shifted away. */
+ rptr->addend = tmp & 0x3;
+ tmp >>= 2;
+
+ /* Diving the result by 10 gives us the second
+ part. If it is 9, then the first two words
+ are a double precision paramater, else it is
+ 3 * the first arg bits + the 2nd arg bits. */
+ tmp1 = tmp / 10;
+ tmp -= tmp1 * 10;
+ if (tmp1 == 9)
+ rptr->addend += (0xe << 6);
+ else
+ {
+ /* Get the two pieces. */
+ tmp2 = tmp1 / 3;
+ tmp1 -= tmp2 * 3;
+ /* Put them in the addend. */
+ rptr->addend += (tmp2 << 8) + (tmp1 << 6);
+ }
+
+ /* What's left is the third part. It's unpacked
+ just like the second. */
+ if (tmp == 9)
+ rptr->addend += (0xe << 2);
+ else
+ {
+ tmp2 = tmp / 3;
+ tmp -= tmp2 * 3;
+ rptr->addend += (tmp2 << 4) + (tmp << 2);
+ }
+ }
+ rptr->addend = HPPA_R_ADDEND (rptr->addend, 0);
+ }
+ break;
/* Handle the linker expression stack. */
case 'O':
switch (op)
@@ -4210,6 +4365,9 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
rptr->addend = var ('T');
else if (som_hppa_howto_table[op].type == R_EXIT)
rptr->addend = var ('U');
+ else if (som_hppa_howto_table[op].type == R_PCREL_CALL
+ || som_hppa_howto_table[op].type == R_ABS_CALL)
+ ;
else
rptr->addend = var ('V');
rptr++;
@@ -4292,7 +4450,8 @@ som_slurp_reloc_table (abfd, section, symbols, just_count)
if (section->relocation != (arelent *) NULL)
return true;
- internal_relocs = (arelent *) malloc (num_relocs * sizeof (arelent));
+ internal_relocs = (arelent *)
+ bfd_zalloc (abfd, (num_relocs * sizeof (arelent)));
if (internal_relocs == (arelent *) NULL)
{
bfd_set_error (bfd_error_no_memory);
@@ -4303,6 +4462,9 @@ som_slurp_reloc_table (abfd, section, symbols, just_count)
som_set_reloc_info (external_relocs, fixup_stream_size,
internal_relocs, section, symbols, false);
+ /* We're done with the external relocations. Free them. */
+ free (external_relocs);
+
/* Save our results and return success. */
section->relocation = internal_relocs;
return (true);