elf32-ppc.c

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

C
1,931
字号
	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_ADDR16_LO",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* The high order 16 bits of the addend minus the symbol */  HOWTO (R_PPC_EMB_NADDR16_HI,	/* type */	 16,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_dont, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_NADDR16_HI", /* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* The high order 16 bits of the result of the addend minus the address,     plus 1 if the contents of the low 16 bits, treated as a signed number,     is negative.  */  HOWTO (R_PPC_EMB_NADDR16_HA,	/* type */	 16,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_dont, /* complain_on_overflow */	 ppc_elf_addr16_ha_reloc, /* special_function */	 "R_PPC_EMB_NADDR16_HA", /* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* 16 bit value resulting from allocating a 4 byte word to hold an     address in the .sdata section, and returning the offset from     _SDA_BASE_ for that relocation */  HOWTO (R_PPC_EMB_SDAI16,	/* type */	 0,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_bitfield, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_SDAI16",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* 16 bit value resulting from allocating a 4 byte word to hold an     address in the .sdata2 section, and returning the offset from     _SDA2_BASE_ for that relocation */  HOWTO (R_PPC_EMB_SDA2I16,	/* type */	 0,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_bitfield, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_SDA2I16",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with     small data items.	 */  HOWTO (R_PPC_EMB_SDA2REL,	/* type */	 0,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_signed, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_SDA2REL",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit     signed offset from the appropriate base, and filling in the register     field with the appropriate register (0, 2, or 13).  */  HOWTO (R_PPC_EMB_SDA21,	/* type */	 0,			/* rightshift */	 2,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_signed, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_SDA21",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* Relocation not handled: R_PPC_EMB_MRKREF */  /* Relocation not handled: R_PPC_EMB_RELSEC16 */  /* Relocation not handled: R_PPC_EMB_RELST_LO */  /* Relocation not handled: R_PPC_EMB_RELST_HI */  /* Relocation not handled: R_PPC_EMB_RELST_HA */  /* Relocation not handled: R_PPC_EMB_BIT_FLD */  /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling     in the 16 bit signed offset from the appropriate base, and filling in the     register field with the appropriate register (0, 2, or 13).  */  HOWTO (R_PPC_EMB_RELSDA,	/* type */	 0,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 true,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_signed, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_EMB_RELSDA",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */  /* GNU extension to record C++ vtable hierarchy */  HOWTO (R_PPC_GNU_VTINHERIT,	/* type */	 0,			/* rightshift */	 0,			/* size (0 = byte, 1 = short, 2 = long) */	 0,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_dont, /* complain_on_overflow */	 NULL,			/* special_function */	 "R_PPC_GNU_VTINHERIT",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0,			/* dst_mask */	 false),		/* pcrel_offset */  /* GNU extension to record C++ vtable member usage */  HOWTO (R_PPC_GNU_VTENTRY,	/* type */	 0,			/* rightshift */	 0,			/* size (0 = byte, 1 = short, 2 = long) */	 0,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_dont, /* complain_on_overflow */	 NULL,			/* special_function */	 "R_PPC_GNU_VTENTRY",	/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0,			/* dst_mask */	 false),		/* pcrel_offset */  /* Phony reloc to handle AIX style TOC entries */  HOWTO (R_PPC_TOC16,		/* type */	 0,			/* rightshift */	 1,			/* size (0 = byte, 1 = short, 2 = long) */	 16,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_signed, /* complain_on_overflow */	 bfd_elf_generic_reloc,	/* special_function */	 "R_PPC_TOC16",		/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0xffff,		/* dst_mask */	 false),		/* pcrel_offset */};/* Initialize the ppc_elf_howto_table, so that linear accesses can be done.  */static voidppc_elf_howto_init (){  unsigned int i, type;  for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++)    {      type = ppc_elf_howto_raw[i].type;      BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0]));      ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];    }}/* This function handles relaxing for the PPC with option --mpc860c0[=<n>].   The MPC860, revision C0 or earlier contains a bug in the die.   If all of the following conditions are true, the next instruction   to be executed *may* be treated as a no-op.   1/ A forward branch is executed.   2/ The branch is predicted as not taken.   3/ The branch is taken.   4/ The branch is located in the last 5 words of a page.      (The EOP limit is 5 by default but may be specified as any value from 1-10.)   Our software solution is to detect these problematic branches in a   linker pass and modify them as follows:   1/ Unconditional branches - Since these are always predicted taken,      there is no problem and no action is required.   2/ Conditional backward branches - No problem, no action required.   3/ Conditional forward branches - Ensure that the "inverse prediction      bit" is set (ensure it is predicted taken).   4/ Conditional register branches - Ensure that the "y bit" is set      (ensure it is predicted taken).*//* Sort sections by address.  */static intppc_elf_sort_rela (arg1, arg2)     const void *arg1;     const void *arg2;{  const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1;  const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2;  /* Sort by offset.  */  return ((*rela1)->r_offset - (*rela2)->r_offset);}static booleanppc_elf_relax_section (abfd, isec, link_info, again)     bfd *abfd;     asection *isec;     struct bfd_link_info *link_info;     boolean *again;{#define PAGESIZE 0x1000  bfd_byte *contents = NULL;  bfd_byte *free_contents = NULL;  Elf_Internal_Rela *internal_relocs = NULL;  Elf_Internal_Rela *free_relocs = NULL;  Elf_Internal_Rela **rela_comb = NULL;  int comb_curr, comb_count;  /* We never have to do this more than once per input section.  */  *again = false;  /* If needed, initialize this section's cooked size.  */  if (isec->_cooked_size == 0)      isec->_cooked_size = isec->_raw_size;  /* We're only interested in text sections which overlap the     troublesome area at the end of a page.  */  if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size)    {      bfd_vma dot, end_page, end_section;      boolean section_modified;      /* Get the section contents.  */      /* Get cached copy if it exists.  */      if (elf_section_data (isec)->this_hdr.contents != NULL)	  contents = elf_section_data (isec)->this_hdr.contents;      else	{	  /* Go get them off disk.  */	  contents = (bfd_byte *) bfd_malloc (isec->_raw_size);	  if (contents == NULL)	    goto error_return;	  free_contents = contents;	  if (! bfd_get_section_contents (abfd, isec, contents,					  (file_ptr) 0, isec->_raw_size))	    goto error_return;	}      comb_curr = 0;      comb_count = 0;      if (isec->reloc_count)	{          unsigned n;          /* Get a copy of the native relocations.  */          internal_relocs = _bfd_elf32_link_read_relocs (    	    abfd, isec, (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;          /* Setup a faster access method for the reloc info we need.  */          rela_comb = (Elf_Internal_Rela**)	    bfd_malloc (isec->reloc_count*sizeof (Elf_Internal_Rela*));          if (rela_comb == NULL)              goto error_return;          for (n = 0; n < isec->reloc_count; ++n)            {              long r_type;              r_type = ELF32_R_TYPE (internal_relocs[n].r_info);              if (r_type < 0 || r_type >= (int) R_PPC_max)                  goto error_return;              /* Prologue constants are sometimes present in the ".text"              sections and they can be identified by their associated relocation.              We don't want to process those words and some others which              can also be identified by their relocations.  However, not all              conditional branches will have a relocation so we will              only ignore words that 1) have a reloc, and 2) the reloc              is not applicable to a conditional branch.              The array rela_comb is built here for use in the EOP scan loop.  */              switch (r_type)                {                case R_PPC_ADDR14_BRNTAKEN:     /* absolute, predicted not taken */                case R_PPC_REL14:               /* relative cond. br.  */                case R_PPC_REL14_BRNTAKEN:      /* rel. cond. br., predicted not taken */                  /* We should check the instruction.  */                  break;                default:                  /* The word is not a conditional branch - ignore it.  */                  rela_comb[comb_count++] = &internal_relocs[n];                  break;                }            }          if (comb_count > 1)	    qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela);	}      /* Enumerate each EOP region that overlaps this section.  */      end_section = isec->vma + isec->_cooked_size;      dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1;      dot -= link_info->mpc860c0;      section_modified = false;      if (dot < isec->vma)      /* Increment the start position if this section */          dot = isec->vma;      /* begins in the middle of its first EOP region.  */      for (;           dot < end_section;           dot += PAGESIZE, end_page += PAGESIZE)        {          /* Check each word in this EOP region.  */          for (; dot < end_page; dot += 4)            {              bfd_vma isec_offset;              unsigned long insn;              boolean skip, modified;              /* Don't process this word if there is a relocation for it and              the relocation indicates the word is not a conditional branch.  */              skip = false;              isec_offset = dot - isec->vma;              for (; comb_curr<comb_count; ++comb_curr)                {                  bfd_vma r_offset;                  r_offset = rela_comb[comb_curr]->r_offset;                  if (r_offset >= isec_offset)                    {                      if (r_offset == isec_offset) skip = true;                      break;                    }                }              if (skip) continue;              /* Check the current word for a problematic conditional branch.  */#define BO0(insn) ((insn) & 0x02000000)#define BO2(insn) ((insn) & 0x00800000)#define BO4(insn) ((insn) & 0x00200000)              insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset);              modified = false;              if ((insn & 0xFc000000) == 0x40000000)                {                  /* Instruction is BCx */                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))                    {                      bfd_vma target;                      /* This branch is predicted as "normal".                      If this is a forward branch, it is problematic.  */                      target = insn & 0x0000Fffc;               /*extract*/                      target = (target ^ 0x8000) - 0x8000;      /*sign extend*/                      if ((insn & 0x00000002) == 0)                          target += dot;                        /*convert to abs*/                      if (target > dot)                        {                          insn |= 0x00200000;   /* set the prediction bit */                          modified = true;                        }

⌨️ 快捷键说明

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