⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elf-m10200.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 3 页
字号:
static booleanmn10200_elf_relax_section (abfd, sec, link_info, again)     bfd *abfd;     asection *sec;     struct bfd_link_info *link_info;     boolean *again;{  Elf_Internal_Shdr *symtab_hdr;  Elf_Internal_Rela *internal_relocs;  Elf_Internal_Rela *free_relocs = NULL;  Elf_Internal_Rela *irel, *irelend;  bfd_byte *contents = NULL;  bfd_byte *free_contents = NULL;  Elf32_External_Sym *extsyms = NULL;  Elf32_External_Sym *free_extsyms = NULL;  /* Assume nothing changes.  */  *again = false;  /* We don't have to do anything for a relocateable link, if     this section does not have relocs, or if this is not a     code section.  */  if (link_info->relocateable      || (sec->flags & SEC_RELOC) == 0      || sec->reloc_count == 0      || (sec->flags & SEC_CODE) == 0)    return true;  /* If this is the first time we have been called for this section,     initialize the cooked size.  */  if (sec->_cooked_size == 0)    sec->_cooked_size = sec->_raw_size;  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;  /* Get a copy of the native relocations.  */  internal_relocs = (_bfd_elf32_link_read_relocs		     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,		      link_info->keep_memory));  if (internal_relocs == NULL)    goto error_return;  if (! link_info->keep_memory)    free_relocs = internal_relocs;  /* Walk through them looking for relaxing opportunities.  */  irelend = internal_relocs + sec->reloc_count;  for (irel = internal_relocs; irel < irelend; irel++)    {      bfd_vma symval;      /* If this isn't something that can be relaxed, then ignore	 this reloc.  */      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_NONE	  || ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_8	  || ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_MAX)	continue;      /* Get the section contents if we haven't done so already.  */      if (contents == NULL)	{	  /* Get cached copy if it exists.  */	  if (elf_section_data (sec)->this_hdr.contents != NULL)	    contents = elf_section_data (sec)->this_hdr.contents;	  else	    {	      /* Go get them off disk.  */	      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;	    }	}      /* Read this BFD's symbols if we haven't done so already.  */      if (extsyms == NULL)	{	  /* Get cached copy if it exists.  */	  if (symtab_hdr->contents != NULL)	    extsyms = (Elf32_External_Sym *) symtab_hdr->contents;	  else	    {	      /* Go get them off disk.  */	      extsyms = ((Elf32_External_Sym *)			 bfd_malloc (symtab_hdr->sh_size));	      if (extsyms == NULL)		goto error_return;	      free_extsyms = extsyms;	      if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0		  || (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd)		      != symtab_hdr->sh_size))		goto error_return;	    }	}      /* Get the value of the symbol referred to by the reloc.  */      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)	{	  Elf_Internal_Sym isym;	  asection *sym_sec;	  /* A local symbol.  */	  bfd_elf32_swap_symbol_in (abfd,				    extsyms + ELF32_R_SYM (irel->r_info),				    &isym);	  sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);	  symval = (isym.st_value		    + sym_sec->output_section->vma		    + sym_sec->output_offset);	}      else	{	  unsigned long indx;	  struct elf_link_hash_entry *h;	  /* An external symbol.  */	  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;	  h = elf_sym_hashes (abfd)[indx];	  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);	}      /* 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.  */      /* Try to turn a 24bit pc-relative branch/call into a 16bit pc-relative	 branch/call.  */      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_PCREL24)	{	  bfd_vma value = symval;	  /* Deal with pc-relative gunk.  */	  value -= (sec->output_section->vma + sec->output_offset);	  value -= (irel->r_offset + 3);	  value += irel->r_addend;	  /* See if the value will fit in 16 bits, note the high value is	     0x7fff + 2 as the target will be two bytes closer if we are	     able to relax.  */	  if ((long) value < 0x8001 && (long) value > -0x8000)	    {	      unsigned char code;	      /* Get the opcode.  */	      code = bfd_get_8 (abfd, contents + irel->r_offset - 1);	      if (code != 0xe0 && code != 0xe1)		continue;	      /* Note that we've changed the relocs, section contents, etc.  */	      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;	      /* Fix the opcode.  */	      if (code == 0xe0)		bfd_put_8 (abfd, 0xfc, contents + irel->r_offset - 2);	      else if (code == 0xe1)		bfd_put_8 (abfd, 0xfd, contents + irel->r_offset - 2);	      /* Fix the relocation's type.  */	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),					   R_MN10200_PCREL16);	      /* The opcode got shorter too, so we have to fix the offset.  */	      irel->r_offset -= 1;	      /* Delete two bytes of data.  */	      if (!mn10200_elf_relax_delete_bytes (abfd, sec,						   irel->r_offset + 1, 2))		goto error_return;	      /* That will change things, so, we should relax again.		 Note that this is not required, and it may be slow.  */	      *again = true;	    }	}      /* Try to turn a 16bit pc-relative branch into a 8bit pc-relative	 branch.  */      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_PCREL16)	{	  bfd_vma value = symval;	  /* Deal with pc-relative gunk.  */	  value -= (sec->output_section->vma + sec->output_offset);	  value -= (irel->r_offset + 2);	  value += irel->r_addend;	  /* See if the value will fit in 8 bits, note the high value is	     0x7f + 1 as the target will be one bytes closer if we are	     able to relax.  */	  if ((long) value < 0x80 && (long) value > -0x80)	    {	      unsigned char code;	      /* Get the opcode.  */	      code = bfd_get_8 (abfd, contents + irel->r_offset - 1);	      if (code != 0xfc)		continue;	      /* Note that we've changed the relocs, section contents, etc.  */	      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;	      /* Fix the opcode.  */	      bfd_put_8 (abfd, 0xea, contents + irel->r_offset - 1);	      /* Fix the relocation's type.  */	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),					   R_MN10200_PCREL8);	      /* Delete one byte of data.  */	      if (!mn10200_elf_relax_delete_bytes (abfd, sec,						   irel->r_offset + 1, 1))		goto error_return;	      /* That will change things, so, we should relax again.		 Note that this is not required, and it may be slow.  */	      *again = true;	    }	}      /* Try to eliminate an unconditional 8 bit pc-relative branch	 which immediately follows a conditional 8 bit pc-relative	 branch around the unconditional branch.	    original:		new:	    bCC lab1		bCC' lab2	    bra lab2	   lab1:	       lab1:	 This happens when the bCC can't reach lab2 at assembly time,	 but due to other relaxations it can reach at link time.  */      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_PCREL8)	{	  Elf_Internal_Rela *nrel;	  bfd_vma value = symval;	  unsigned char code;	  /* Deal with pc-relative gunk.  */	  value -= (sec->output_section->vma + sec->output_offset);	  value -= (irel->r_offset + 1);	  value += irel->r_addend;	  /* Do nothing if this reloc is the last byte in the section.  */	  if (irel->r_offset == sec->_cooked_size)	    continue;	  /* See if the next instruction is an unconditional pc-relative	     branch, more often than not this test will fail, so we	     test it first to speed things up.  */	  code = bfd_get_8 (abfd, contents + irel->r_offset + 1);	  if (code != 0xea)	    continue;	  /* Also make sure the next relocation applies to the next	     instruction and that it's a pc-relative 8 bit branch.  */	  nrel = irel + 1;	  if (nrel == irelend	      || irel->r_offset + 2 != nrel->r_offset	      || ELF32_R_TYPE (nrel->r_info) != (int) R_MN10200_PCREL8)	    continue;	  /* Make sure our destination immediately follows the	     unconditional branch.  */	  if (symval != (sec->output_section->vma + sec->output_offset			 + irel->r_offset + 3))	    continue;	  /* Now make sure we are a conditional branch.  This may not	     be necessary, but why take the chance.	     Note these checks assume that R_MN10200_PCREL8 relocs	     only occur on bCC and bCCx insns.  If they occured	     elsewhere, we'd need to know the start of this insn	     for this check to be accurate.  */	  code = bfd_get_8 (abfd, contents + irel->r_offset - 1);	  if (code != 0xe0 && code != 0xe1 && code != 0xe2	      && code != 0xe3 && code != 0xe4 && code != 0xe5	      && code != 0xe6 && code != 0xe7 && code != 0xe8	      && code != 0xe9 && code != 0xec && code != 0xed	      && code != 0xee && code != 0xef && code != 0xfc	      && code != 0xfd && code != 0xfe && code != 0xff)	    continue;	  /* We also have to be sure there is no symbol/label	     at the unconditional branch.  */	  if (mn10200_elf_symbol_address_p (abfd, sec, extsyms,					    irel->r_offset + 1))	    continue;	  /* Note that we've changed the relocs, section contents, etc.  */	  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;	  /* Reverse the condition of the first branch.  */	  switch (code)	    {	    case 0xfc:	      code = 0xfd;	      break;	    case 0xfd:	      code = 0xfc;	      break;	    case 0xfe:	      code = 0xff;	      break;	    case 0xff:	      code = 0xfe;	      break;	    case 0xe8:	      code = 0xe9;	      break;	    case 0xe9:	      code = 0xe8;	      break;	    case 0xe0:	      code = 0xe2;	      break;	    case 0xe2:	      code = 0xe0;	      break;	    case 0xe3:	      code = 0xe1;	      break;	    case 0xe1:	      code = 0xe3;	      break;	    case 0xe4:	      code = 0xe6;	      break;	    case 0xe6:	      code = 0xe4;	      break;	    case 0xe7:	      code = 0xe5;	      break;	    case 0xe5:	      code = 0xe7;	      break;	    case 0xec:	      code = 0xed;	      break;	    case 0xed:	      code = 0xec;	      break;	    case 0xee:	      code = 0xef;	      break;	    case 0xef:	      code = 0xee;	      break;	    }	  bfd_put_8 (abfd, code, contents + irel->r_offset - 1);	  /* Set the reloc type and symbol for the first branch	     from the second branch.  */	  irel->r_info = nrel->r_info;	  /* Make the reloc for the second branch a null reloc.  */	  nrel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info),				       R_MN10200_NONE);	  /* Delete two bytes of data.  */	  if (!mn10200_elf_relax_delete_bytes (abfd, sec,					       irel->r_offset + 1, 2))	    goto error_return;	  /* That will change things, so, we should relax again.	     Note that this is not required, and it may be slow.  */	  *again = true;	}      /* Try to turn a 24bit immediate, displacement or absolute address	 into a 16bit immediate, displacement or absolute address.  */      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_24)	{	  bfd_vma value = symval;	  /* See if the value will fit in 16 bits.	     We allow any 16bit match here.  We prune those we can't	     handle below.  */	  if ((long) value < 0x7fff && (long) value > -0x8000)	    {	      unsigned char code;	      /* All insns which have 24bit operands are 5 bytes long,		 the first byte will always be 0xf4, but we double check		 it just in case.  */	      /* Get the first opcode.  */	      code = bfd_get_8 (abfd, contents + irel->r_offset - 2);	      if (code != 0xf4)		continue;	      /* Get the second opcode.  */	      code = bfd_get_8 (abfd, contents + irel->r_offset - 1);	      switch (code & 0xfc)		{		/* mov imm24,dn -> mov imm16,dn */		case 0x70:		  /* Not safe if the high bit is on as relaxing may		     move the value out of high mem and thus not fit		     in a signed 16bit value.  */		  if (value & 0x8000)		    continue;		  /* Note that we've changed the reldection contents, etc.  */		  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;		  /* Fix the opcode.  */		  bfd_put_8 (abfd, 0xf8 + (code & 0x03),			     contents + irel->r_offset - 2);		  /* Fix the relocation's type.  */		  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),					       R_MN10200_16);		  /* The opcode got shorter too, so we have to fix the		     offset.  */		  irel->r_offset -= 1;		  /* Delete two bytes of data.  */		  if (!mn10200_elf_relax_delete_bytes (abfd, sec,						       irel->r_offset + 1, 2))		    goto error_return;		  /* That will change things, so, we should relax again.		     Note that this is not required, and it may be slow.  */		  *again = true;		  break;		/* mov imm24,an -> mov imm16,an		   cmp imm24,an -> cmp imm16,an		   mov (abs24),dn -> mov (abs16),dn		   mov dn,(abs24) -> mov dn,(abs16)		   movb dn,(abs24) -> movb dn,(abs16)		   movbu (abs24),dn -> movbu (abs16),dn */		case 0x74:		case 0x7c:		case 0xc0:		case 0x40:		case 0x44:		case 0xc8:		  /* Note that we've changed the reldection contents, etc.  */		  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 ((code & 0xfc) == 0x74)		    code = 0xdc + (code & 0x03);		  else if ((code & 0xfc) == 0x7c)		    code = 0xec + (code & 0x03);		  else if ((code & 0xfc) == 0xc0)

⌨️ 快捷键说明

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