diff options
author | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-13 12:38:00 -0700 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-13 12:38:00 -0700 |
commit | 54f1b3cf509cd889905287cb8ce6c5ae33911a21 (patch) | |
tree | e39b1a7fa04db86a8215b7f9d4656d74e394aec0 /binutils-2.25/bfd/reloc16.c | |
parent | 2a6558a8ecfb81d75215b4ec7dc61113e12cfd5f (diff) | |
download | toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.zip toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.gz toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.bz2 |
Add upstream binutils-2.25 snapshot 4/4 2014
For MIPS -mmsa support
Change-Id: I08c4f002fa7b33dec85ed75956e6ab551bb03c96
Diffstat (limited to 'binutils-2.25/bfd/reloc16.c')
-rw-r--r-- | binutils-2.25/bfd/reloc16.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/binutils-2.25/bfd/reloc16.c b/binutils-2.25/bfd/reloc16.c new file mode 100644 index 0000000..31fc15d --- /dev/null +++ b/binutils-2.25/bfd/reloc16.c @@ -0,0 +1,334 @@ +/* 8 and 16 bit COFF relocation functions, for BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001, + 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2012 + Free Software Foundation, Inc. + Written by Cygnus Support. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + + +/* Most of this hacked by Steve Chamberlain <sac@cygnus.com>. */ + +/* These routines are used by coff-h8300 and coff-z8k to do + relocation. + + FIXME: This code should be rewritten to support the new COFF + linker. Basically, they need to deal with COFF relocs rather than + BFD generic relocs. They should store the relocs in some location + where coff_link_input_bfd can find them (and coff_link_input_bfd + should be changed to use this location rather than rereading the + file) (unless info->keep_memory is FALSE, in which case they should + free up the relocs after dealing with them). */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "coff/internal.h" +#include "libcoff.h" + +bfd_vma +bfd_coff_reloc16_get_value (arelent *reloc, + struct bfd_link_info *link_info, + asection *input_section) +{ + bfd_vma value; + asymbol *symbol = *(reloc->sym_ptr_ptr); + /* A symbol holds a pointer to a section, and an offset from the + base of the section. To relocate, we find where the section will + live in the output and add that in. */ + + if (bfd_is_und_section (symbol->section) + || bfd_is_com_section (symbol->section)) + { + struct bfd_link_hash_entry *h; + + /* The symbol is undefined in this BFD. Look it up in the + global linker hash table. FIXME: This should be changed when + we convert this stuff to use a specific final_link function + and change the interface to bfd_relax_section to not require + the generic symbols. */ + h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info, + bfd_asymbol_name (symbol), + FALSE, FALSE, TRUE); + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) + value = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + else if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_common) + value = h->u.c.size; + else if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_undefweak) + /* This is a GNU extension. */ + value = 0; + else + { + if (!((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (symbol), + input_section->owner, input_section, reloc->address, + TRUE))) + abort (); + value = 0; + } + } + else + { + value = symbol->value + + symbol->section->output_offset + + symbol->section->output_section->vma; + } + + /* Add the value contained in the relocation. */ + value += reloc->addend; + + return value; +} + +void +bfd_perform_slip (bfd *abfd, + unsigned int slip, + asection *input_section, + bfd_vma value) +{ + asymbol **s; + + s = _bfd_generic_link_get_symbols (abfd); + BFD_ASSERT (s != (asymbol **) NULL); + + /* Find all symbols past this point, and make them know + what's happened. */ + while (*s) + { + asymbol *p = *s; + if (p->section == input_section) + { + /* This was pointing into this section, so mangle it. */ + if (p->value > value) + { + p->value -= slip; + if (p->udata.p != NULL) + { + struct generic_link_hash_entry *h; + + h = (struct generic_link_hash_entry *) p->udata.p; + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + h->root.u.def.value -= slip; + BFD_ASSERT (h->root.u.def.value == p->value); + } + } + } + s++; + } +} + +bfd_boolean +bfd_coff_reloc16_relax_section (bfd *abfd, + asection *input_section, + struct bfd_link_info *link_info, + bfd_boolean *again) +{ + /* Get enough memory to hold the stuff. */ + bfd *input_bfd = input_section->owner; + unsigned *shrinks; + unsigned shrink = 0; + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector = NULL; + long reloc_count; + + if (link_info->relocatable) + (*link_info->callbacks->einfo) + (_("%P%F: --relax and -r may not be used together\n")); + + /* We only do global relaxation once. It is not safe to do it multiple + times (see discussion of the "shrinks" array below). */ + *again = FALSE; + + if (reloc_size < 0) + return FALSE; + + reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); + if (!reloc_vector && reloc_size > 0) + return FALSE; + + /* Get the relocs and think about them. */ + reloc_count = + bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, + _bfd_generic_link_get_symbols (input_bfd)); + if (reloc_count < 0) + { + free (reloc_vector); + return FALSE; + } + + /* The reloc16.c and related relaxing code is very simple, the price + for that simplicity is we can only call this function once for + each section. + + So, to get the best results within that limitation, we do multiple + relaxing passes over each section here. That involves keeping track + of the "shrink" at each reloc in the section. This allows us to + accurately determine the relative location of two relocs within + this section. + + In theory, if we kept the "shrinks" array for each section for the + entire link, we could use the generic relaxing code in the linker + and get better results, particularly for jsr->bsr and 24->16 bit + memory reference relaxations. */ + + if (reloc_count > 0) + { + int another_pass = 0; + bfd_size_type amt; + + /* Allocate and initialize the shrinks array for this section. + The last element is used as an accumulator of shrinks. */ + amt = reloc_count + 1; + amt *= sizeof (unsigned); + shrinks = (unsigned *) bfd_zmalloc (amt); + + /* Loop until nothing changes in this section. */ + do + { + arelent **parent; + unsigned int i; + long j; + + another_pass = 0; + + for (i = 0, parent = reloc_vector; *parent; parent++, i++) + { + /* Let the target/machine dependent code examine each reloc + in this section and attempt to shrink it. */ + shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent, + shrinks[i], link_info); + + /* If it shrunk, note it in the shrinks array and set up for + another pass. */ + if (shrink != shrinks[i]) + { + another_pass = 1; + for (j = i + 1; j <= reloc_count; j++) + shrinks[j] += shrink - shrinks[i]; + } + } + } + while (another_pass); + + shrink = shrinks[reloc_count]; + free ((char *) shrinks); + } + + input_section->rawsize = input_section->size; + input_section->size -= shrink; + free ((char *) reloc_vector); + return TRUE; +} + +bfd_byte * +bfd_coff_reloc16_get_relocated_section_contents + (bfd *in_abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols) +{ + /* Get enough memory to hold the stuff. */ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector; + long reloc_count; + bfd_size_type sz; + + if (reloc_size < 0) + return NULL; + + /* If producing relocatable output, don't bother to relax. */ + if (relocatable) + return bfd_generic_get_relocated_section_contents (in_abfd, link_info, + link_order, + data, relocatable, + symbols); + + /* Read in the section. */ + sz = input_section->rawsize ? input_section->rawsize : input_section->size; + if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz)) + return NULL; + + reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); + if (!reloc_vector && reloc_size != 0) + return NULL; + + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + reloc_vector, + symbols); + if (reloc_count < 0) + { + free (reloc_vector); + return NULL; + } + + if (reloc_count > 0) + { + arelent **parent = reloc_vector; + arelent *reloc; + unsigned int dst_address = 0; + unsigned int src_address = 0; + unsigned int run; + unsigned int idx; + + /* Find how long a run we can do. */ + while (dst_address < link_order->size) + { + reloc = *parent; + if (reloc) + { + /* Note that the relaxing didn't tie up the addresses in the + relocation, so we use the original address to work out the + run of non-relocated data. */ + run = reloc->address - src_address; + parent++; + } + else + { + run = link_order->size - dst_address; + } + + /* Copy the bytes. */ + for (idx = 0; idx < run; idx++) + data[dst_address++] = data[src_address++]; + + /* Now do the relocation. */ + if (reloc) + { + bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order, + reloc, data, &src_address, + &dst_address); + } + } + } + free ((char *) reloc_vector); + return data; +} |