diff options
author | Jeff Law <law@redhat.com> | 1993-11-14 00:00:05 +0000 |
---|---|---|
committer | Jeff Law <law@redhat.com> | 1993-11-14 00:00:05 +0000 |
commit | 9d0dea6fcadf34de771c782b42bba555216da8e3 (patch) | |
tree | 2a2ebda3998e7ffe62e65b8f0c4f20744a431272 /bfd/som.c | |
parent | aff977904874706286cb13dcc02439db6ac6f02b (diff) | |
download | gdb-9d0dea6fcadf34de771c782b42bba555216da8e3.zip gdb-9d0dea6fcadf34de771c782b42bba555216da8e3.tar.gz gdb-9d0dea6fcadf34de771c782b42bba555216da8e3.tar.bz2 |
* som.c (som_write_fixups): New function.
Diffstat (limited to 'bfd/som.c')
-rw-r--r-- | bfd/som.c | 257 |
1 files changed, 256 insertions, 1 deletions
@@ -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 |