reloc.c

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

C
2,228
字号
   relocateable link depends upon how the object format defines   relocations.   FIXME: This routine ignores any special_function in the HOWTO,   since the existing special_function values have been written for   bfd_perform_relocation.   HOWTO is the reloc howto information.   INPUT_BFD is the BFD which the reloc applies to.   INPUT_SECTION is the section which the reloc applies to.   CONTENTS is the contents of the section.   ADDRESS is the address of the reloc within INPUT_SECTION.   VALUE is the value of the symbol the reloc refers to.   ADDEND is the addend of the reloc.  */bfd_reloc_status_type_bfd_final_link_relocate (howto, input_bfd, input_section, contents, address,			  value, addend)     reloc_howto_type *howto;     bfd *input_bfd;     asection *input_section;     bfd_byte *contents;     bfd_vma address;     bfd_vma value;     bfd_vma addend;{  bfd_vma relocation;  /* Sanity check the address.  */  if (address > input_section->_raw_size)    return bfd_reloc_outofrange;  /* This function assumes that we are dealing with a basic relocation     against a symbol.  We want to compute the value of the symbol to     relocate to.  This is just VALUE, the value of the symbol, plus     ADDEND, any addend associated with the reloc.  */  relocation = value + addend;  /* If the relocation is PC relative, we want to set RELOCATION to     the distance between the symbol (currently in RELOCATION) and the     location we are relocating.  Some targets (e.g., i386-aout)     arrange for the contents of the section to be the negative of the     offset of the location within the section; for such targets     pcrel_offset is false.  Other targets (e.g., m88kbcs or ELF)     simply leave the contents of the section as zero; for such     targets pcrel_offset is true.  If pcrel_offset is false we do not     need to subtract out the offset of the location within the     section (which is just ADDRESS).  */  if (howto->pc_relative)    {      relocation -= (input_section->output_section->vma		     + input_section->output_offset);      if (howto->pcrel_offset)	relocation -= address;    }  return _bfd_relocate_contents (howto, input_bfd, relocation,				 contents + address);}/* Relocate a given location using a given value and howto.  */bfd_reloc_status_type_bfd_relocate_contents (howto, input_bfd, relocation, location)     reloc_howto_type *howto;     bfd *input_bfd;     bfd_vma relocation;     bfd_byte *location;{  int size;  bfd_vma x = 0;  bfd_reloc_status_type flag;  unsigned int rightshift = howto->rightshift;  unsigned int bitpos = howto->bitpos;  /* If the size is negative, negate RELOCATION.  This isn't very     general.  */  if (howto->size < 0)    relocation = -relocation;  /* Get the value we are going to relocate.  */  size = bfd_get_reloc_size (howto);  switch (size)    {    default:    case 0:      abort ();    case 1:      x = bfd_get_8 (input_bfd, location);      break;    case 2:      x = bfd_get_16 (input_bfd, location);      break;    case 4:      x = bfd_get_32 (input_bfd, location);      break;    case 8:#ifdef BFD64      x = bfd_get_64 (input_bfd, location);#else      abort ();#endif      break;    }  /* Check for overflow.  FIXME: We may drop bits during the addition     which we don't check for.  We must either check at every single     operation, which would be tedious, or we must do the computations     in a type larger than bfd_vma, which would be inefficient.  */  flag = bfd_reloc_ok;  if (howto->complain_on_overflow != complain_overflow_dont)    {      bfd_vma addrmask, fieldmask, signmask, ss;      bfd_vma a, b, sum;      /* Get the values to be added together.  For signed and unsigned         relocations, we assume that all values should be truncated to         the size of an address.  For bitfields, all the bits matter.         See also bfd_check_overflow.  */      fieldmask = N_ONES (howto->bitsize);      addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;      a = relocation;      b = x & howto->src_mask;      switch (howto->complain_on_overflow)	{	case complain_overflow_signed:	  a = (a & addrmask) >> rightshift;	  /* If any sign bits are set, all sign bits must be set.	     That is, A must be a valid negative address after	     shifting.  */	  signmask = ~ (fieldmask >> 1);	  ss = a & signmask;	  if (ss != 0 && ss != ((addrmask >> rightshift) & signmask))	    flag = bfd_reloc_overflow;	  /* We only need this next bit of code if the sign bit of B             is below the sign bit of A.  This would only happen if             SRC_MASK had fewer bits than BITSIZE.  Note that if             SRC_MASK has more bits than BITSIZE, we can get into             trouble; we would need to verify that B is in range, as             we do for A above.  */	  signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;	  /* Set all the bits above the sign bit.  */	  b = (b ^ signmask) - signmask;	  b = (b & addrmask) >> bitpos;	  /* Now we can do the addition.  */	  sum = a + b;	  /* See if the result has the correct sign.  Bits above the             sign bit are junk now; ignore them.  If the sum is             positive, make sure we did not have all negative inputs;             if the sum is negative, make sure we did not have all             positive inputs.  The test below looks only at the sign             bits, and it really just	         SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM)	     */	  signmask = (fieldmask >> 1) + 1;	  if (((~ (a ^ b)) & (a ^ sum)) & signmask)	    flag = bfd_reloc_overflow;	  break;	case complain_overflow_unsigned:	  /* Checking for an unsigned overflow is relatively easy:             trim the addresses and add, and trim the result as well.             Overflow is normally indicated when the result does not             fit in the field.  However, we also need to consider the             case when, e.g., fieldmask is 0x7fffffff or smaller, an             input is 0x80000000, and bfd_vma is only 32 bits; then we             will get sum == 0, but there is an overflow, since the             inputs did not fit in the field.  Instead of doing a             separate test, we can check for this by or-ing in the             operands when testing for the sum overflowing its final             field.  */	  a = (a & addrmask) >> rightshift;	  b = (b & addrmask) >> bitpos;	  sum = (a + b) & addrmask;	  if ((a | b | sum) & ~ fieldmask)	    flag = bfd_reloc_overflow;	  break;	case complain_overflow_bitfield:	  /* Much like the signed check, but for a field one bit	     wider, and no trimming inputs with addrmask.  We allow a	     bitfield to represent numbers in the range -2**n to	     2**n-1, where n is the number of bits in the field.	     Note that when bfd_vma is 32 bits, a 32-bit reloc can't	     overflow, which is exactly what we want.  */	  a >>= rightshift;	  signmask = ~ fieldmask;	  ss = a & signmask;	  if (ss != 0 && ss != (((bfd_vma) -1 >> rightshift) & signmask))	    flag = bfd_reloc_overflow;	  signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;	  b = (b ^ signmask) - signmask;	  b >>= bitpos;	  sum = a + b;	  /* We mask with addrmask here to explicitly allow an address	     wrap-around.  The Linux kernel relies on it, and it is	     the only way to write assembler code which can run when	     loaded at a location 0x80000000 away from the location at	     which it is linked.  */	  signmask = fieldmask + 1;	  if (((~ (a ^ b)) & (a ^ sum)) & signmask & addrmask)	    flag = bfd_reloc_overflow;	  break;	default:	  abort ();	}    }  /* Put RELOCATION in the right bits.  */  relocation >>= (bfd_vma) rightshift;  relocation <<= (bfd_vma) bitpos;  /* Add RELOCATION to the right bits of X.  */  x = ((x & ~howto->dst_mask)       | (((x & howto->src_mask) + relocation) & howto->dst_mask));  /* Put the relocated value back in the object file.  */  switch (size)    {    default:    case 0:      abort ();    case 1:      bfd_put_8 (input_bfd, x, location);      break;    case 2:      bfd_put_16 (input_bfd, x, location);      break;    case 4:      bfd_put_32 (input_bfd, x, location);      break;    case 8:#ifdef BFD64      bfd_put_64 (input_bfd, x, location);#else      abort ();#endif      break;    }  return flag;}/*DOCDDINODE	howto manager,  , typedef arelent, RelocationsSECTION	The howto manager	When an application wants to create a relocation, but doesn't	know what the target machine might call it, it can find out by	using this bit of code.*//*TYPEDEF	bfd_reloc_code_typeDESCRIPTION	The insides of a reloc code.  The idea is that, eventually, there	will be one enumerator for every type of relocation we ever do.	Pass one of these values to <<bfd_reloc_type_lookup>>, and it'll	return a howto pointer.	This does mean that the application must determine the correct	enumerator value; you can't get a howto pointer from a random set	of attributes.SENUM   bfd_reloc_code_realENUM  BFD_RELOC_64ENUMX  BFD_RELOC_32ENUMX  BFD_RELOC_26ENUMX  BFD_RELOC_24ENUMX  BFD_RELOC_16ENUMX  BFD_RELOC_14ENUMX  BFD_RELOC_8ENUMDOC  Basic absolute relocations of N bits.ENUM  BFD_RELOC_64_PCRELENUMX  BFD_RELOC_32_PCRELENUMX  BFD_RELOC_24_PCRELENUMX  BFD_RELOC_16_PCRELENUMX  BFD_RELOC_12_PCRELENUMX  BFD_RELOC_8_PCRELENUMDOC  PC-relative relocations.  Sometimes these are relative to the addressof the relocation itself; sometimes they are relative to the start ofthe section containing the relocation.  It depends on the specific target.The 24-bit relocation is used in some Intel 960 configurations.ENUM  BFD_RELOC_32_GOT_PCRELENUMX  BFD_RELOC_16_GOT_PCRELENUMX  BFD_RELOC_8_GOT_PCRELENUMX  BFD_RELOC_32_GOTOFFENUMX  BFD_RELOC_16_GOTOFFENUMX  BFD_RELOC_LO16_GOTOFFENUMX  BFD_RELOC_HI16_GOTOFFENUMX  BFD_RELOC_HI16_S_GOTOFFENUMX  BFD_RELOC_8_GOTOFFENUMX  BFD_RELOC_32_PLT_PCRELENUMX  BFD_RELOC_24_PLT_PCRELENUMX  BFD_RELOC_16_PLT_PCRELENUMX  BFD_RELOC_8_PLT_PCRELENUMX  BFD_RELOC_32_PLTOFFENUMX  BFD_RELOC_16_PLTOFFENUMX  BFD_RELOC_LO16_PLTOFFENUMX  BFD_RELOC_HI16_PLTOFFENUMX  BFD_RELOC_HI16_S_PLTOFFENUMX  BFD_RELOC_8_PLTOFFENUMDOC  For ELF.ENUM  BFD_RELOC_68K_GLOB_DATENUMX  BFD_RELOC_68K_JMP_SLOTENUMX  BFD_RELOC_68K_RELATIVEENUMDOC  Relocations used by 68K ELF.ENUM  BFD_RELOC_32_BASERELENUMX  BFD_RELOC_16_BASERELENUMX  BFD_RELOC_LO16_BASERELENUMX  BFD_RELOC_HI16_BASERELENUMX  BFD_RELOC_HI16_S_BASERELENUMX  BFD_RELOC_8_BASERELENUMX  BFD_RELOC_RVAENUMDOC  Linkage-table relative.ENUM  BFD_RELOC_8_FFnnENUMDOC  Absolute 8-bit relocation, but used to form an address like 0xFFnn.ENUM  BFD_RELOC_32_PCREL_S2ENUMX  BFD_RELOC_16_PCREL_S2ENUMX  BFD_RELOC_23_PCREL_S2ENUMDOC  These PC-relative relocations are stored as word displacements --i.e., byte displacements shifted right two bits.  The 30-bit worddisplacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on theSPARC.  (SPARC tools generally refer to this as <<WDISP30>>.)  Thesigned 16-bit displacement is used on the MIPS, and the 23-bitdisplacement is used on the Alpha.ENUM  BFD_RELOC_HI22ENUMX  BFD_RELOC_LO10ENUMDOC  High 22 bits and low 10 bits of 32-bit value, placed into lower bits ofthe target word.  These are used on the SPARC.ENUM  BFD_RELOC_GPREL16ENUMX  BFD_RELOC_GPREL32ENUMDOC  For systems that allocate a Global Pointer register, these aredisplacements off that register.  These relocation types arehandled specially, because the value the register will have isdecided relatively late.ENUM  BFD_RELOC_I960_CALLJENUMDOC  Reloc types used for i960/b.out.ENUM  BFD_RELOC_NONEENUMX  BFD_RELOC_SPARC_WDISP22ENUMX  BFD_RELOC_SPARC22ENUMX  BFD_RELOC_SPARC13ENUMX  BFD_RELOC_SPARC_GOT10ENUMX

⌨️ 快捷键说明

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