elf32-sh.c

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

C
2,188
字号
    }  /* Look for load and store instructions that we can align on four     byte boundaries.  */  if (have_code)    {      boolean swapped;      /* Get the section contents.  */      if (contents == NULL)	{	  if (elf_section_data (sec)->this_hdr.contents != NULL)	    contents = elf_section_data (sec)->this_hdr.contents;	  else	    {	      contents = (bfd_byte *) bfd_malloc (sec->_raw_size);	      if (contents == NULL)		goto error_return;	      free_contents = contents;	      if (! bfd_get_section_contents (abfd, sec, contents,					      (file_ptr) 0, sec->_raw_size))		goto error_return;	    }	}      if (! sh_elf_align_loads (abfd, sec, internal_relocs, contents,				&swapped))	goto error_return;      if (swapped)	{	  elf_section_data (sec)->relocs = internal_relocs;	  free_relocs = NULL;	  elf_section_data (sec)->this_hdr.contents = contents;	  free_contents = NULL;	  symtab_hdr->contents = (bfd_byte *) extsyms;	  free_extsyms = NULL;	}    }  if (free_relocs != NULL)    {      free (free_relocs);      free_relocs = NULL;    }  if (free_contents != NULL)    {      if (! link_info->keep_memory)	free (free_contents);      else	{	  /* Cache the section contents for elf_link_input_bfd.  */	  elf_section_data (sec)->this_hdr.contents = contents;	}      free_contents = NULL;    }  if (free_extsyms != NULL)    {      if (! link_info->keep_memory)	free (free_extsyms);      else	{	  /* Cache the symbols for elf_link_input_bfd.  */	  symtab_hdr->contents = extsyms;	}      free_extsyms = NULL;    }  return true; error_return:  if (free_relocs != NULL)    free (free_relocs);  if (free_contents != NULL)    free (free_contents);  if (free_extsyms != NULL)    free (free_extsyms);  return false;}/* Delete some bytes from a section while relaxing.  FIXME: There is a   lot of duplication between this function and sh_relax_delete_bytes   in coff-sh.c.  */static booleansh_elf_relax_delete_bytes (abfd, sec, addr, count)     bfd *abfd;     asection *sec;     bfd_vma addr;     int count;{  Elf_Internal_Shdr *symtab_hdr;  Elf32_External_Sym *extsyms;  int shndx, index;  bfd_byte *contents;  Elf_Internal_Rela *irel, *irelend;  Elf_Internal_Rela *irelalign;  bfd_vma toaddr;  Elf32_External_Sym *esym, *esymend;  struct elf_link_hash_entry *sym_hash;  asection *o;  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;  extsyms = (Elf32_External_Sym *) symtab_hdr->contents;  shndx = _bfd_elf_section_from_bfd_section (abfd, sec);  contents = elf_section_data (sec)->this_hdr.contents;  /* The deletion must stop at the next ALIGN reloc for an aligment     power larger than the number of bytes we are deleting.  */  irelalign = NULL;  toaddr = sec->_cooked_size;  irel = elf_section_data (sec)->relocs;  irelend = irel + sec->reloc_count;  for (; irel < irelend; irel++)    {      if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN	  && irel->r_offset > addr	  && count < (1 << irel->r_addend))	{	  irelalign = irel;	  toaddr = irel->r_offset;	  break;	}    }  /* Actually delete the bytes.  */  memmove (contents + addr, contents + addr + count, toaddr - addr - count);  if (irelalign == NULL)    sec->_cooked_size -= count;  else    {      int i;#define NOP_OPCODE (0x0009)      BFD_ASSERT ((count & 1) == 0);      for (i = 0; i < count; i += 2)	bfd_put_16 (abfd, NOP_OPCODE, contents + toaddr - count + i);    }  /* Adjust all the relocs.  */  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)    {      bfd_vma nraddr, stop;      bfd_vma start = 0;      int insn = 0;      Elf_Internal_Sym sym;      int off, adjust, oinsn;      bfd_signed_vma voff = 0;      boolean overflow;      /* Get the new reloc address.  */      nraddr = irel->r_offset;      if ((irel->r_offset > addr	   && irel->r_offset < toaddr)	  || (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN	      && irel->r_offset == toaddr))	nraddr -= count;      /* See if this reloc was for the bytes we have deleted, in which	 case we no longer care about it.  Don't delete relocs which	 represent addresses, though.  */      if (irel->r_offset >= addr	  && irel->r_offset < addr + count	  && ELF32_R_TYPE (irel->r_info) != (int) R_SH_ALIGN	  && ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE	  && ELF32_R_TYPE (irel->r_info) != (int) R_SH_DATA	  && ELF32_R_TYPE (irel->r_info) != (int) R_SH_LABEL)	irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),				     (int) R_SH_NONE);      /* If this is a PC relative reloc, see if the range it covers         includes the bytes we have deleted.  */      switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info))	{	default:	  break;	case R_SH_DIR8WPN:	case R_SH_IND12W:	case R_SH_DIR8WPZ:	case R_SH_DIR8WPL:	  start = irel->r_offset;	  insn = bfd_get_16 (abfd, contents + nraddr);	  break;	}      switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info))	{	default:	  start = stop = addr;	  break;	case R_SH_DIR32:	  /* If this reloc is against a symbol defined in this             section, and the symbol will not be adjusted below, we             must check the addend to see it will put the value in             range to be adjusted, and hence must be changed.  */	  if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)	    {	      bfd_elf32_swap_symbol_in (abfd,					extsyms + ELF32_R_SYM (irel->r_info),					&sym);	      if (sym.st_shndx == shndx		  && (sym.st_value <= addr		      || sym.st_value >= toaddr))		{		  bfd_vma val;		  val = bfd_get_32 (abfd, contents + nraddr);		  val += sym.st_value;		  if (val > addr && val < toaddr)		    bfd_put_32 (abfd, val - count, contents + nraddr);		}	    }	  start = stop = addr;	  break;	case R_SH_DIR8WPN:	  off = insn & 0xff;	  if (off & 0x80)	    off -= 0x100;	  stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);	  break;	case R_SH_IND12W:	  if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info)	    start = stop = addr;	  else	    {	      off = insn & 0xfff;	      if (off & 0x800)		off -= 0x1000;	      stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);	    }	  break;	case R_SH_DIR8WPZ:	  off = insn & 0xff;	  stop = start + 4 + off * 2;	  break;	case R_SH_DIR8WPL:	  off = insn & 0xff;	  stop = (start & ~(bfd_vma) 3) + 4 + off * 4;	  break;	case R_SH_SWITCH8:	case R_SH_SWITCH16:	case R_SH_SWITCH32:	  /* These relocs types represent	       .word L2-L1	     The r_addend field holds the difference between the reloc	     address and L1.  That is the start of the reloc, and	     adding in the contents gives us the top.  We must adjust	     both the r_offset field and the section contents.	     N.B. in gas / coff bfd, the elf bfd r_addend is called r_offset,	     and the elf bfd r_offset is called r_vaddr.  */	  stop = irel->r_offset;	  start = (bfd_vma) ((bfd_signed_vma) stop - (long) irel->r_addend);	  if (start > addr	      && start < toaddr	      && (stop <= addr || stop >= toaddr))	    irel->r_addend += count;	  else if (stop > addr		   && stop < toaddr		   && (start <= addr || start >= toaddr))	    irel->r_addend -= count;	  if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_SWITCH16)	    voff = bfd_get_signed_16 (abfd, contents + nraddr);	  else if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_SWITCH8)	    voff = bfd_get_8 (abfd, contents + nraddr);	  else	    voff = bfd_get_signed_32 (abfd, contents + nraddr);	  stop = (bfd_vma) ((bfd_signed_vma) start + voff);	  break;	case R_SH_USES:	  start = irel->r_offset;	  stop = (bfd_vma) ((bfd_signed_vma) start			    + (long) irel->r_addend			    + 4);	  break;	}      if (start > addr	  && start < toaddr	  && (stop <= addr || stop >= toaddr))	adjust = count;      else if (stop > addr	       && stop < toaddr	       && (start <= addr || start >= toaddr))	adjust = - count;      else	adjust = 0;      if (adjust != 0)	{	  oinsn = insn;	  overflow = false;	  switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info))	    {	    default:	      abort ();	      break;	    case R_SH_DIR8WPN:	    case R_SH_DIR8WPZ:	      insn += adjust / 2;	      if ((oinsn & 0xff00) != (insn & 0xff00))		overflow = true;	      bfd_put_16 (abfd, insn, contents + nraddr);	      break;	    case R_SH_IND12W:	      insn += adjust / 2;	      if ((oinsn & 0xf000) != (insn & 0xf000))		overflow = true;	      bfd_put_16 (abfd, insn, contents + nraddr);	      break;	    case R_SH_DIR8WPL:	      BFD_ASSERT (adjust == count || count >= 4);	      if (count >= 4)		insn += adjust / 4;	      else		{		  if ((irel->r_offset & 3) == 0)		    ++insn;		}	      if ((oinsn & 0xff00) != (insn & 0xff00))		overflow = true;	      bfd_put_16 (abfd, insn, contents + nraddr);	      break;	    case R_SH_SWITCH8:	      voff += adjust;	      if (voff < 0 || voff >= 0xff)		overflow = true;	      bfd_put_8 (abfd, voff, contents + nraddr);	      break;	    case R_SH_SWITCH16:	      voff += adjust;	      if (voff < - 0x8000 || voff >= 0x8000)		overflow = true;	      bfd_put_signed_16 (abfd, voff, contents + nraddr);	      break;	    case R_SH_SWITCH32:	      voff += adjust;	      bfd_put_signed_32 (abfd, voff, contents + nraddr);	      break;	    case R_SH_USES:	      irel->r_addend += adjust;	      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;	    }	}      irel->r_offset = nraddr;    }  /* Look through all the other sections.  If there contain any IMM32     relocs against internal symbols which we are not going to adjust     below, we may need to adjust the addends.  */  for (o = abfd->sections; o != NULL; o = o->next)    {      Elf_Internal_Rela *internal_relocs;      Elf_Internal_Rela *irelscan, *irelscanend;      bfd_byte *ocontents;      if (o == sec	  || (o->flags & SEC_RELOC) == 0	  || o->reloc_count == 0)	continue;      /* We always cache the relocs.  Perhaps, if info->keep_memory is         false, we should free them, if we are permitted to, when we         leave sh_coff_relax_section.  */      internal_relocs = (_bfd_elf32_link_read_relocs			 (abfd, o, (PTR) NULL, (Elf_Internal_Rela *) NULL,			  true));      if (internal_relocs == NULL)	return false;      ocontents = NULL;      irelscanend = internal_relocs + o->reloc_count;      for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++)	{	  Elf_Internal_Sym sym;	  /* Dwarf line numbers use R_SH_SWITCH32 relocs.  */	  if (ELF32_R_TYPE (irelscan->r_info) == (int) R_SH_SWITCH32)	    {	      bfd_vma start, stop;	      bfd_signed_vma voff;	      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;

⌨️ 快捷键说明

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