coff-h8300.c

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

C
1,341
字号
  if (input_section != last_input_section)    last_reloc = NULL;  /* Only examine the relocs which might be relaxable.  */  switch (reloc->howto->type)    {    /* This is the 16/24 bit absolute branch which could become an 8 bit       pc-relative branch.  */    case R_JMP1:    case R_JMPL1:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* Get the address of the next instruction (not the reloc).  */      dot = (input_section->output_section->vma	     + input_section->output_offset + address);      /* Adjust for R_JMP1 vs R_JMPL1.  */      dot += (reloc->howto->type == R_JMP1 ? 1 : 2);      /* Compute the distance from this insn to the branch target.  */      gap = value - dot;      /* If the distance is within -128..+128 inclusive, then we can relax	 this jump.  +128 is valid since the target will move two bytes	 closer if we do relax this branch.  */      if ((int)gap >= -128 && (int)gap <= 128 )	{	  /* It's possible we may be able to eliminate this branch entirely;	     if the previous instruction is a branch around this instruction,	     and there's no label at this instruction, then we can reverse	     the condition on the previous branch and eliminate this jump.	       original:			new:		 bCC lab1			bCC' lab2		 jmp lab2		lab1:				lab1:	     This saves 4 bytes instead of two, and should be relatively	     common.  */	  if (gap <= 126	      && last_reloc	      && last_reloc->howto->type == R_PCRBYTE)	    {	      bfd_vma last_value;	      last_value = bfd_coff_reloc16_get_value (last_reloc, link_info,						       input_section) + 1;	      if (last_value == dot + 2		  && last_reloc->address + 1 == reloc->address		  && !h8300_symbol_address_p (abfd, input_section, dot - 2))		{		  reloc->howto = howto_table + 19;		  last_reloc->howto = howto_table + 18;		  last_reloc->sym_ptr_ptr = reloc->sym_ptr_ptr;		  last_reloc->addend = reloc->addend;		  shrink += 4;		  bfd_perform_slip (abfd, 4, input_section, address);		  break;		}	    }	  /* Change the reloc type.  */	  reloc->howto = reloc->howto + 1;	  /* This shrinks this section by two bytes.  */	  shrink += 2;	  bfd_perform_slip (abfd, 2, input_section, address);	}      break;    /* This is the 16 bit pc-relative branch which could become an 8 bit       pc-relative branch.  */    case R_PCRWORD:      /* Get the address of the target of this branch, add one to the value         because the addend field in PCrel jumps is off by -1.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section) + 1;      /* Get the address of the next instruction if we were to relax.  */      dot = input_section->output_section->vma +	input_section->output_offset + address;      /* Compute the distance from this insn to the branch target.  */      gap = value - dot;      /* If the distance is within -128..+128 inclusive, then we can relax	 this jump.  +128 is valid since the target will move two bytes	 closer if we do relax this branch.  */      if ((int)gap >= -128 && (int)gap <= 128 )	{	  /* Change the reloc type.  */	  reloc->howto = howto_table + 15;	  /* This shrinks this section by two bytes.  */	  shrink += 2;	  bfd_perform_slip (abfd, 2, input_section, address);	}      break;    /* This is a 16 bit absolute address in a mov.b insn, which can       become an 8 bit absolute address if it's in the right range.  */    case R_MOV16B1:      /* Get the address of the data referenced by this mov.b insn.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* The address is in 0xff00..0xffff inclusive on the h8300 or	 0xffff00..0xffffff inclusive on the h8300h, then we can	 relax this mov.b  */      if ((bfd_get_mach (abfd) == bfd_mach_h8300	   && value >= 0xff00	   && value <= 0xffff)	  || ((bfd_get_mach (abfd) == bfd_mach_h8300h	       || bfd_get_mach (abfd) == bfd_mach_h8300s)	      && value >= 0xffff00	      && value <= 0xffffff))	{	  /* Change the reloc type.  */	  reloc->howto = reloc->howto + 1;	  /* This shrinks this section by two bytes.  */	  shrink += 2;	  bfd_perform_slip (abfd, 2, input_section, address);	}      break;    /* Similarly for a 24 bit absolute address in a mov.b.  Note that       if we can't relax this into an 8 bit absolute, we'll fall through       and try to relax it into a 16bit absolute.  */    case R_MOV24B1:      /* Get the address of the data referenced by this mov.b insn.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* The address is in 0xffff00..0xffffff inclusive on the h8300h,	 then we can relax this mov.b  */      if ((bfd_get_mach (abfd) == bfd_mach_h8300h	   || bfd_get_mach (abfd) == bfd_mach_h8300s)	  && value >= 0xffff00	  && value <= 0xffffff)	{	  /* Change the reloc type.  */	  reloc->howto = reloc->howto + 1;	  /* This shrinks this section by four bytes.  */	  shrink += 4;	  bfd_perform_slip (abfd, 4, input_section, address);	  /* Done with this reloc.  */	  break;	}      /* FALLTHROUGH and try to turn the 32/24 bit reloc into a 16 bit	 reloc.  */    /* This is a 24/32 bit absolute address in a mov insn, which can       become an 16 bit absolute address if it's in the right range.  */    case R_MOVL1:      /* Get the address of the data referenced by this mov insn.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* If this address is in 0x0000..0x7fff inclusive or         0xff8000..0xffffff inclusive, then it can be relaxed.  */      if (value <= 0x7fff || value >= 0xff8000)	{	  /* Change the reloc type.  */	  reloc->howto = howto_table + 17;	  /* This shrinks this section by two bytes.  */	  shrink += 2;	  bfd_perform_slip (abfd, 2, input_section, address);	}      break;      /* No other reloc types represent relaxing opportunities.  */    default:      break;    }  last_reloc = reloc;  last_input_section = input_section;  return shrink;}/* Handle relocations for the H8/300, including relocs for relaxed   instructions.   FIXME: Not all relocations check for overflow!  */static voidh8300_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr,			   dst_ptr)     bfd *abfd;     struct bfd_link_info *link_info;     struct bfd_link_order *link_order;     arelent *reloc;     bfd_byte *data;     unsigned int *src_ptr;     unsigned int *dst_ptr;{  unsigned int src_address = *src_ptr;  unsigned int dst_address = *dst_ptr;  asection *input_section = link_order->u.indirect.section;  bfd_vma value;  bfd_vma dot;  int gap, tmp;  switch (reloc->howto->type)    {    /* Generic 8bit pc-relative relocation.  */    case R_PCRBYTE:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      dot = (link_order->offset	     + dst_address	     + link_order->u.indirect.section->output_section->vma);      gap = value - dot;      /* Sanity check.  */      if (gap < -128 || gap > 126)	{	  if (! ((*link_info->callbacks->reloc_overflow)		 (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),		  reloc->howto->name, reloc->addend, input_section->owner,		  input_section, reloc->address)))	    abort ();	}      /* Everything looks OK.  Apply the relocation and update the	 src/dst address appropriately.  */      bfd_put_8 (abfd, gap, data + dst_address);      dst_address++;      src_address++;      /* All done.  */      break;    /* Generic 16bit pc-relative relocation.  */    case R_PCRWORD:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* Get the address of the instruction (not the reloc).  */      dot = (link_order->offset	     + dst_address	     + link_order->u.indirect.section->output_section->vma + 1);      gap = value - dot;      /* Sanity check.  */      if (gap > 32766 || gap < -32768)	{	  if (! ((*link_info->callbacks->reloc_overflow)		 (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),		  reloc->howto->name, reloc->addend, input_section->owner,		  input_section, reloc->address)))	    abort ();	}      /* Everything looks OK.  Apply the relocation and update the	 src/dst address appropriately.  */      bfd_put_16 (abfd, gap, data + dst_address);      dst_address += 2;      src_address += 2;      /* All done.  */      break;    /* Generic 8bit absolute relocation.  */    case R_RELBYTE:      /* Get the address of the object referenced by this insn.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* Sanity check.  */      if (value <= 0xff	  || (value >= 0x0000ff00 && value <= 0x0000ffff)  	  || (value >= 0x00ffff00 && value <= 0x00ffffff)	  || (value >= 0xffffff00 && value <= 0xffffffff))	{	  /* Everything looks OK.  Apply the relocation and update the	     src/dst address appropriately.  */	  bfd_put_8 (abfd, value & 0xff, data + dst_address);	  dst_address += 1;	  src_address += 1;	}      else	{	  if (! ((*link_info->callbacks->reloc_overflow)		 (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),		  reloc->howto->name, reloc->addend, input_section->owner,		  input_section, reloc->address)))	    abort ();	}      /* All done.  */      break;    /* Various simple 16bit absolute relocations.  */    case R_MOV16B1:    case R_JMP1:    case R_RELWORD:      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      bfd_put_16 (abfd, value, data + dst_address);      dst_address += 2;      src_address += 2;      break;    /* Various simple 24/32bit absolute relocations.  */    case R_MOV24B1:    case R_MOVL1:    case R_RELLONG:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      bfd_put_32 (abfd, value, data + dst_address);      dst_address += 4;      src_address += 4;      break;    /* Another 24/32bit absolute relocation.  */    case R_JMPL1:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      value = ((value & 0x00ffffff)	       | (bfd_get_32 (abfd, data + src_address) & 0xff000000));      bfd_put_32 (abfd, value, data + dst_address);      dst_address += 4;      src_address += 4;      break;    /* A 16bit abolute relocation that was formerlly a 24/32bit       absolute relocation.  */    case R_MOVL2:      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* Sanity check.  */      if (value <= 0x7fff || value >= 0xff8000)	{	  /* Insert the 16bit value into the proper location.  */	  bfd_put_16 (abfd, value, data + dst_address);	  /* Fix the opcode.  For all the move insns, we simply	     need to turn off bit 0x20 in the previous byte.  */          data[dst_address - 1] &= ~0x20;	  dst_address += 2;	  src_address += 4;	}      else	{	  if (! ((*link_info->callbacks->reloc_overflow)		 (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),		  reloc->howto->name, reloc->addend, input_section->owner,		  input_section, reloc->address)))	    abort ();        }      break;    /* A 16bit absolute branch that is now an 8-bit pc-relative branch.  */    case R_JMP2:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* Get the address of the next instruction.  */      dot = (link_order->offset	     + dst_address	     + link_order->u.indirect.section->output_section->vma + 1);      gap = value - dot;      /* Sanity check.  */      if (gap < -128 || gap > 126)	{	  if (! ((*link_info->callbacks->reloc_overflow)		 (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),		  reloc->howto->name, reloc->addend, input_section->owner,		  input_section, reloc->address)))	    abort ();	}      /* Now fix the instruction itself.  */      switch (data[dst_address - 1])	{	case 0x5e:	  /* jsr -> bsr */	  bfd_put_8 (abfd, 0x55, data + dst_address - 1);	  break;	case 0x5a:	  /* jmp ->bra */	  bfd_put_8 (abfd, 0x40, data + dst_address - 1);	  break;	default:	  abort ();	}      /* Write out the 8bit value.  */      bfd_put_8 (abfd, gap, data + dst_address);      dst_address += 1;      src_address += 3;      break;    /* A 16bit pc-relative branch that is now an 8-bit pc-relative branch.  */    case R_PCRWORD_B:      /* Get the address of the target of this branch.  */      value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);      /* Get the address of the instruction (not the reloc).  */      dot = (link_order->offset	     + dst_address	     + link_order->u.indirect.section->output_section->vma - 1);      gap = value - dot;      /* Sanity check.  */      if (gap < -128 || gap > 126)	{	  if (! ((*link_info->callbacks->reloc_overflow)		 (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),		  reloc->howto->name, reloc->addend, input_section->owner,		  input_section, reloc->address)))	    abort ();	}      /* Now fix the instruction.  */      switch (data[dst_address - 2])	{	case 0x58:	  /* bCC:16 -> bCC:8 */	  /* Get the condition code from the original insn.  */	  tmp = data[dst_address - 1];	  tmp &= 0xf0;	  tmp >>= 4;	  /* Now or in the high nibble of the opcode.  */	  tmp |= 0x40;	  /* Write it.  */	  bfd_put_8 (abfd, tmp, data + dst_address - 2);	  break;

⌨️ 快捷键说明

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