coff-alpha.c

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

C
2,226
字号
      /* Add the section VMA and the symbol value.  */      relocation = (h->root.u.def.value		    + hsec->output_section->vma		    + hsec->output_offset);    }  else    {      /* Change the symndx value to the right one for	 the output BFD.  */      r_symndx = h->indx;      if (r_symndx == -1)	{	  /* Caller must give an error.  */	  r_symndx = 0;	}      relocation = 0;    }  /* Write out the new r_symndx value.  */  bfd_h_put_32 (input_bfd, (bfd_vma) r_symndx,		(bfd_byte *) ext_rel->r_symndx);  return relocation;}/* Relocate a section while linking an Alpha ECOFF file.  This is   quite similar to get_relocated_section_contents.  Perhaps they   could be combined somehow.  */static booleanalpha_relocate_section (output_bfd, info, input_bfd, input_section,			contents, external_relocs)     bfd *output_bfd;     struct bfd_link_info *info;     bfd *input_bfd;     asection *input_section;     bfd_byte *contents;     PTR external_relocs;{  asection **symndx_to_section, *lita_sec;  struct ecoff_link_hash_entry **sym_hashes;  bfd_vma gp;  boolean gp_undefined;  bfd_vma stack[RELOC_STACKSIZE];  int tos = 0;  struct external_reloc *ext_rel;  struct external_reloc *ext_rel_end;  /* We keep a table mapping the symndx found in an internal reloc to     the appropriate section.  This is faster than looking up the     section by name each time.  */  symndx_to_section = ecoff_data (input_bfd)->symndx_to_section;  if (symndx_to_section == (asection **) NULL)    {      symndx_to_section = ((asection **)			   bfd_alloc (input_bfd,				      (NUM_RELOC_SECTIONS				       * sizeof (asection *))));      if (!symndx_to_section)	return false;      symndx_to_section[RELOC_SECTION_NONE] = NULL;      symndx_to_section[RELOC_SECTION_TEXT] =	bfd_get_section_by_name (input_bfd, ".text");      symndx_to_section[RELOC_SECTION_RDATA] =	bfd_get_section_by_name (input_bfd, ".rdata");      symndx_to_section[RELOC_SECTION_DATA] =	bfd_get_section_by_name (input_bfd, ".data");      symndx_to_section[RELOC_SECTION_SDATA] =	bfd_get_section_by_name (input_bfd, ".sdata");      symndx_to_section[RELOC_SECTION_SBSS] =	bfd_get_section_by_name (input_bfd, ".sbss");      symndx_to_section[RELOC_SECTION_BSS] =	bfd_get_section_by_name (input_bfd, ".bss");      symndx_to_section[RELOC_SECTION_INIT] =	bfd_get_section_by_name (input_bfd, ".init");      symndx_to_section[RELOC_SECTION_LIT8] =	bfd_get_section_by_name (input_bfd, ".lit8");      symndx_to_section[RELOC_SECTION_LIT4] =	bfd_get_section_by_name (input_bfd, ".lit4");      symndx_to_section[RELOC_SECTION_XDATA] =	bfd_get_section_by_name (input_bfd, ".xdata");      symndx_to_section[RELOC_SECTION_PDATA] =	bfd_get_section_by_name (input_bfd, ".pdata");      symndx_to_section[RELOC_SECTION_FINI] =	bfd_get_section_by_name (input_bfd, ".fini");      symndx_to_section[RELOC_SECTION_LITA] =	bfd_get_section_by_name (input_bfd, ".lita");      symndx_to_section[RELOC_SECTION_ABS] = bfd_abs_section_ptr;      symndx_to_section[RELOC_SECTION_RCONST] =	bfd_get_section_by_name (input_bfd, ".rconst");      ecoff_data (input_bfd)->symndx_to_section = symndx_to_section;    }  sym_hashes = ecoff_data (input_bfd)->sym_hashes;  /* On the Alpha, the .lita section must be addressable by the global     pointer.  To support large programs, we need to allow multiple     global pointers.  This works as long as each input .lita section     is <64KB big.  This implies that when producing relocatable     output, the .lita section is limited to 64KB. .  */  lita_sec = symndx_to_section[RELOC_SECTION_LITA];  gp = _bfd_get_gp_value (output_bfd);  if (! info->relocateable && lita_sec != NULL)    {      struct ecoff_section_tdata *lita_sec_data;      /* Make sure we have a section data structure to which we can	 hang on to the gp value we pick for the section.  */      lita_sec_data = ecoff_section_data (input_bfd, lita_sec);      if (lita_sec_data == NULL)	{	  lita_sec_data = ((struct ecoff_section_tdata *)			   bfd_zalloc (input_bfd,				       sizeof (struct ecoff_section_tdata)));	  ecoff_section_data (input_bfd, lita_sec) = lita_sec_data;	}      if (lita_sec_data->gp != 0)	{	  /* If we already assigned a gp to this section, we better	     stick with that value.  */	  gp = lita_sec_data->gp;	}      else	{	  bfd_vma lita_vma;	  bfd_size_type lita_size;	  lita_vma = lita_sec->output_offset + lita_sec->output_section->vma;	  lita_size = lita_sec->_cooked_size;	  if (lita_size == 0)	    lita_size = lita_sec->_raw_size;	  if (gp == 0	      || lita_vma <  gp - 0x8000	      || lita_vma + lita_size >= gp + 0x8000)	    {	      /* Either gp hasn't been set at all or the current gp		 cannot address this .lita section.  In both cases we		 reset the gp to point into the "middle" of the		 current input .lita section.  */	      if (gp && !ecoff_data (output_bfd)->issued_multiple_gp_warning)		{		  (*info->callbacks->warning) (info,					       _("using multiple gp values"),					       (char *) NULL, output_bfd,					       (asection *) NULL, (bfd_vma) 0);		  ecoff_data (output_bfd)->issued_multiple_gp_warning = true;		}	      if (lita_vma < gp - 0x8000)		gp = lita_vma + lita_size - 0x8000;	      else		gp = lita_vma + 0x8000;	    }	  lita_sec_data->gp = gp;	}      _bfd_set_gp_value (output_bfd, gp);    }  gp_undefined = (gp == 0);  BFD_ASSERT (bfd_header_little_endian (output_bfd));  BFD_ASSERT (bfd_header_little_endian (input_bfd));  ext_rel = (struct external_reloc *) external_relocs;  ext_rel_end = ext_rel + input_section->reloc_count;  for (; ext_rel < ext_rel_end; ext_rel++)    {      bfd_vma r_vaddr;      unsigned long r_symndx;      int r_type;      int r_extern;      int r_offset;      int r_size;      boolean relocatep;      boolean adjust_addrp;      boolean gp_usedp;      bfd_vma addend;      r_vaddr = bfd_h_get_64 (input_bfd, (bfd_byte *) ext_rel->r_vaddr);      r_symndx = bfd_h_get_32 (input_bfd, (bfd_byte *) ext_rel->r_symndx);      r_type = ((ext_rel->r_bits[0] & RELOC_BITS0_TYPE_LITTLE)		>> RELOC_BITS0_TYPE_SH_LITTLE);      r_extern = (ext_rel->r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0;      r_offset = ((ext_rel->r_bits[1] & RELOC_BITS1_OFFSET_LITTLE)		  >> RELOC_BITS1_OFFSET_SH_LITTLE);      /* Ignored the reserved bits.  */      r_size = ((ext_rel->r_bits[3] & RELOC_BITS3_SIZE_LITTLE)		>> RELOC_BITS3_SIZE_SH_LITTLE);      relocatep = false;      adjust_addrp = true;      gp_usedp = false;      addend = 0;      switch (r_type)	{	default:	  abort ();	case ALPHA_R_IGNORE:	  /* This reloc appears after a GPDISP reloc.  On earlier	     versions of OSF/1, It marked the position of the second	     instruction to be altered by the GPDISP reloc, but it is	     not otherwise used for anything.  For some reason, the	     address of the relocation does not appear to include the	     section VMA, unlike the other relocation types.  */	  if (info->relocateable)	    bfd_h_put_64 (input_bfd,			  input_section->output_offset + r_vaddr,			  (bfd_byte *) ext_rel->r_vaddr);	  adjust_addrp = false;	  break;	case ALPHA_R_REFLONG:	case ALPHA_R_REFQUAD:	case ALPHA_R_HINT:	  relocatep = true;	  break;	case ALPHA_R_BRADDR:	case ALPHA_R_SREL16:	case ALPHA_R_SREL32:	case ALPHA_R_SREL64:	  if (r_extern)	    addend += - (r_vaddr + 4);	  relocatep = true;	  break;	case ALPHA_R_GPREL32:	  /* This relocation is used in a switch table.  It is a 32	     bit offset from the current GP value.  We must adjust it	     by the different between the original GP value and the	     current GP value.  */	  relocatep = true;	  addend = ecoff_data (input_bfd)->gp - gp;	  gp_usedp = true;	  break;	case ALPHA_R_LITERAL:	  /* This is a reference to a literal value, generally	     (always?) in the .lita section.  This is a 16 bit GP	     relative relocation.  Sometimes the subsequent reloc is a	     LITUSE reloc, which indicates how this reloc is used.	     This sometimes permits rewriting the two instructions	     referred to by the LITERAL and the LITUSE into different	     instructions which do not refer to .lita.  This can save	     a memory reference, and permits removing a value from	     .lita thus saving GP relative space.	     We do not these optimizations.  To do them we would need	     to arrange to link the .lita section first, so that by	     the time we got here we would know the final values to	     use.  This would not be particularly difficult, but it is	     not currently implemented.  */	  /* I believe that the LITERAL reloc will only apply to a ldq	     or ldl instruction, so check my assumption.  */	  {	    unsigned long insn;	    insn = bfd_get_32 (input_bfd,			       contents + r_vaddr - input_section->vma);	    BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29			|| ((insn >> 26) & 0x3f) == 0x28);	  }	  relocatep = true;	  addend = ecoff_data (input_bfd)->gp - gp;	  gp_usedp = true;	  break;	case ALPHA_R_LITUSE:	  /* See ALPHA_R_LITERAL above for the uses of this reloc.  It	     does not cause anything to happen, itself.  */	  break;	case ALPHA_R_GPDISP:	  /* This marks the ldah of an ldah/lda pair which loads the	     gp register with the difference of the gp value and the	     current location.  The second of the pair is r_symndx	     bytes ahead.  It used to be marked with an ALPHA_R_IGNORE	     reloc, but OSF/1 3.2 no longer does that.  */	  {	    unsigned long insn1, insn2;	    /* Get the two instructions.  */	    insn1 = bfd_get_32 (input_bfd,				contents + r_vaddr - input_section->vma);	    insn2 = bfd_get_32 (input_bfd,				(contents				 + r_vaddr				 - input_section->vma				 + r_symndx));	    BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */	    BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */	    /* Get the existing addend.  We must account for the sign	       extension done by lda and ldah.  */	    addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff);	    if (insn1 & 0x8000)	      {		/* This is addend -= 0x100000000 without causing an		   integer overflow on a 32 bit host.  */		addend -= 0x80000000;		addend -= 0x80000000;	      }	    if (insn2 & 0x8000)	      addend -= 0x10000;	    /* The existing addend includes the difference between the	       gp of the input BFD and the address in the input BFD.	       We want to change this to the difference between the	       final GP and the final address.  */	    addend += (gp		       - ecoff_data (input_bfd)->gp		       + input_section->vma		       - (input_section->output_section->vma			  + input_section->output_offset));	    /* Change the instructions, accounting for the sign	       extension, and write them out.  */	    if (addend & 0x8000)	      addend += 0x10000;	    insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff);	    insn2 = (insn2 & 0xffff0000) | (addend & 0xffff);	    bfd_put_32 (input_bfd, (bfd_vma) insn1,			contents + r_vaddr - input_section->vma);	    bfd_put_32 (input_bfd, (bfd_vma) insn2,			contents + r_vaddr - input_section->vma + r_symndx);	    gp_usedp = true;	  }	  break;	case ALPHA_R_OP_PUSH:	case ALPHA_R_OP_PSUB:	case ALPHA_R_OP_PRSHIFT:	  /* Manipulate values on the reloc evaluation stack.  The	     r_vaddr field is not an address in input_section, it is	     the current value (including any addend) of the object	     being used.  */	  if (! r_extern)	    {	      asection *s;	      s = symndx_to_section[r_symndx];	      if (s == (asection *) NULL)		abort ();	      addend = s->output_section->vma + s->output_offset - s->vma;	    }	  else	    {	      struct ecoff_link_hash_entry *h;	      h = sym_hashes[r_symndx];	      if (h == (struct ecoff_link_hash_entry *) NULL)		abort ();	      if (! info->relocateable)		{		  if (h->root.type == bfd_link_hash_defined		      || h->root.type == bfd_link_hash_defweak)		    addend = (h->root.u.def.value			      + h->root.u.def.section->output_section->vma			      + h->root.u.def.section->output_offset);		  else		    {		      /* Note that we pass the address as 0, since we			 do not have a meaningful number for the			 location within the section that is being			 relocated.  */		      if (! ((*info->callbacks->undefined_symbol)			     (info, h->root.root.string, input_bfd,			      input_section, (bfd_vma) 0, true)))			return false;		      addend = 0;		    }		}	      else		{		  if (h->root.type != bfd_link_hash_defined		      && h->root.type != bfd_link_hash_defweak		      && h->indx == -1)		    {		      /* This symbol is not being written out.  Pass			 the address as 0, as with undefined_symbol,			 above.  */		      if (! ((*info->callbacks->unattached_reloc)			     (info, h->root.root.string, input_bfd,			      input_section, (bfd_vma) 0)))			return false;		    }		  addend = alpha_convert_external_reloc (output_bfd, info,							 input_bfd,							 ext_rel, h);		}	    }	  addend += r_vaddr;	  if (info->relocateable)	    {	      /* Adjust r_vaddr by the addend.  */	      bfd_h_put_64 (input_bfd, addend,			    (bfd_byte *) ext_rel->r_vaddr);	    }	  else	    {	      switch (r_type)		{		case ALPHA_R_OP_PUSH:		  if (tos >= RELOC_STACKSIZE)		    abort ();		  stack[tos++] = addend;		  break;		case ALPHA_R_OP_PSUB:		  if (tos == 0)		    abort ();		  stack[tos - 1] -= addend;		  break;		case ALPHA_R_OP_PRSHIFT:		  if (tos == 0)		    abort ();		  stack[tos - 1] >>= addend;		  break;		}	    }	  adjust_addrp = false;	  break;	case ALPHA_R_OP_STORE:

⌨️ 快捷键说明

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