nlmconv.c

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

C
2,181
字号
  if (! bfd_set_section_contents (outbfd, secsec, (PTR) inname, secsecoff,				  strlen (inname) + 1))    bfd_fatal (_("set .nlmsection contents"));  secsecoff += strlen (inname) + 1;  add = ((secsecoff + 3) &~ 3) - secsecoff;  if (add != 0)    {      bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);      if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, add))	bfd_fatal (_("set .nlmsection contents"));      secsecoff += add;    }  if (contents != NULL)    bfd_h_put_32 (outbfd, (bfd_vma) outsec->filepos, buf);  else    bfd_h_put_32 (outbfd, (bfd_vma) 0, buf);  if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))    bfd_fatal (_("set .nlmsection contents"));  secsecoff += 4;  bfd_h_put_32 (outbfd, (bfd_vma) size, buf);  if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4))    bfd_fatal (_("set .nlmsection contents"));  secsecoff += 4;}/* Some, perhaps all, NetWare targets require changing the relocs used   by the input formats.  */static voidmangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,	       contents_size)     bfd *outbfd;     asection *insec;     arelent ***relocs_ptr;     long *reloc_count_ptr;     char *contents;     bfd_size_type contents_size;{  switch (bfd_get_arch (outbfd))    {#ifdef NLMCONV_I386    case bfd_arch_i386:      i386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,			  contents, contents_size);      break;#endif#ifdef NLMCONV_ALPHA    case bfd_arch_alpha:      alpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,			   contents, contents_size);      break;#endif#ifdef NLMCONV_POWERPC    case bfd_arch_powerpc:      powerpc_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,			     contents, contents_size);      break;#endif    default:      default_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr,			     contents, contents_size);      break;    }}/* By default all we need to do for relocs is change the address by   the output_offset.  *//*ARGSUSED*/static voiddefault_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,		       contents_size)     bfd *outbfd;     asection *insec;     arelent ***relocs_ptr;     long *reloc_count_ptr;     char *contents;     bfd_size_type contents_size;{  if (insec->output_offset != 0)    {      long reloc_count;      register arelent **relocs;      register long i;      reloc_count = *reloc_count_ptr;      relocs = *relocs_ptr;      for (i = 0; i < reloc_count; i++, relocs++)	(*relocs)->address += insec->output_offset;    }}#ifdef NLMCONV_I386/* NetWare on the i386 supports a restricted set of relocs, which are   different from those used on other i386 targets.  This routine   converts the relocs.  It is, obviously, very target dependent.  At   the moment, the nlm32-i386 backend performs similar translations;   however, it is more reliable and efficient to do them here.  */static reloc_howto_type nlm_i386_pcrel_howto =  HOWTO (1,			/* type */	 0,			/* rightshift */	 2,			/* size (0 = byte, 1 = short, 2 = long) */	 32,			/* bitsize */	 true,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_signed, /* complain_on_overflow */	 0,			/* special_function */	 "DISP32",		/* name */	 true,			/* partial_inplace */	 0xffffffff,		/* src_mask */	 0xffffffff,		/* dst_mask */	 true);			/* pcrel_offset */static voidi386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,		    contents_size)     bfd *outbfd;     asection *insec;     arelent ***relocs_ptr;     long *reloc_count_ptr;     char *contents;     bfd_size_type contents_size;{  long reloc_count, i;  arelent **relocs;  reloc_count = *reloc_count_ptr;  relocs = *relocs_ptr;  for (i = 0; i < reloc_count; i++)    {      arelent *rel;      asymbol *sym;      bfd_size_type address;      bfd_vma addend;      rel = *relocs++;      sym = *rel->sym_ptr_ptr;      /* We're moving the relocs from the input section to the output	 section, so we must adjust the address accordingly.  */      address = rel->address;      rel->address += insec->output_offset;      /* Note that no serious harm will ensue if we fail to change a	 reloc.  The backend will fail when writing out the reloc.  */      /* Make sure this reloc is within the data we have.  We use only	 4 byte relocs here, so we insist on having 4 bytes.  */      if (address + 4 > contents_size)	continue;      /* A PC relative reloc entirely within a single section is	 completely unnecessary.  This can be generated by ld -r.  */      if (sym == insec->symbol	  && rel->howto != NULL	  && rel->howto->pc_relative	  && ! rel->howto->pcrel_offset)	{	  --*reloc_count_ptr;	  --relocs;	  memmove (relocs, relocs + 1,		   (size_t) ((reloc_count - i) * sizeof (arelent *)));	  continue;	}      /* Get the amount the relocation will add in.  */      addend = rel->addend + sym->value;      /* NetWare doesn't support PC relative relocs against defined	 symbols, so we have to eliminate them by doing the relocation	 now.  We can only do this if the reloc is within a single	 section.  */      if (rel->howto != NULL	  && rel->howto->pc_relative	  && bfd_get_section (sym) == insec->output_section)	{	  bfd_vma val;	  if (rel->howto->pcrel_offset)	    addend -= address;	  val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);	  val += addend;	  bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);	  --*reloc_count_ptr;	  --relocs;	  memmove (relocs, relocs + 1,		   (size_t) ((reloc_count - i) * sizeof (arelent *)));	  continue;	}      /* NetWare doesn't support reloc addends, so we get rid of them	 here by simply adding them into the object data.  We handle	 the symbol value, if any, the same way.  */      if (addend != 0	  && rel->howto != NULL	  && rel->howto->rightshift == 0	  && rel->howto->size == 2	  && rel->howto->bitsize == 32	  && rel->howto->bitpos == 0	  && rel->howto->src_mask == 0xffffffff	  && rel->howto->dst_mask == 0xffffffff)	{	  bfd_vma val;	  val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);	  val += addend;	  bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);	  /* Adjust the reloc for the changes we just made.  */	  rel->addend = 0;	  if (! bfd_is_und_section (bfd_get_section (sym)))	    rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr;	}      /* NetWare uses a reloc with pcrel_offset set.  We adjust	 pc_relative relocs accordingly.  We are going to change the	 howto field, so we can only do this if the current one is	 compatible.  We should check that special_function is NULL	 here, but at the moment coff-i386 uses a special_function	 which does not affect what we are doing here.  */      if (rel->howto != NULL	  && rel->howto->pc_relative	  && ! rel->howto->pcrel_offset	  && rel->howto->rightshift == 0	  && rel->howto->size == 2	  && rel->howto->bitsize == 32	  && rel->howto->bitpos == 0	  && rel->howto->src_mask == 0xffffffff	  && rel->howto->dst_mask == 0xffffffff)	{	  bfd_vma val;	  /* When pcrel_offset is not set, it means that the negative	     of the address of the memory location is stored in the	     memory location.  We must add it back in.  */	  val = bfd_get_32 (outbfd, (bfd_byte *) contents + address);	  val += address;	  bfd_put_32 (outbfd, val, (bfd_byte *) contents + address);	  /* We must change to a new howto.  */	  rel->howto = &nlm_i386_pcrel_howto;	}    }}#endif /* NLMCONV_I386 */#ifdef NLMCONV_ALPHA/* On the Alpha the first reloc for every section must be a special   relocs which hold the GP address.  Also, the first reloc in the   file must be a special reloc which holds the address of the .lita   section.  */static reloc_howto_type nlm32_alpha_nw_howto =  HOWTO (ALPHA_R_NW_RELOC,	/* type */	 0,			/* rightshift */	 0,			/* size (0 = byte, 1 = short, 2 = long) */	 0,			/* bitsize */	 false,			/* pc_relative */	 0,			/* bitpos */	 complain_overflow_dont, /* complain_on_overflow */	 0,			/* special_function */	 "NW_RELOC",		/* name */	 false,			/* partial_inplace */	 0,			/* src_mask */	 0,			/* dst_mask */	 false);		/* pcrel_offset *//*ARGSUSED*/static voidalpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents,		     contents_size)     bfd *outbfd;     asection *insec;     register arelent ***relocs_ptr;     long *reloc_count_ptr;     char *contents;     bfd_size_type contents_size;{  long old_reloc_count;  arelent **old_relocs;  register arelent **relocs;  old_reloc_count = *reloc_count_ptr;  old_relocs = *relocs_ptr;  relocs = (arelent **) xmalloc ((old_reloc_count + 3) * sizeof (arelent *));  *relocs_ptr = relocs;  if (nlm_alpha_backend_data (outbfd)->lita_address == 0)    {      bfd *inbfd;      asection *lita_section;      inbfd = insec->owner;      lita_section = bfd_get_section_by_name (inbfd, _LITA);      if (lita_section != (asection *) NULL)	{	  nlm_alpha_backend_data (outbfd)->lita_address =	    bfd_get_section_vma (inbfd, lita_section);	  nlm_alpha_backend_data (outbfd)->lita_size =	    bfd_section_size (inbfd, lita_section);	}      else	{	  /* Avoid outputting this reloc again.  */	  nlm_alpha_backend_data (outbfd)->lita_address = 4;	}      *relocs = (arelent *) xmalloc (sizeof (arelent));      (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;      (*relocs)->address = nlm_alpha_backend_data (outbfd)->lita_address;      (*relocs)->addend = nlm_alpha_backend_data (outbfd)->lita_size + 1;      (*relocs)->howto = &nlm32_alpha_nw_howto;      ++relocs;      ++(*reloc_count_ptr);    }  /* Get the GP value from bfd.  */  if (nlm_alpha_backend_data (outbfd)->gp == 0)    nlm_alpha_backend_data (outbfd)->gp =      bfd_ecoff_get_gp_value (insec->owner);  *relocs = (arelent *) xmalloc (sizeof (arelent));  (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;  (*relocs)->address = nlm_alpha_backend_data (outbfd)->gp;  (*relocs)->addend = 0;  (*relocs)->howto = &nlm32_alpha_nw_howto;  ++relocs;  ++(*reloc_count_ptr);  memcpy ((PTR) relocs, (PTR) old_relocs,	  (size_t) old_reloc_count * sizeof (arelent *));  relocs[old_reloc_count] = (arelent *) NULL;  free (old_relocs);  if (insec->output_offset != 0)    {      register bfd_size_type i;      for (i = 0; i < (bfd_size_type) old_reloc_count; i++, relocs++)	(*relocs)->address += insec->output_offset;    }}#endif /* NLMCONV_ALPHA */#ifdef NLMCONV_POWERPC/* We keep a linked list of stubs which we must build.  Because BFD   requires us to know the sizes of all sections before we can set the   contents of any, we must figure out which stubs we want to build   before we can actually build any of them.  */struct powerpc_stub{  /* Next stub in linked list.  */  struct powerpc_stub *next;  /* Symbol whose value is the start of the stub.  This is a symbol     whose name begins with `.'.  */  asymbol *start;  /* Symbol we are going to create a reloc against.  This is a symbol     with the same name as START but without the leading `.'.  */  asymbol *reloc;  /* The TOC index for this stub.  This is the index into the TOC     section at which the reloc is created.  */  unsigned int toc_index;};/* The linked list of stubs.  */static struct powerpc_stub *powerpc_stubs;/* This is what a stub looks like.  The first instruction will get   adjusted with the correct TOC index.  */static unsigned long powerpc_stub_insns[] ={  0x81820000,		/* lwz	 r12,0(r2) */  0x90410014,		/* stw	 r2,20(r1) */  0x800c0000,		/* lwz	 r0,0(r12) */  0x804c0004,		/* lwz	 r2,r(r12) */  0x7c0903a6,		/* mtctr r0 */  0x4e800420,		/* bctr */  0,			/* Traceback table.  */  0xc8000,  0};#define POWERPC_STUB_INSN_COUNT \  (sizeof powerpc_stub_insns / sizeof powerpc_stub_insns[0])#define POWERPC_STUB_SIZE (4 * POWERPC_STUB_INSN_COUNT)/* Each stub uses a four byte TOC entry.  */#define POWERPC_STUB_TOC_ENTRY_SIZE (4)/* The original size of the .got section.  */static bfd_size_type powerpc_initial_got_size;/* Look for all undefined symbols beginning with `.', and prepare to   build a stub for each one.  */static voidpowerpc_build_stubs (inbfd, outbfd, symbols_ptr, symcount_ptr)     bfd *inbfd;     bfd *outbfd;     asymbol ***symbols_ptr;     long *symcount_ptr;{  asection *stub_sec;  asection *got_sec;  unsigned int got_base;  long i;  long symcount;  long stubcount;  /* Make a section to hold stubs.  We don't set SEC_HAS_CONTENTS for     the section to prevent copy_sections from reading from it.  */  stub_sec = bfd_make_section (inbfd, ".stubs");  if (stub_sec == (asection *) NULL      || ! bfd_set_section_flags (inbfd, stub_sec,				  (SEC_CODE				   | SEC_RELOC				   | SEC_ALLOC				   | SEC_LOAD))

⌨️ 快捷键说明

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