reloc.c

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

C
2,228
字号
/*TYPEDEF	arelent_chainDESCRIPTION	How relocs are tied together in an <<asection>>:.typedef struct relent_chain {.  arelent relent;.  struct   relent_chain *next;.} arelent_chain;*//* N_ONES produces N one bits, without overflowing machine arithmetic.  */#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)/*FUNCTION	bfd_check_overflowSYNOPSIS	bfd_reloc_status_type		bfd_check_overflow			(enum complain_overflow how,			 unsigned int bitsize,			 unsigned int rightshift,			 unsigned int addrsize,			 bfd_vma relocation);DESCRIPTION	Perform overflow checking on @var{relocation} which has	@var{bitsize} significant bits and will be shifted right by	@var{rightshift} bits, on a machine with addresses containing	@var{addrsize} significant bits.  The result is either of	@code{bfd_reloc_ok} or @code{bfd_reloc_overflow}.*/bfd_reloc_status_typebfd_check_overflow (how, bitsize, rightshift, addrsize, relocation)     enum complain_overflow how;     unsigned int bitsize;     unsigned int rightshift;     unsigned int addrsize;     bfd_vma relocation;{  bfd_vma fieldmask, addrmask, signmask, ss, a;  bfd_reloc_status_type flag = bfd_reloc_ok;  a = relocation;  /* Note: BITSIZE should always be <= ADDRSIZE, but in case it's not,     we'll be permissive: extra bits in the field mask will     automatically extend the address mask for purposes of the     overflow check.  */  fieldmask = N_ONES (bitsize);  addrmask = N_ONES (addrsize) | fieldmask;  switch (how)    {    case complain_overflow_dont:      break;    case complain_overflow_signed:      /* If any sign bits are set, all sign bits must be set.  That         is, A must be a valid negative address after shifting.  */      a = (a & addrmask) >> rightshift;      signmask = ~ (fieldmask >> 1);      ss = a & signmask;      if (ss != 0 && ss != ((addrmask >> rightshift) & signmask))	flag = bfd_reloc_overflow;      break;    case complain_overflow_unsigned:      /* We have an overflow if the address does not fit in the field.  */      a = (a & addrmask) >> rightshift;      if ((a & ~ fieldmask) != 0)	flag = bfd_reloc_overflow;      break;    case complain_overflow_bitfield:      /* Bitfields are sometimes signed, sometimes unsigned.  We	 explicitly allow an address wrap too, which means a bitfield	 of n bits is allowed to store -2**n to 2**n-1.  Thus overflow	 if the value has some, but not all, bits set outside the	 field.  */      a >>= rightshift;      ss = a & ~ fieldmask;      if (ss != 0 && ss != (((bfd_vma) -1 >> rightshift) & ~ fieldmask))	flag = bfd_reloc_overflow;      break;    default:      abort ();    }  return flag;}/*FUNCTION	bfd_perform_relocationSYNOPSIS	bfd_reloc_status_type                bfd_perform_relocation                        (bfd *abfd,                         arelent *reloc_entry,                         PTR data,                         asection *input_section,                         bfd *output_bfd,			 char **error_message);DESCRIPTION	If @var{output_bfd} is supplied to this function, the	generated image will be relocatable; the relocations are	copied to the output file after they have been changed to	reflect the new state of the world. There are two ways of	reflecting the results of partial linkage in an output file:	by modifying the output data in place, and by modifying the	relocation record.  Some native formats (e.g., basic a.out and	basic coff) have no way of specifying an addend in the	relocation type, so the addend has to go in the output data.	This is no big deal since in these formats the output data	slot will always be big enough for the addend. Complex reloc	types with addends were invented to solve just this problem.	The @var{error_message} argument is set to an error message if	this return @code{bfd_reloc_dangerous}.*/bfd_reloc_status_typebfd_perform_relocation (abfd, reloc_entry, data, input_section, output_bfd,			error_message)     bfd *abfd;     arelent *reloc_entry;     PTR data;     asection *input_section;     bfd *output_bfd;     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;  symbol = *(reloc_entry->sym_ptr_ptr);  if (bfd_is_abs_section (symbol->section)      && output_bfd != (bfd *) NULL)    {      reloc_entry->address += input_section->output_offset;      return bfd_reloc_ok;    }  /* If we are not producing relocateable output, return an error if     the symbol is not defined.  An undefined weak symbol is     considered to have a value of zero (SVR4 ABI, p. 4-27).  */  if (bfd_is_und_section (symbol->section)      && (symbol->flags & BSF_WEAK) == 0      && output_bfd == (bfd *) NULL)    flag = bfd_reloc_undefined;  /* 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;      cont = howto->special_function (abfd, reloc_entry, symbol, data,				      input_section, output_bfd,				      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 /      bfd_octets_per_byte (abfd))    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 (output_bfd && 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)	relocation -= reloc_entry->address;    }  if (output_bfd != (bfd *) NULL)    {      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_perform_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_perform_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;	    }	}    }  else    {      reloc_entry->addend = 0;    }  /* 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_reloc_ok)    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))  switch (howto->size)

⌨️ 快捷键说明

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