elf32-sh.c

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

C
2,188
字号
		    }		}	      stop = irelscan->r_offset;	      start		= (bfd_vma) ((bfd_signed_vma) stop - (long) irelscan->r_addend);	      /* STOP is in a different section, so it won't change.  */	      if (start > addr && start < toaddr)		irelscan->r_addend += count;	      voff = bfd_get_signed_32 (abfd, ocontents + irelscan->r_offset);	      stop = (bfd_vma) ((bfd_signed_vma) start + voff);	      if (start > addr		  && start < toaddr		  && (stop <= addr || stop >= toaddr))		bfd_put_signed_32 (abfd, voff + count,				   ocontents + irelscan->r_offset);	      else if (stop > addr		       && stop < toaddr		       && (start <= addr || start >= toaddr))		bfd_put_signed_32 (abfd, voff - count,				   ocontents + irelscan->r_offset);	    }	  if (ELF32_R_TYPE (irelscan->r_info) != (int) R_SH_DIR32)	    continue;	  if (ELF32_R_SYM (irelscan->r_info) >= symtab_hdr->sh_info)	    continue;	  bfd_elf32_swap_symbol_in (abfd,				    extsyms + ELF32_R_SYM (irelscan->r_info),				    &sym);	  if (sym.st_shndx == shndx	      && (sym.st_value <= addr		  || sym.st_value >= toaddr))	    {	      bfd_vma val;	      if (ocontents == NULL)		{		  if (elf_section_data (o)->this_hdr.contents != NULL)		    ocontents = elf_section_data (o)->this_hdr.contents;		  else		    {		      /* We always cache the section contents.                         Perhaps, if info->keep_memory is false, we                         should free them, if we are permitted to,                         when we leave sh_coff_relax_section.  */		      ocontents = (bfd_byte *) bfd_malloc (o->_raw_size);		      if (ocontents == NULL)			return false;		      if (! bfd_get_section_contents (abfd, o, ocontents,						      (file_ptr) 0,						      o->_raw_size))			return false;		      elf_section_data (o)->this_hdr.contents = ocontents;		    }		}	      val = bfd_get_32 (abfd, ocontents + irelscan->r_offset);	      val += sym.st_value;	      if (val > addr && val < toaddr)		bfd_put_32 (abfd, val - count,			    ocontents + irelscan->r_offset);	    }	}    }  /* Adjust the local symbols defined in this section.  */  esym = extsyms;  esymend = esym + symtab_hdr->sh_info;  for (; esym < esymend; esym++)    {      Elf_Internal_Sym isym;      bfd_elf32_swap_symbol_in (abfd, esym, &isym);      if (isym.st_shndx == shndx	  && isym.st_value > addr	  && isym.st_value < toaddr)	{	  isym.st_value -= count;	  bfd_elf32_swap_symbol_out (abfd, &isym, esym);	}    }  /* Now adjust the global symbols defined in this section.  */  esym = extsyms + symtab_hdr->sh_info;  esymend = extsyms + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym));  for (index = 0; esym < esymend; esym++, index++)    {      Elf_Internal_Sym isym;      bfd_elf32_swap_symbol_in (abfd, esym, &isym);      sym_hash = elf_sym_hashes (abfd)[index];      if (isym.st_shndx == shndx	  && ((sym_hash)->root.type == bfd_link_hash_defined	      || (sym_hash)->root.type == bfd_link_hash_defweak)	  && (sym_hash)->root.u.def.section == sec	  && (sym_hash)->root.u.def.value > addr	  && (sym_hash)->root.u.def.value < toaddr)	{	  (sym_hash)->root.u.def.value -= count;	}    }  /* See if we can move the ALIGN reloc forward.  We have adjusted     r_offset for it already.  */  if (irelalign != NULL)    {      bfd_vma alignto, alignaddr;      alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend);      alignaddr = BFD_ALIGN (irelalign->r_offset,			     1 << irelalign->r_addend);      if (alignto != alignaddr)	{	  /* Tail recursion.  */	  return sh_elf_relax_delete_bytes (abfd, sec, alignaddr,					    alignto - alignaddr);	}    }  return true;}/* Look for loads and stores which we can align to four byte   boundaries.  This is like sh_align_loads in coff-sh.c.  */static booleansh_elf_align_loads (abfd, sec, internal_relocs, contents, pswapped)     bfd *abfd;     asection *sec;     Elf_Internal_Rela *internal_relocs;     bfd_byte *contents;     boolean *pswapped;{  Elf_Internal_Rela *irel, *irelend;  bfd_vma *labels = NULL;  bfd_vma *label, *label_end;  *pswapped = false;  irelend = internal_relocs + sec->reloc_count;  /* Get all the addresses with labels on them.  */  labels = (bfd_vma *) bfd_malloc (sec->reloc_count * sizeof (bfd_vma));  if (labels == NULL)    goto error_return;  label_end = labels;  for (irel = internal_relocs; irel < irelend; irel++)    {      if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_LABEL)	{	  *label_end = irel->r_offset;	  ++label_end;	}    }  /* Note that the assembler currently always outputs relocs in     address order.  If that ever changes, this code will need to sort     the label values and the relocs.  */  label = labels;  for (irel = internal_relocs; irel < irelend; irel++)    {      bfd_vma start, stop;      if (ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE)	continue;      start = irel->r_offset;      for (irel++; irel < irelend; irel++)	if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_DATA)	  break;      if (irel < irelend)	stop = irel->r_offset;      else	stop = sec->_cooked_size;      if (! _bfd_sh_align_load_span (abfd, sec, contents, sh_elf_swap_insns,				     (PTR) internal_relocs, &label,				     label_end, start, stop, pswapped))	goto error_return;    }  free (labels);  return true; error_return:  if (labels != NULL)    free (labels);  return false;}/* Swap two SH instructions.  This is like sh_swap_insns in coff-sh.c.  */static booleansh_elf_swap_insns (abfd, sec, relocs, contents, addr)     bfd *abfd;     asection *sec;     PTR relocs;     bfd_byte *contents;     bfd_vma addr;{  Elf_Internal_Rela *internal_relocs = (Elf_Internal_Rela *) relocs;  unsigned short i1, i2;  Elf_Internal_Rela *irel, *irelend;  /* Swap the instructions themselves.  */  i1 = bfd_get_16 (abfd, contents + addr);  i2 = bfd_get_16 (abfd, contents + addr + 2);  bfd_put_16 (abfd, i2, contents + addr);  bfd_put_16 (abfd, i1, contents + addr + 2);  /* Adjust all reloc addresses.  */  irelend = internal_relocs + sec->reloc_count;  for (irel = internal_relocs; irel < irelend; irel++)    {      enum elf_sh_reloc_type type;      int add;      /* There are a few special types of relocs that we don't want to         adjust.  These relocs do not apply to the instruction itself,         but are only associated with the address.  */      type = (enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info);      if (type == R_SH_ALIGN	  || type == R_SH_CODE	  || type == R_SH_DATA	  || type == R_SH_LABEL)	continue;      /* If an R_SH_USES reloc points to one of the addresses being         swapped, we must adjust it.  It would be incorrect to do this         for a jump, though, since we want to execute both         instructions after the jump.  (We have avoided swapping         around a label, so the jump will not wind up executing an         instruction it shouldn't).  */      if (type == R_SH_USES)	{	  bfd_vma off;	  off = irel->r_offset + 4 + irel->r_addend;	  if (off == addr)	    irel->r_offset += 2;	  else if (off == addr + 2)	    irel->r_offset -= 2;	}      if (irel->r_offset == addr)	{	  irel->r_offset += 2;	  add = -2;	}      else if (irel->r_offset == addr + 2)	{	  irel->r_offset -= 2;	  add = 2;	}      else	add = 0;      if (add != 0)	{	  bfd_byte *loc;	  unsigned short insn, oinsn;	  boolean overflow;	  loc = contents + irel->r_offset;	  overflow = false;	  switch (type)	    {	    default:	      break;	    case R_SH_DIR8WPN:	    case R_SH_DIR8WPZ:	      insn = bfd_get_16 (abfd, loc);	      oinsn = insn;	      insn += add / 2;	      if ((oinsn & 0xff00) != (insn & 0xff00))		overflow = true;	      bfd_put_16 (abfd, insn, loc);	      break;	    case R_SH_IND12W:	      insn = bfd_get_16 (abfd, loc);	      oinsn = insn;	      insn += add / 2;	      if ((oinsn & 0xf000) != (insn & 0xf000))		overflow = true;	      bfd_put_16 (abfd, insn, loc);	      break;	    case R_SH_DIR8WPL:	      /* This reloc ignores the least significant 3 bits of                 the program counter before adding in the offset.                 This means that if ADDR is at an even address, the                 swap will not affect the offset.  If ADDR is an at an                 odd address, then the instruction will be crossing a                 four byte boundary, and must be adjusted.  */	      if ((addr & 3) != 0)		{		  insn = bfd_get_16 (abfd, loc);		  oinsn = insn;		  insn += add / 2;		  if ((oinsn & 0xff00) != (insn & 0xff00))		    overflow = true;		  bfd_put_16 (abfd, insn, loc);		}	      break;	    }	  if (overflow)	    {	      ((*_bfd_error_handler)	       (_("%s: 0x%lx: fatal: reloc overflow while relaxing"),		bfd_get_filename (abfd), (unsigned long) irel->r_offset));	      bfd_set_error (bfd_error_bad_value);	      return false;	    }	}    }  return true;}/* The size in bytes of an entry in the procedure linkage table.  */#define PLT_ENTRY_SIZE 28/* First entry in an absolute procedure linkage table look like this.  */static const bfd_byte elf_sh_plt0_entry_be[PLT_ENTRY_SIZE] ={  0xd0, 0x04,	/* mov.l 1f,r0 */  0xd2, 0x05,	/* mov.l 2f,r2 */  0x60, 0x02,	/* mov.l @r0,r0 */  0x62, 0x22,	/* mov.l @r2,r2 */  0x40, 0x2b,	/* jmp @r0 */  0xe0, 0x00,	/*  mov #0,r0 */  0x00, 0x09,	/* nop */  0x00, 0x09,	/* nop */  0x00, 0x09,	/* nop */  0x00, 0x09,	/* nop */  0, 0, 0, 0,	/* 1: replaced with address of .got.plt + 8.  */  0, 0, 0, 0,	/* 2: replaced with address of .got.plt + 4.  */};static const bfd_byte elf_sh_plt0_entry_le[PLT_ENTRY_SIZE] ={  0x04, 0xd0,	/* mov.l 1f,r0 */  0x05, 0xd2,	/* mov.l 2f,r2 */  0x02, 0x60,	/* mov.l @r0,r0 */  0x22, 0x62,	/* mov.l @r2,r2 */  0x2b, 0x40,	/* jmp @r0 */  0x00, 0xe0,	/*  mov #0,r0 */  0x09, 0x00,	/* nop */  0x09, 0x00,	/* nop */  0x09, 0x00,	/* nop */  0x09, 0x00,	/* nop */  0, 0, 0, 0,	/* 1: replaced with address of .got.plt + 8.  */  0, 0, 0, 0,	/* 2: replaced with address of .got.plt + 4.  */};/* Sebsequent entries in an absolute procedure linkage table look like   this.  */static const bfd_byte elf_sh_plt_entry_be[PLT_ENTRY_SIZE] ={  0xd0, 0x04,	/* mov.l 1f,r0 */  0x60, 0x02,	/* mov.l @r0,r0 */  0xd2, 0x02,	/* mov.l 0f,r2 */  0x40, 0x2b,   /* jmp @r0 */  0x60, 0x23,	/*  mov r2,r0 */  0xd1, 0x03,	/* mov.l 2f,r1 */  0x40, 0x2b,	/* jmp @r0 */  0x00, 0x09,	/* nop */  0, 0, 0, 0,	/* 0: replaced with address of .PLT0.  */  0, 0, 0, 0,	/* 1: replaced with address of this symbol in .got.  */  0, 0, 0, 0,	/* 2: replaced with offset into relocation table.  */};static const bfd_byte elf_sh_plt_entry_le[PLT_ENTRY_SIZE] ={  0x04, 0xd0,	/* mov.l 1f,r0 */  0x02, 0x60,	/* mov.l @r0,r0 */  0x02, 0xd2,	/* mov.l 0f,r2 */  0x2b, 0x40,   /* jmp @r0 */  0x23, 0x60,	/*  mov r2,r0 */  0x03, 0xd1,	/* mov.l 2f,r1 */  0x2b, 0x40,	/* jmp @r0 */  0x09, 0x00,	/*  nop */  0, 0, 0, 0,	/* 0: replaced with address of .PLT.  */  0, 0, 0, 0,	/* 1: replaced with address of this symbol in .got.  */  0, 0, 0, 0,	/* 2: replaced with offset into relocation table.  */};/* Entries in a PIC procedure linkage table look like this.  */static const bfd_byte elf_sh_pic_plt_entry_be[PLT_ENTRY_SIZE] ={  0xd0, 0x04,	/* mov.l 1f,r0 */  0x00, 0xce,	/* mov.l @(r0,r12),r0 */  0x40, 0x2b,	/* jmp @r0 */  0x00, 0x09,	/*  nop */  0x50, 0xc2,	/* 0: mov.l @(8,r12),r0 */  0x52, 0xc1,	/* 1: mov.l @(4,r12),r2 */  0xd1, 0x02,	/* mov.l 2f,r1 */  0x40, 0x2b,	/* jmp @r0 */  0xe0, 0x00,	/*  mov #0,r0 ! shows the type of PLT.  */  0x00, 0x09,	/* nop */  0, 0, 0, 0,	/* 1: replaced with address of this symbol in .got.  */  0, 0, 0, 0    /* 2: replaced with offset into relocation table.  */};static const bfd_byte elf_sh_pic_plt_entry_le[PLT_ENTRY_SIZE] ={  0x04, 0xd0,	/* mov.l 1f,r0 */  0xce, 0x00,	/* mov.l @(r0,r12),r0 */  0x2b, 0x40,	/* jmp @r0 */  0x09, 0x00,	/*  nop */  0xc2, 0x50,	/* 0: mov.l @(8,r12),r0 */  0xc1, 0x52,	/* 1: mov.l @(4,r12),r2 */  0x02, 0xd1,	/* mov.l 2f,r1 */  0x2b, 0x40,	/* jmp @r0 */  0x00, 0xe0,	/*  mov #0,r0 ! shows the type of PLT.  */  0x09, 0x0

⌨️ 快捷键说明

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