coff-sh.c

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

C
2,052
字号
			    &sym);      if (sym.n_scnum != 0 && sym.n_scnum != sec->target_index)	{	  ((*_bfd_error_handler)	   ("%s: 0x%lx: warning: symbol in unexpected section",	    bfd_get_filename (abfd), (unsigned long) paddr));	  continue;	}      if (sym.n_sclass != C_EXT)	{	  symval = (sym.n_value		    - sec->vma		    + sec->output_section->vma		    + sec->output_offset);	}      else	{	  struct coff_link_hash_entry *h;	  h = obj_coff_sym_hashes (abfd)[irelfn->r_symndx];	  BFD_ASSERT (h != NULL);	  if (h->root.type != bfd_link_hash_defined	      && h->root.type != bfd_link_hash_defweak)	    {	      /* This appears to be a reference to an undefined                 symbol.  Just ignore it--it will be caught by the                 regular reloc processing.  */	      continue;	    }	  symval = (h->root.u.def.value		    + h->root.u.def.section->output_section->vma		    + h->root.u.def.section->output_offset);	}      symval += bfd_get_32 (abfd, contents + paddr - sec->vma);      /* See if this function call can be shortened.  */      foff = (symval	      - (irel->r_vaddr		 - sec->vma		 + sec->output_section->vma		 + sec->output_offset		 + 4));      if (foff < -0x1000 || foff >= 0x1000)	{	  /* After all that work, we can't shorten this function call.  */	  continue;	}      /* Shorten the function call.  */      /* For simplicity of coding, we are going to modify the section	 contents, the section relocs, and the BFD symbol table.  We	 must tell the rest of the code not to free up this	 information.  It would be possible to instead create a table	 of changes which have to be made, as is done in coff-mips.c;	 that would be more work, but would require less memory when	 the linker is run.  */      if (coff_section_data (abfd, sec) == NULL)	{	  sec->used_by_bfd =	    ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata)));	  if (sec->used_by_bfd == NULL)	    goto error_return;	}      coff_section_data (abfd, sec)->relocs = internal_relocs;      coff_section_data (abfd, sec)->keep_relocs = true;      free_relocs = NULL;      coff_section_data (abfd, sec)->contents = contents;      coff_section_data (abfd, sec)->keep_contents = true;      free_contents = NULL;      obj_coff_keep_syms (abfd) = true;      /* Replace the jsr with a bsr.  */      /* Change the R_SH_USES reloc into an R_SH_PCDISP reloc, and         replace the jsr with a bsr.  */      irel->r_type = R_SH_PCDISP;      irel->r_symndx = irelfn->r_symndx;      if (sym.n_sclass != C_EXT)	{	  /* If this needs to be changed because of future relaxing,             it will be handled here like other internal PCDISP             relocs.  */	  bfd_put_16 (abfd,		      0xb000 | ((foff >> 1) & 0xfff),		      contents + irel->r_vaddr - sec->vma);	}      else	{	  /* We can't fully resolve this yet, because the external             symbol value may be changed by future relaxing.  We let             the final link phase handle it.  */	  bfd_put_16 (abfd, 0xb000, contents + irel->r_vaddr - sec->vma);	}      /* See if there is another R_SH_USES reloc referring to the same         register load.  */      for (irelscan = internal_relocs; irelscan < irelend; irelscan++)	if (irelscan->r_type == R_SH_USES	    && laddr == irelscan->r_vaddr - sec->vma + 4 + irelscan->r_offset)	  break;      if (irelscan < irelend)	{	  /* Some other function call depends upon this register load,	     and we have not yet converted that function call.	     Indeed, we may never be able to convert it.  There is	     nothing else we can do at this point.  */	  continue;	}      /* Look for a R_SH_COUNT reloc on the location where the         function address is stored.  Do this before deleting any         bytes, to avoid confusion about the address.  */      for (irelcount = internal_relocs; irelcount < irelend; irelcount++)	if (irelcount->r_vaddr == paddr	    && irelcount->r_type == R_SH_COUNT)	  break;      /* Delete the register load.  */      if (! sh_relax_delete_bytes (abfd, sec, laddr, 2))	goto error_return;      /* That will change things, so, just in case it permits some         other function call to come within range, we should relax         again.  Note that this is not required, and it may be slow.  */      *again = true;      /* Now check whether we got a COUNT reloc.  */      if (irelcount >= irelend)	{	  ((*_bfd_error_handler)	   ("%s: 0x%lx: warning: could not find expected COUNT reloc",	    bfd_get_filename (abfd), (unsigned long) paddr));	  continue;	}      /* The number of uses is stored in the r_offset field.  We've         just deleted one.  */      if (irelcount->r_offset == 0)	{	  ((*_bfd_error_handler) ("%s: 0x%lx: warning: bad count",				  bfd_get_filename (abfd),				  (unsigned long) paddr));	  continue;	}      --irelcount->r_offset;      /* If there are no more uses, we can delete the address.  Reload         the address from irelfn, in case it was changed by the         previous call to sh_relax_delete_bytes.  */      if (irelcount->r_offset == 0)	{	  if (! sh_relax_delete_bytes (abfd, sec,				       irelfn->r_vaddr - sec->vma, 4))	    goto error_return;	}      /* We've done all we can with that function call.  */    }  /* 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 (coff_section_data (abfd, sec) != NULL	      && coff_section_data (abfd, sec)->contents != NULL)	    contents = coff_section_data (abfd, sec)->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_align_loads (abfd, sec, internal_relocs, contents, &swapped))	goto error_return;      if (swapped)	{	  if (coff_section_data (abfd, sec) == NULL)	    {	      sec->used_by_bfd =		((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata)));	      if (sec->used_by_bfd == NULL)		goto error_return;	    }	  coff_section_data (abfd, sec)->relocs = internal_relocs;	  coff_section_data (abfd, sec)->keep_relocs = true;	  free_relocs = NULL;	  coff_section_data (abfd, sec)->contents = contents;	  coff_section_data (abfd, sec)->keep_contents = true;	  free_contents = NULL;	  obj_coff_keep_syms (abfd) = true;	}    }  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 coff_link_input_bfd.  */	  if (coff_section_data (abfd, sec) == NULL)	    {	      sec->used_by_bfd =		((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata)));	      if (sec->used_by_bfd == NULL)		goto error_return;	      coff_section_data (abfd, sec)->relocs = NULL;	    }	  coff_section_data (abfd, sec)->contents = contents;	}    }  return true; error_return:  if (free_relocs != NULL)    free (free_relocs);  if (free_contents != NULL)    free (free_contents);  return false;}/* Delete some bytes from a section while relaxing.  */static booleansh_relax_delete_bytes (abfd, sec, addr, count)     bfd *abfd;     asection *sec;     bfd_vma addr;     int count;{  bfd_byte *contents;  struct internal_reloc *irel, *irelend;  struct internal_reloc *irelalign;  bfd_vma toaddr;  bfd_byte *esym, *esymend;  bfd_size_type symesz;  struct coff_link_hash_entry **sym_hash;  asection *o;  contents = coff_section_data (abfd, sec)->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 = coff_section_data (abfd, sec)->relocs;  irelend = irel + sec->reloc_count;  for (; irel < irelend; irel++)    {      if (irel->r_type == R_SH_ALIGN	  && irel->r_vaddr - sec->vma > addr	  && count < (1 << irel->r_offset))	{	  irelalign = irel;	  toaddr = irel->r_vaddr - sec->vma;	  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 = coff_section_data (abfd, sec)->relocs; irel < irelend; irel++)    {      bfd_vma nraddr, stop;      bfd_vma start = 0;      int insn = 0;      struct internal_syment sym;      int off, adjust, oinsn;      bfd_signed_vma voff = 0;      boolean overflow;      /* Get the new reloc address.  */      nraddr = irel->r_vaddr - sec->vma;      if ((irel->r_vaddr - sec->vma > addr	   && irel->r_vaddr - sec->vma < toaddr)	  || (irel->r_type == R_SH_ALIGN	      && irel->r_vaddr - sec->vma == 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_vaddr - sec->vma >= addr	  && irel->r_vaddr - sec->vma < addr + count	  && irel->r_type != R_SH_ALIGN	  && irel->r_type != R_SH_CODE	  && irel->r_type != R_SH_DATA	  && irel->r_type != R_SH_LABEL)	irel->r_type = R_SH_UNUSED;      /* If this is a PC relative reloc, see if the range it covers         includes the bytes we have deleted.  */      switch (irel->r_type)	{	default:	  break;	case R_SH_PCDISP8BY2:	case R_SH_PCDISP:	case R_SH_PCRELIMM8BY2:	case R_SH_PCRELIMM8BY4:	  start = irel->r_vaddr - sec->vma;	  insn = bfd_get_16 (abfd, contents + nraddr);	  break;	}      switch (irel->r_type)	{	default:	  start = stop = addr;	  break;	case R_SH_IMM32:#ifdef COFF_WITH_PE	case R_SH_IMM32CE:	case R_SH_IMAGEBASE:#endif	  /* 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.  */	  bfd_coff_swap_sym_in (abfd,				((bfd_byte *) obj_coff_external_syms (abfd)				 + (irel->r_symndx				    * bfd_coff_symesz (abfd))),				&sym);	  if (sym.n_sclass != C_EXT	      && sym.n_scnum == sec->target_index	      && ((bfd_vma) sym.n_value <= addr		  || (bfd_vma) sym.n_value >= toaddr))	    {	      bfd_vma val;	      val = bfd_get_32 (abfd, contents + nraddr);	      val += sym.n_value;	      if (val > addr && val < toaddr)		bfd_put_32 (abfd, val - count, contents + nraddr);	    }	  start = stop = addr;	  break;	case R_SH_PCDISP8BY2:	  off = insn & 0xff;	  if (off & 0x80)	    off -= 0x100;	  stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);	  break;	case R_SH_PCDISP:	  bfd_coff_swap_sym_in (abfd,				((bfd_byte *) obj_coff_external_syms (abfd)				 + (irel->r_symndx				    * bfd_coff_symesz (abfd))),				&sym);	  if (sym.n_sclass == C_EXT)	    start = stop = addr;	  else	    {	      off = insn & 0xfff;	      if (off & 0x800)		off -= 0x1000;	      stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);	    }

⌨️ 快捷键说明

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