elf64-alpha.c

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

C
2,160
字号
	       Perhaps conditionalize this on a flag being set in the target	       object file's header, and have gcc set it?  */	  }	  break;	}    }  /* If all cases were optimized, we can reduce the use count on this     got entry by one, possibly eliminating it.  */  if (all_optimized)    {      info->gotent->use_count -= 1;      alpha_elf_tdata (info->gotent->gotobj)->total_got_entries -= 1;      if (!info->h)	alpha_elf_tdata (info->gotent->gotobj)->n_local_got_entries -= 1;      /* If the literal instruction is no longer needed (it may have been	 reused.  We can eliminate it.	 ??? For now, I don't want to deal with compacting the section,	 so just nop it out.  */      if (!lit_reused)	{	  irel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);	  info->changed_relocs = true;	  bfd_put_32 (info->abfd, INSN_UNOP, info->contents + irel->r_offset);	  info->changed_contents = true;	}    }  return irel + count;}static bfd_vmaelf64_alpha_relax_opt_call (info, symval)     struct alpha_relax_info *info;     bfd_vma symval;{  /* If the function has the same gp, and we can identify that the     function does not use its function pointer, we can eliminate the     address load.  */  /* If the symbol is marked NOPV, we are being told the function never     needs its procedure value.  */  if ((info->other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_NOPV)    return symval;  /* If the symbol is marked STD_GP, we are being told the function does     a normal ldgp in the first two words.  */  else if ((info->other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_STD_GPLOAD)    ;  /* Otherwise, we may be able to identify a GP load in the first two     words, which we can then skip.  */  else    {      Elf_Internal_Rela *tsec_relocs, *tsec_relend, *tsec_free, *gpdisp;      bfd_vma ofs;      /* Load the relocations from the section that the target symbol is in.  */      if (info->sec == info->tsec)	{	  tsec_relocs = info->relocs;	  tsec_relend = info->relend;	  tsec_free = NULL;	}      else	{	  tsec_relocs = (_bfd_elf64_link_read_relocs		         (info->abfd, info->tsec, (PTR) NULL,			 (Elf_Internal_Rela *) NULL,			 info->link_info->keep_memory));	  if (tsec_relocs == NULL)	    return 0;	  tsec_relend = tsec_relocs + info->tsec->reloc_count;	  tsec_free = (info->link_info->keep_memory ? NULL : tsec_relocs);	}      /* Recover the symbol's offset within the section.  */      ofs = (symval - info->tsec->output_section->vma	     - info->tsec->output_offset);      /* Look for a GPDISP reloc.  */      gpdisp = (elf64_alpha_find_reloc_at_ofs		(tsec_relocs, tsec_relend, ofs, R_ALPHA_GPDISP));      if (!gpdisp || gpdisp->r_addend != 4)	{	  if (tsec_free)	    free (tsec_free);	  return 0;	}      if (tsec_free)        free (tsec_free);    }  /* We've now determined that we can skip an initial gp load.  Verify     that the call and the target use the same gp.   */  if (info->link_info->hash->creator != info->tsec->owner->xvec      || info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj)    return 0;  return symval + 8;}static booleanelf64_alpha_relax_without_lituse (info, symval, irel)     struct alpha_relax_info *info;     bfd_vma symval;     Elf_Internal_Rela *irel;{  unsigned int insn;  bfd_signed_vma disp;  /* Get the instruction.  */  insn = bfd_get_32 (info->abfd, info->contents + irel->r_offset);  if (insn >> 26 != OP_LDQ)    {      ((*_bfd_error_handler)       ("%s: %s+0x%lx: warning: LITERAL relocation against unexpected insn",	bfd_get_filename (info->abfd), info->sec->name,	(unsigned long) irel->r_offset));      return true;    }  /* So we aren't told much.  Do what we can with the address load and     fake the rest.  All of the optimizations here require that the     offset from the GP fit in 16 bits.  */  disp = symval - info->gp;  if (disp < -0x8000 || disp >= 0x8000)    return true;  /* On the LITERAL instruction itself, consider exchanging     `ldq R,X(gp)' for `lda R,Y(gp)'.  */  insn = (OP_LDA << 26) | (insn & 0x03ff0000);  bfd_put_32 (info->abfd, insn, info->contents + irel->r_offset);  info->changed_contents = true;  irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), R_ALPHA_GPRELLOW);  info->changed_relocs = true;  /* Reduce the use count on this got entry by one, possibly     eliminating it.  */  info->gotent->use_count -= 1;  alpha_elf_tdata (info->gotent->gotobj)->total_got_entries -= 1;  if (!info->h)    alpha_elf_tdata (info->gotent->gotobj)->n_local_got_entries -= 1;  /* ??? Search forward through this basic block looking for insns     that use the target register.  Stop after an insn modifying the     register is seen, or after a branch or call.     Any such memory load insn may be substituted by a load directly     off the GP.  This allows the memory load insn to be issued before     the calculated GP register would otherwise be ready.     Any such jsr insn can be replaced by a bsr if it is in range.     This would mean that we'd have to _add_ relocations, the pain of     which gives one pause.  */  return true;}static booleanelf64_alpha_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 *free_contents = NULL;  Elf64_External_Sym *extsyms = NULL;  Elf64_External_Sym *free_extsyms = NULL;  struct alpha_elf_got_entry **local_got_entries;  struct alpha_relax_info info;  /* We are not currently changing any sizes, so only one pass.  */  *again = false;  if (link_info->relocateable      || (sec->flags & SEC_RELOC) == 0      || sec->reloc_count == 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;  local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;  /* Load the relocations for this section.  */  internal_relocs = (_bfd_elf64_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;  memset(&info, 0, sizeof (info));  info.abfd = abfd;  info.sec = sec;  info.link_info = link_info;  info.relocs = internal_relocs;  info.relend = irelend = internal_relocs + sec->reloc_count;  /* Find the GP for this object.  */  info.gotobj = alpha_elf_tdata (abfd)->gotobj;  if (info.gotobj)    {      asection *sgot = alpha_elf_tdata (info.gotobj)->got;      info.gp = _bfd_get_gp_value (info.gotobj);      if (info.gp == 0)	{	  info.gp = (sgot->output_section->vma		     + sgot->output_offset		     + 0x8000);	  _bfd_set_gp_value (info.gotobj, info.gp);	}    }  for (irel = internal_relocs; irel < irelend; irel++)    {      bfd_vma symval;      Elf_Internal_Sym isym;      struct alpha_elf_got_entry *gotent;      if (ELF64_R_TYPE (irel->r_info) != (int) R_ALPHA_LITERAL)	continue;      /* Get the section contents.  */      if (info.contents == NULL)	{	  if (elf_section_data (sec)->this_hdr.contents != NULL)	    info.contents = elf_section_data (sec)->this_hdr.contents;	  else	    {	      info.contents = (bfd_byte *) bfd_malloc (sec->_raw_size);	      if (info.contents == NULL)		goto error_return;	      free_contents = info.contents;	      if (! bfd_get_section_contents (abfd, sec, info.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)	{	  if (symtab_hdr->contents != NULL)	    extsyms = (Elf64_External_Sym *) symtab_hdr->contents;	  else	    {	      extsyms = ((Elf64_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 (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)	{	  /* A local symbol.  */	  bfd_elf64_swap_symbol_in (abfd,				    extsyms + ELF64_R_SYM (irel->r_info),				    &isym);	  if (isym.st_shndx == SHN_UNDEF)	    info.tsec = bfd_und_section_ptr;	  else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)	    info.tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);	  else if (isym.st_shndx == SHN_ABS)	    info.tsec = bfd_abs_section_ptr;	  else if (isym.st_shndx == SHN_COMMON)	    info.tsec = bfd_com_section_ptr;	  else	    continue;	/* who knows.  */	  info.h = NULL;	  info.other = isym.st_other;	  gotent = local_got_entries[ELF64_R_SYM(irel->r_info)];	  symval = isym.st_value;	}      else	{	  unsigned long indx;	  struct alpha_elf_link_hash_entry *h;	  indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;	  h = alpha_elf_sym_hashes (abfd)[indx];	  BFD_ASSERT (h != NULL);	  while (h->root.root.type == bfd_link_hash_indirect		 || h->root.root.type == bfd_link_hash_warning)	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;	  /* We can't do anthing with undefined or dynamic symbols.  */	  if (h->root.root.type == bfd_link_hash_undefined	      || h->root.root.type == bfd_link_hash_undefweak	      || alpha_elf_dynamic_symbol_p (&h->root, link_info))	    continue;	  info.h = h;	  info.gotent = gotent;	  info.tsec = h->root.root.u.def.section;	  info.other = h->root.other;	  gotent = h->got_entries;	  symval = h->root.root.u.def.value;	}      /* Search for the got entry to be used by this relocation.  */      while (gotent->gotobj != info.gotobj || gotent->addend != irel->r_addend)	gotent = gotent->next;      info.gotent = gotent;      symval += info.tsec->output_section->vma + info.tsec->output_offset;      symval += irel->r_addend;      BFD_ASSERT(info.gotent != NULL);      /* If there exist LITUSE relocations immediately following, this	 opens up all sorts of interesting optimizations, because we	 now know every location that this address load is used.  */      if (irel+1 < irelend && ELF64_R_TYPE (irel[1].r_info) == R_ALPHA_LITUSE)	{	  irel = elf64_alpha_relax_with_lituse (&info, symval, irel, irelend);	  if (irel == NULL)	    goto error_return;	}      else	{	  if (!elf64_alpha_relax_without_lituse (&info, symval, irel))	    goto error_return;	}    }  if (!elf64_alpha_size_got_sections (abfd, link_info))    return false;  if (info.changed_relocs)    {      elf_section_data (sec)->relocs = internal_relocs;    }  else if (free_relocs != NULL)    {      free (free_relocs);    }  if (info.changed_contents)    {      elf_section_data (sec)->this_hdr.contents = info.contents;    }  else 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 = info.contents;	}    }  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;	}    }  *again = info.changed_contents || info.changed_relocs;  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;}/* PLT/GOT Stuff */#define PLT_HEADER_SIZE 32#define PLT_HEADER_WORD1	0xc3600000	/* br   $27,.+4     */#define PLT_HEADER_WORD2	0xa77b000c	/* ldq  $27,12($27) */#define PLT_HEADER_WORD3	0x47ff041f	/* nop              */#define PLT_HEADER_WORD4	0x6b7b0000	/* jmp  $27,($27)   */#define PLT_ENTRY_SIZE 12#define PLT_ENTRY_WORD1		0xc3800000	/* br   $28, plt0   */#define PLT_ENTRY_WORD2		0#define PLT_ENTRY_WORD3		0#define MAX_GOT_ENTRIES		(64*1024 / 8)#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"/* Handle an Alpha specific section when reading an object file.  This   is called when elfcode.h finds a section with an unknown type.   FIXME: We need to handle the SHF_ALPHA_GPREL flag, but I'm not sure   how to.  */static booleanelf64_alpha_section_from_shdr (abfd, hdr, name)     bfd *abfd;     Elf64_Internal_Shdr *hdr;

⌨️ 快捷键说明

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