reloc.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,228 行 · 第 1/5 页

C
2,228
字号
    {    case 0:      {	char x = bfd_get_8 (abfd, (char *) data + octets);	DOIT (x);	bfd_put_8 (abfd, x, (unsigned char *) data + octets);      }      break;    case 1:      {	short x = bfd_get_16 (abfd, (bfd_byte *) data + octets);	DOIT (x);	bfd_put_16 (abfd, x, (unsigned char *) data + octets);      }      break;    case 2:      {	long x = bfd_get_32 (abfd, (bfd_byte *) data + octets);	DOIT (x);	bfd_put_32 (abfd, x, (bfd_byte *) data + octets);      }      break;    case -2:      {	long x = bfd_get_32 (abfd, (bfd_byte *) data + octets);	relocation = -relocation;	DOIT (x);	bfd_put_32 (abfd, x, (bfd_byte *) data + octets);      }      break;    case -1:      {	long x = bfd_get_16 (abfd, (bfd_byte *) data + octets);	relocation = -relocation;	DOIT (x);	bfd_put_16 (abfd, x, (bfd_byte *) data + octets);      }      break;    case 3:      /* Do nothing */      break;    case 4:#ifdef BFD64      {	bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + octets);	DOIT (x);	bfd_put_64 (abfd, x, (bfd_byte *) data + octets);      }#else      abort ();#endif      break;    default:      return bfd_reloc_other;    }  return flag;}/*FUNCTION	bfd_install_relocationSYNOPSIS	bfd_reloc_status_type                bfd_install_relocation                        (bfd *abfd,                         arelent *reloc_entry,                         PTR data, bfd_vma data_start,                         asection *input_section,			 char **error_message);DESCRIPTION	This looks remarkably like <<bfd_perform_relocation>>, except it	does not expect that the section contents have been filled in.	I.e., it's suitable for use when creating, rather than applying	a relocation.	For now, this function should be considered reserved for the	assembler.*/bfd_reloc_status_typebfd_install_relocation (abfd, reloc_entry, data_start, data_start_offset,			input_section, error_message)     bfd *abfd;     arelent *reloc_entry;     PTR data_start;     bfd_vma data_start_offset;     asection *input_section;     char **error_message;{  bfd_vma relocation;  bfd_reloc_status_type flag = bfd_reloc_ok;  bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd);  bfd_vma output_base = 0;  reloc_howto_type *howto = reloc_entry->howto;  asection *reloc_target_output_section;  asymbol *symbol;  bfd_byte *data;  symbol = *(reloc_entry->sym_ptr_ptr);  if (bfd_is_abs_section (symbol->section))    {      reloc_entry->address += input_section->output_offset;      return bfd_reloc_ok;    }  /* If there is a function supplied to handle this relocation type,     call it.  It'll return `bfd_reloc_continue' if further processing     can be done.  */  if (howto->special_function)    {      bfd_reloc_status_type cont;      /* XXX - The special_function calls haven't been fixed up to deal	 with creating new relocations and section contents.  */      cont = howto->special_function (abfd, reloc_entry, symbol,				      /* XXX - Non-portable! */				      ((bfd_byte *) data_start				       - data_start_offset),				      input_section, abfd, error_message);      if (cont != bfd_reloc_continue)	return cont;    }  /* Is the address of the relocation really within the section?  */  if (reloc_entry->address > input_section->_cooked_size)    return bfd_reloc_outofrange;  /* Work out which section the relocation is targetted at and the     initial relocation command value.  */  /* Get symbol value.  (Common symbols are special.)  */  if (bfd_is_com_section (symbol->section))    relocation = 0;  else    relocation = symbol->value;  reloc_target_output_section = symbol->section->output_section;  /* Convert input-section-relative symbol value to absolute.  */  if (howto->partial_inplace == false)    output_base = 0;  else    output_base = reloc_target_output_section->vma;  relocation += output_base + symbol->section->output_offset;  /* Add in supplied addend.  */  relocation += reloc_entry->addend;  /* Here the variable relocation holds the final address of the     symbol we are relocating against, plus any addend.  */  if (howto->pc_relative == true)    {      /* This is a PC relative relocation.  We want to set RELOCATION	 to the distance between the address of the symbol and the	 location.  RELOCATION is already the address of the symbol.	 We start by subtracting the address of the section containing	 the location.	 If pcrel_offset is set, we must further subtract the position	 of the location within the section.  Some targets arrange for	 the addend to be the negative of the position of the location	 within the section; for example, i386-aout does this.  For	 i386-aout, pcrel_offset is false.  Some other targets do not	 include the position of the location; for example, m88kbcs,	 or ELF.  For those targets, pcrel_offset is true.	 If we are producing relocateable output, then we must ensure	 that this reloc will be correctly computed when the final	 relocation is done.  If pcrel_offset is false we want to wind	 up with the negative of the location within the section,	 which means we must adjust the existing addend by the change	 in the location within the section.  If pcrel_offset is true	 we do not want to adjust the existing addend at all.	 FIXME: This seems logical to me, but for the case of	 producing relocateable output it is not what the code	 actually does.  I don't want to change it, because it seems	 far too likely that something will break.  */      relocation -=	input_section->output_section->vma + input_section->output_offset;      if (howto->pcrel_offset == true && howto->partial_inplace == true)	relocation -= reloc_entry->address;    }  if (howto->partial_inplace == false)    {      /* This is a partial relocation, and we want to apply the relocation	 to the reloc entry rather than the raw data. Modify the reloc	 inplace to reflect what we now know.  */      reloc_entry->addend = relocation;      reloc_entry->address += input_section->output_offset;      return flag;    }  else    {      /* This is a partial relocation, but inplace, so modify the	 reloc record a bit.	 If we've relocated with a symbol with a section, change	 into a ref to the section belonging to the symbol.  */      reloc_entry->address += input_section->output_offset;      /* WTF?? */      if (abfd->xvec->flavour == bfd_target_coff_flavour	  && strcmp (abfd->xvec->name, "coff-Intel-little") != 0	  && strcmp (abfd->xvec->name, "coff-Intel-big") != 0)	{#if 1/* For m68k-coff, the addend was being subtracted twice during   relocation with -r.  Removing the line below this comment   fixes that problem; see PR 2953.However, Ian wrote the following, regarding removing the line below,which explains why it is still enabled:  --djmIf you put a patch like that into BFD you need to check all the COFFlinkers.  I am fairly certain that patch will break coff-i386 (e.g.,SCO); see coff_i386_reloc in coff-i386.c where I worked around theproblem in a different way.  There may very well be a reason that thecode works as it does.Hmmm.  The first obvious point is that bfd_install_relocation shouldnot have any tests that depend upon the flavour.  It's seem likeentirely the wrong place for such a thing.  The second obvious pointis that the current code ignores the reloc addend when producingrelocateable output for COFF.  That's peculiar.  In fact, I reallyhave no idea what the point of the line you want to remove is.A typical COFF reloc subtracts the old value of the symbol and adds inthe new value to the location in the object file (if it's a pcrelative reloc it adds the difference between the symbol value and thelocation).  When relocating we need to preserve that property.BFD handles this by setting the addend to the negative of the oldvalue of the symbol.  Unfortunately it handles common symbols in anon-standard way (it doesn't subtract the old value) but that's adifferent story (we can't change it without losing backwardcompatibility with old object files) (coff-i386 does subtract the oldvalue, to be compatible with existing coff-i386 targets, like SCO).So everything works fine when not producing relocateable output.  Whenwe are producing relocateable output, logically we should do exactlywhat we do when not producing relocateable output.  Therefore, yourpatch is correct.  In fact, it should probably always just setreloc_entry->addend to 0 for all cases, since it is, in fact, going toadd the value into the object file.  This won't hurt the COFF code,which doesn't use the addend; I'm not sure what it will do to otherformats (the thing to check for would be whether any formats both usethe addend and set partial_inplace).When I wanted to make coff-i386 produce relocateable output, I raninto the problem that you are running into: I wanted to remove thatline.  Rather than risk it, I made the coff-i386 relocs use a specialfunction; it's coff_i386_reloc in coff-i386.c.  The functionspecifically adds the addend field into the object file, knowing thatbfd_install_relocation is not going to.  If you remove that line, thencoff-i386.c will wind up adding the addend field in twice.  It'strivial to fix; it just needs to be done.The problem with removing the line is just that it may break someworking code.  With BFD it's hard to be sure of anything.  The rightway to deal with this is simply to build and test at least all thesupported COFF targets.  It should be straightforward if time and diskspace consuming.  For each target:    1) build the linker    2) generate some executable, and link it using -r (I would       probably use paranoia.o and link against newlib/libc.a, which       for all the supported targets would be available in       /usr/cygnus/progressive/H-host/target/lib/libc.a).    3) make the change to reloc.c    4) rebuild the linker    5) repeat step 2    6) if the resulting object files are the same, you have at least       made it no worse    7) if they are different you have to figure out which version is       right*/	  relocation -= reloc_entry->addend;#endif	  reloc_entry->addend = 0;	}      else	{	  reloc_entry->addend = relocation;	}    }  /* FIXME: This overflow checking is incomplete, because the value     might have overflowed before we get here.  For a correct check we     need to compute the value in a size larger than bitsize, but we     can't reasonably do that for a reloc the same size as a host     machine word.     FIXME: We should also do overflow checking on the result after     adding in the value contained in the object file.  */  if (howto->complain_on_overflow != complain_overflow_dont)    flag = bfd_check_overflow (howto->complain_on_overflow,			       howto->bitsize,			       howto->rightshift,			       bfd_arch_bits_per_address (abfd),			       relocation);  /*    Either we are relocating all the way, or we don't want to apply    the relocation to the reloc entry (probably because there isn't    any room in the output format to describe addends to relocs)    */  /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler     (OSF version 1.3, compiler version 3.11).  It miscompiles the     following program:     struct str     {       unsigned int i0;     } s = { 0 };     int     main ()     {       unsigned long x;       x = 0x100000000;       x <<= (unsigned long) s.i0;       if (x == 0)	 printf ("failed\n");       else	 printf ("succeeded (%lx)\n", x);     }     */  relocation >>= (bfd_vma) howto->rightshift;  /* Shift everything up to where it's going to be used */  relocation <<= (bfd_vma) howto->bitpos;  /* Wait for the day when all have the mask in them */  /* What we do:     i instruction to be left alone     o offset within instruction     r relocation offset to apply     S src mask     D dst mask     N ~dst mask     A part 1     B part 2     R result     Do this:     ((  i i i i i o o o o o  from bfd_get<size>     and           S S S S S) to get the size offset we want     +   r r r r r r r r r r) to get the final value to place     and           D D D D D  to chop to right size     -----------------------     =             A A A A A     And this:     (   i i i i i o o o o o  from bfd_get<size>     and N N N N N          ) get instruction     -----------------------     =   B B B B B     And then:     (   B B B B B     or            A A A A A)     -----------------------     =   R R R R R R R R R R  put into bfd_put<size>     */#define DOIT(x) \  x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) +  relocation) & howto->dst_mask))  data = (bfd_byte *) data_start + (octets - data_start_offset);  switch (howto->size)    {    case 0:      {	char x = bfd_get_8 (abfd, (char *) data);	DOIT (x);	bfd_put_8 (abfd, x, (unsigned char *) data);      }      break;    case 1:      {	short x = bfd_get_16 (abfd, (bfd_byte *) data);	DOIT (x);	bfd_put_16 (abfd, x, (unsigned char *) data);      }      break;    case 2:      {	long x = bfd_get_32 (abfd, (bfd_byte *) data);	DOIT (x);	bfd_put_32 (abfd, x, (bfd_byte *) data);      }      break;    case -2:      {	long x = bfd_get_32 (abfd, (bfd_byte *) data);	relocation = -relocation;	DOIT (x);	bfd_put_32 (abfd, x, (bfd_byte *) data);      }      break;    case 3:      /* Do nothing */      break;    case 4:      {	bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data);	DOIT (x);	bfd_put_64 (abfd, x, (bfd_byte *) data);      }      break;    default:      return bfd_reloc_other;    }  return flag;}/* This relocation routine is used by some of the backend linkers.   They do not construct asymbol or arelent structures, so there is no   reason for them to use bfd_perform_relocation.  Also,   bfd_perform_relocation is so hacked up it is easier to write a new   function than to try to deal with it.   This routine does a final relocation.  Whether it is useful for a

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?