diff options
author | Ian Lance Taylor <ian@airs.com> | 1994-03-25 22:37:55 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 1994-03-25 22:37:55 +0000 |
commit | a3a33af390c3a99e00b20847a102e307cfb538c7 (patch) | |
tree | b262eb6f85a5b10fe60cdc47a0f753178e889283 /bfd/ecoff.c | |
parent | f078dc7cf26a816ef0bb66be8b819ac549486e86 (diff) | |
download | gdb-a3a33af390c3a99e00b20847a102e307cfb538c7.zip gdb-a3a33af390c3a99e00b20847a102e307cfb538c7.tar.gz gdb-a3a33af390c3a99e00b20847a102e307cfb538c7.tar.bz2 |
Changes to support linker relaxing of embedded MIPS PIC code to
use a five instruction sequence for funtion calls which are out of
range of the bal instruction.
* libecoff.h (struct ecoff_section_tdata): Define.
(ecoff_section_data): Define.
(ecoff_bfd_relax_section): Don't define.
* ecoff.c (ecoff_final_link_debug_accumulate): Don't read or free
the debugging information if it has already been read.
(ecoff_indirect_link_order): Handle _cooked_size being different
from _raw_size. Don't reread the contents or the relocs if they
have already been read in.
* coff-mips.c (mips_howto_table): Change bitsize of PCREL16 from
18 to 16.
(PCREL16_EXPANSION_ADJUSTMENT): Define.
(mips_relocate_refhi): Take adjust argument.
(mips_relocate_section): Handle reloc offsets stored in section
used_by_bfd field. Call mips_relax_pcrel16 to handle details of
expanding an out of range PCREL16. Keep trace of adjustments
required by expansions. Set s and unset h when converting a reloc
from undefined to section. Change handling of PC relative relocs:
if against a section, they are correct in the object file, if
against an external symbol they are pcrel_offset.
(mips_relax_section): New function.
(mips_relax_pcrel16): New function.
(ecoff_bfd_relax_section): Define.
* coff-alpha.c (ecoff_bfd_relax_section): Define.
* ecofflink.c (bfd_ecoff_debug_accumulate): Handle adjustments
built by mips_relax_section when writing out addresses.
* elf32-mips.c (mips_elf_read_ecoff_info): Clear adjust field.
Diffstat (limited to 'bfd/ecoff.c')
-rw-r--r-- | bfd/ecoff.c | 420 |
1 files changed, 344 insertions, 76 deletions
diff --git a/bfd/ecoff.c b/bfd/ecoff.c index 745d46a..5665a99 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -371,13 +371,16 @@ ecoff_styp_to_sec_flags (abfd, hdr) } else if ((styp_flags & STYP_DATA) || (styp_flags & STYP_RDATA) - || (styp_flags & STYP_SDATA)) + || (styp_flags & STYP_SDATA) + || styp_flags == STYP_PDATA + || styp_flags == STYP_XDATA) { if (sec_flags & SEC_NEVER_LOAD) sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY; else sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; - if (styp_flags & STYP_RDATA) + if ((styp_flags & STYP_RDATA) + || styp_flags == STYP_PDATA) sec_flags |= SEC_READONLY; } else if ((styp_flags & STYP_BSS) @@ -385,7 +388,7 @@ ecoff_styp_to_sec_flags (abfd, hdr) { sec_flags |= SEC_ALLOC; } - else if (styp_flags & STYP_INFO) + else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT) { sec_flags |= SEC_NEVER_LOAD; } @@ -3650,7 +3653,7 @@ ecoff_link_check_archive_element (abfd, info, pneeded) external_ext_size = backend->debug_swap.external_ext_size; esize = symhdr->iextMax * external_ext_size; external_ext = (PTR) malloc (esize); - if (external_ext == NULL) + if (external_ext == NULL && esize != 0) { bfd_set_error (bfd_error_no_memory); goto error_return; @@ -3661,7 +3664,7 @@ ecoff_link_check_archive_element (abfd, info, pneeded) goto error_return; ssext = (char *) malloc (symhdr->issExtMax); - if (ssext == NULL) + if (ssext == NULL && symhdr->issExtMax != 0) { bfd_set_error (bfd_error_no_memory); goto error_return; @@ -3774,7 +3777,7 @@ ecoff_link_add_object_symbols (abfd, info) external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size; esize = symhdr->iextMax * external_ext_size; external_ext = (PTR) malloc (esize); - if (external_ext == NULL) + if (external_ext == NULL && esize != 0) { bfd_set_error (bfd_error_no_memory); goto error_return; @@ -3785,7 +3788,7 @@ ecoff_link_add_object_symbols (abfd, info) goto error_return; ssext = (char *) malloc (symhdr->issExtMax); - if (ssext == NULL) + if (ssext == NULL && symhdr->issExtMax != 0) { bfd_set_error (bfd_error_no_memory); goto error_return; @@ -3972,7 +3975,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext) if (! (_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL, section, value, - (const char *) NULL, true, true, backend->constructor_bitsize, + (const char *) NULL, true, true, (struct bfd_link_hash_entry **) &h))) return false; @@ -4006,6 +4009,9 @@ static boolean ecoff_link_write_external static boolean ecoff_indirect_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *)); +static boolean ecoff_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); /* ECOFF final link routine. This looks through all the input BFDs and gathers together all the debugging information, and then @@ -4111,6 +4117,9 @@ ecoff_bfd_final_link (abfd, info) p = p->next) if (p->type == bfd_indirect_link_order) o->reloc_count += p->u.indirect.section->reloc_count; + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; } } @@ -4189,6 +4198,12 @@ ecoff_bfd_final_link (abfd, info) if (! ecoff_indirect_link_order (abfd, info, o, p)) return false; } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! ecoff_reloc_link_order (abfd, info, o, p)) + return false; + } else { if (! _bfd_default_link_order (abfd, info, o, p)) @@ -4241,16 +4256,22 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle) } \ } - READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *); - READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); - READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); - READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); - READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); - READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), - union aux_ext *); - READ (ss, cbSsOffset, issMax, sizeof (char), char *); - READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); - READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); + /* If raw_syments is not NULL, then the data was already by read by + ecoff_slurp_symbolic_info. */ + if (ecoff_data (input_bfd)->raw_syments == NULL) + { + READ (line, cbLineOffset, cbLine, sizeof (unsigned char), + unsigned char *); + READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); + READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); + READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); + READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); + READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), + union aux_ext *); + READ (ss, cbSsOffset, issMax, sizeof (char), char *); + READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); + READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); + } #undef READ /* We do not read the external strings or the external symbols. */ @@ -4261,36 +4282,39 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle) input_bfd, debug, swap, info)); return_something: - if (debug->line != NULL) - free (debug->line); - if (debug->external_dnr != NULL) - free (debug->external_dnr); - if (debug->external_pdr != NULL) - free (debug->external_pdr); - if (debug->external_sym != NULL) - free (debug->external_sym); - if (debug->external_opt != NULL) - free (debug->external_opt); - if (debug->external_aux != NULL) - free (debug->external_aux); - if (debug->ss != NULL) - free (debug->ss); - if (debug->external_fdr != NULL) - free (debug->external_fdr); - if (debug->external_rfd != NULL) - free (debug->external_rfd); - - /* Make sure we don't accidentally follow one of these pointers on - to the stack. */ - debug->line = NULL; - debug->external_dnr = NULL; - debug->external_pdr = NULL; - debug->external_sym = NULL; - debug->external_opt = NULL; - debug->external_aux = NULL; - debug->ss = NULL; - debug->external_fdr = NULL; - debug->external_rfd = NULL; + if (ecoff_data (input_bfd)->raw_syments == NULL) + { + if (debug->line != NULL) + free (debug->line); + if (debug->external_dnr != NULL) + free (debug->external_dnr); + if (debug->external_pdr != NULL) + free (debug->external_pdr); + if (debug->external_sym != NULL) + free (debug->external_sym); + if (debug->external_opt != NULL) + free (debug->external_opt); + if (debug->external_aux != NULL) + free (debug->external_aux); + if (debug->ss != NULL) + free (debug->ss); + if (debug->external_fdr != NULL) + free (debug->external_fdr); + if (debug->external_rfd != NULL) + free (debug->external_rfd); + + /* Make sure we don't accidentally follow one of these pointers + into freed memory. */ + debug->line = NULL; + debug->external_dnr = NULL; + debug->external_pdr = NULL; + debug->external_sym = NULL; + debug->external_opt = NULL; + debug->external_aux = NULL; + debug->ss = NULL; + debug->external_fdr = NULL; + debug->external_rfd = NULL; + } return ret; } @@ -4318,9 +4342,42 @@ ecoff_link_write_external (h, data) h->esym.reserved = 0; h->esym.ifd = ifdNil; h->esym.asym.value = 0; - /* FIXME: we can do better than this for st and sc. */ h->esym.asym.st = stGlobal; - h->esym.asym.sc = scAbs; + + if (h->root.type != bfd_link_hash_defined) + h->esym.asym.sc = scAbs; + else + { + asection *output_section; + const char *name; + + output_section = h->root.u.def.section->output_section; + name = bfd_section_name (output_section->owner, output_section); + + if (strcmp (name, _TEXT) == 0) + h->esym.asym.sc = scText; + else if (strcmp (name, _DATA) == 0) + h->esym.asym.sc = scData; + else if (strcmp (name, _SDATA) == 0) + h->esym.asym.sc = scSData; + else if (strcmp (name, _RDATA) == 0) + h->esym.asym.sc = scRData; + else if (strcmp (name, _BSS) == 0) + h->esym.asym.sc = scBss; + else if (strcmp (name, _SBSS) == 0) + h->esym.asym.sc = scSBss; + else if (strcmp (name, _INIT) == 0) + h->esym.asym.sc = scInit; + else if (strcmp (name, _FINI) == 0) + h->esym.asym.sc = scFini; + else if (strcmp (name, _PDATA) == 0) + h->esym.asym.sc = scPData; + else if (strcmp (name, _XDATA) == 0) + h->esym.asym.sc = scXData; + else + h->esym.asym.sc = scAbs; + } + h->esym.asym.reserved = 0; h->esym.asym.index = indexNil; } @@ -4343,9 +4400,9 @@ ecoff_link_write_external (h, data) abort (); case bfd_link_hash_undefined: case bfd_link_hash_weak: - if (h->esym.asym.st != scUndefined - && h->esym.asym.st != scSUndefined) - h->esym.asym.st = scUndefined; + if (h->esym.asym.sc != scUndefined + && h->esym.asym.sc != scSUndefined) + h->esym.asym.sc = scUndefined; break; case bfd_link_hash_defined: if (h->esym.asym.sc == scUndefined @@ -4394,7 +4451,9 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order) { asection *input_section; bfd *input_bfd; - bfd_size_type input_size; + struct ecoff_section_tdata *section_tdata; + bfd_size_type raw_size; + bfd_size_type cooked_size; bfd_byte *contents = NULL; bfd_size_type external_reloc_size; bfd_size_type external_relocs_size; @@ -4407,37 +4466,63 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order) input_section = link_order->u.indirect.section; input_bfd = input_section->owner; + section_tdata = ecoff_section_data (input_bfd, input_section); + + raw_size = input_section->_raw_size; + cooked_size = input_section->_cooked_size; + if (cooked_size == 0) + cooked_size = raw_size; BFD_ASSERT (input_section->output_section == output_section); BFD_ASSERT (input_section->output_offset == link_order->offset); - BFD_ASSERT (bfd_section_size (input_bfd, input_section) == link_order->size); - - /* Get the section contents. */ - input_size = bfd_section_size (input_bfd, input_section); - contents = (bfd_byte *) malloc (input_size); - if (contents == NULL) + BFD_ASSERT (cooked_size == link_order->size); + + /* Get the section contents. We allocate memory for the larger of + the size before relocating and the size after relocating. */ + contents = (bfd_byte *) malloc (raw_size >= cooked_size + ? raw_size + : cooked_size); + if (contents == NULL && raw_size != 0) { bfd_set_error (bfd_error_no_memory); goto error_return; } - if (! bfd_get_section_contents (input_bfd, input_section, (PTR) contents, - (file_ptr) 0, input_size)) - goto error_return; - /* Get the relocs. */ + /* If we are relaxing, the contents may have already been read into + memory, in which case we copy them into our new buffer. We don't + simply reuse the old buffer in case cooked_size > raw_size. */ + if (section_tdata != (struct ecoff_section_tdata *) NULL + && section_tdata->contents != (bfd_byte *) NULL) + memcpy (contents, section_tdata->contents, raw_size); + else + { + if (! bfd_get_section_contents (input_bfd, input_section, + (PTR) contents, + (file_ptr) 0, raw_size)) + goto error_return; + } + + /* Get the relocs. If we are relaxing MIPS code, they will already + have been read in. Otherwise, we read them in now. */ external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size; external_relocs_size = external_reloc_size * input_section->reloc_count; - external_relocs = (PTR) malloc (external_relocs_size); - if (external_relocs == NULL) + + if (section_tdata != (struct ecoff_section_tdata *) NULL) + external_relocs = section_tdata->external_relocs; + else { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } + external_relocs = (PTR) malloc (external_relocs_size); + if (external_relocs == NULL && external_relocs_size != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } - if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 - || (bfd_read (external_relocs, 1, external_relocs_size, input_bfd) - != external_relocs_size)) - goto error_return; + if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 + || (bfd_read (external_relocs, 1, external_relocs_size, input_bfd) + != external_relocs_size)) + goto error_return; + } /* Relocate the section contents. */ if (! ((*ecoff_backend (input_bfd)->relocate_section) @@ -4450,7 +4535,7 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order) output_section, (PTR) contents, input_section->output_offset, - input_size)) + cooked_size)) goto error_return; /* If we are producing relocateable output, the relocs were @@ -4471,14 +4556,197 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order) if (contents != NULL) free (contents); - if (external_relocs != NULL) + if (external_relocs != NULL && section_tdata == NULL) free (external_relocs); return true; error_return: if (contents != NULL) free (contents); - if (external_relocs != NULL) + if (external_relocs != NULL && section_tdata == NULL) free (external_relocs); return false; } + +/* Generate a reloc when linking an ECOFF file. This is a reloc + requested by the linker, and does come from any input file. This + is used to build constructor and destructor tables when linking + with -Ur. */ + +static boolean +ecoff_reloc_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + arelent rel; + struct internal_reloc in; + bfd_size_type external_reloc_size; + bfd_byte *rbuf; + boolean ok; + + /* We set up an arelent to pass to the backend adjust_reloc_out + routine. */ + rel.address = link_order->offset; + + rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (rel.howto == (const reloc_howto_type *) NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (link_order->type == bfd_section_reloc_link_order) + rel.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; + else + { + /* We can't set up a reloc against a symbol correctly, because + we have no asymbol structure. Currently no adjust_reloc_out + routine cases. */ + rel.sym_ptr_ptr = (asymbol **) NULL; + } + + /* All ECOFF relocs are in-place. Put the addend into the object + file. */ + + BFD_ASSERT (rel.howto->partial_inplace); + if (link_order->u.reloc.p->addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (rel.howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + rstat = _bfd_relocate_contents (rel.howto, output_bfd, + link_order->u.reloc.p->addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (output_bfd, + link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + rel.howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + rel.addend = 0; + + /* Move the information into a internal_reloc structure. */ + in.r_vaddr = (rel.address + + bfd_get_section_vma (output_bfd, output_section)); + in.r_type = rel.howto->type; + + if (link_order->type == bfd_symbol_reloc_link_order) + { + struct ecoff_link_hash_entry *h; + + h = ecoff_link_hash_lookup (ecoff_hash_table (info), + link_order->u.reloc.p->u.name, + false, false, true); + if (h != (struct ecoff_link_hash_entry *) NULL + && h->indx != -1) + in.r_symndx = h->indx; + else + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + in.r_symndx = 0; + } + in.r_extern = 1; + } + else + { + CONST char *name; + + name = bfd_get_section_name (output_bfd, + link_order->u.reloc.p->u.section); + if (strcmp (name, ".text") == 0) + in.r_symndx = RELOC_SECTION_TEXT; + else if (strcmp (name, ".rdata") == 0) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else if (strcmp (name, ".xdata") == 0) + in.r_symndx = RELOC_SECTION_XDATA; + else if (strcmp (name, ".pdata") == 0) + in.r_symndx = RELOC_SECTION_PDATA; + else if (strcmp (name, ".fini") == 0) + in.r_symndx = RELOC_SECTION_FINI; + else if (strcmp (name, ".lita") == 0) + in.r_symndx = RELOC_SECTION_LITA; + else if (strcmp (name, "*ABS*") == 0) + in.r_symndx = RELOC_SECTION_ABS; + else + abort (); + in.r_extern = 0; + } + + /* Let the BFD backend adjust the reloc. */ + (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in); + + /* Get some memory and swap out the reloc. */ + external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size; + rbuf = (bfd_byte *) malloc (external_reloc_size); + if (rbuf == (bfd_byte *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf); + + ok = (bfd_seek (output_bfd, + (output_section->rel_filepos + + output_section->reloc_count * external_reloc_size), + SEEK_SET) == 0 + && (bfd_write ((PTR) rbuf, 1, external_reloc_size, output_bfd) + == external_reloc_size)); + + if (ok) + ++output_section->reloc_count; + + free (rbuf); + + return ok; +} |