Beispiel #1
0
static void bfd_section_setup(bfd_section_t *Section) {
	bfd *Bfd = Section->Bfd;
	bfd_info_t *BfdInfo = Section->BfdInfo;
	asection *Sect = Section->Sect;
	Section->Size = bfd_get_section_size(Sect);
	bfd_malloc_and_get_section(Bfd, Sect, &Section->Code);
	arelent **Relocs = (arelent **)malloc(bfd_get_reloc_upper_bound(Bfd, Sect));
	Section->NoOfRelocs = bfd_canonicalize_reloc(Bfd, Sect, Relocs, BfdInfo->Symbols);
	Section->Relocs = (relocation_t *)malloc(sizeof(relocation_t) * Section->NoOfRelocs);
	for (int I = Section->NoOfRelocs - 1; I >= 0; --I) {
		relocation_t *Relocation = Section->Relocs + I;
		asymbol *Sym = *(Relocs[I]->sym_ptr_ptr);
		reloc_howto_type *Type = Relocs[I]->howto;
		Relocation->Position = Relocs[I]->address;
		Relocation->Size = bfd_get_reloc_size(Type);
		Relocation->Flags = Type->pc_relative ? RELOC_REL : RELOC_ABS;
		uint32_t *Target = (uint32_t *)(Section->Code + Relocs[I]->address);
		if (Type->pc_relative) {
#ifdef WINDOWS
			*(long *)(Section->Code + Relocs[I]->address) -= Relocs[I]->address + 4;// why oh why is this here???
#else
            *(long *)(Section->Code + Relocs[I]->address) -= Relocs[I]->address;// + 4 on windows platforms ???;
#endif
		};
		if (Sym->section == bfd_und_section_ptr) {
			symbol_t *Symbol;
			do {
				Symbol = (symbol_t *)stringtable_get(BfdInfo->LocalTable, Sym->name);
				if (Symbol) break;
				Symbol = (symbol_t *)stringtable_get(GlobalTable, Sym->name);
				if (Symbol) break;
				Symbol = (symbol_t *)stringtable_get(WeakTable, Sym->name);
				if (Symbol) break;
#ifdef WINDOWS
                char *WindowsSizeHint = strrchr(Sym->name, '@');
                if (WindowsSizeHint) {
                    *WindowsSizeHint = 0;
                    Symbol = (symbol_t *)stringtable_get(BfdInfo->LocalTable, Sym->name);
                    if (Symbol) break;
                    Symbol = (symbol_t *)stringtable_get(GlobalTable, Sym->name);
                    if (Symbol) break;
                    Symbol = (symbol_t *)stringtable_get(WeakTable, Sym->name);
                    if (Symbol) break;
                }
#endif
				printf("%s: unresolved symbol %s.\n", Bfd->filename, Sym->name);
				exit(1);
			} while (0);
			section_t *Section2 = Symbol->Section;
			section_relocate(Section2, Relocation, Target);
			if (Type->partial_inplace) *Target += (uint32_t)Symbol->Offset;
		} else if (Sym->section->userdata) {
			section_t *Section2 = (section_t *)Sym->section->userdata;
			section_relocate(Section2, Relocation, Target);
			if (Type->partial_inplace) *Target += (uint32_t)Sym->value;
		};
	};
};
/* Insert the addend/value into the instruction or data object being
   relocated.  */
bfd_reloc_status_type
_bfd_aarch64_elf_put_addend (bfd *abfd,
			     bfd_byte *address, bfd_reloc_code_real_type r_type,
			     reloc_howto_type *howto, bfd_signed_vma addend)
{
  bfd_reloc_status_type status = bfd_reloc_ok;
  bfd_signed_vma old_addend = addend;
  bfd_vma contents;
  int size;

  size = bfd_get_reloc_size (howto);
  switch (size)
    {
    case 2:
      contents = bfd_get_16 (abfd, address);
      break;
    case 4:
      if (howto->src_mask != 0xffffffff)
	/* Must be 32-bit instruction, always little-endian.  */
	contents = bfd_getl32 (address);
      else
	/* Must be 32-bit data (endianness dependent).  */
	contents = bfd_get_32 (abfd, address);
      break;
    case 8:
      contents = bfd_get_64 (abfd, address);
      break;
    default:
      abort ();
    }

  switch (howto->complain_on_overflow)
    {
    case complain_overflow_dont:
      break;
    case complain_overflow_signed:
      status = aarch64_signed_overflow (addend,
					howto->bitsize + howto->rightshift);
      break;
    case complain_overflow_unsigned:
      status = aarch64_unsigned_overflow (addend,
					  howto->bitsize + howto->rightshift);
      break;
    case complain_overflow_bitfield:
    default:
      abort ();
    }

  addend >>= howto->rightshift;

  switch (r_type)
    {
    case BFD_RELOC_AARCH64_JUMP26:
    case BFD_RELOC_AARCH64_CALL26:
      contents = reencode_branch_ofs_26 (contents, addend);
      break;

    case BFD_RELOC_AARCH64_BRANCH19:
      contents = reencode_cond_branch_ofs_19 (contents, addend);
      break;

    case BFD_RELOC_AARCH64_TSTBR14:
      contents = reencode_tst_branch_ofs_14 (contents, addend);
      break;

    case BFD_RELOC_AARCH64_LD_LO19_PCREL:
    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
      if (old_addend & ((1 << howto->rightshift) - 1))
	return bfd_reloc_overflow;
      contents = reencode_ld_lit_ofs_19 (contents, addend);
      break;

    case BFD_RELOC_AARCH64_TLSDESC_CALL:
      break;

    case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
    case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
    case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
    case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
      contents = reencode_adr_imm (contents, addend);
      break;

    case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
    case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
    case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
    case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
    case BFD_RELOC_AARCH64_ADD_LO12:
      /* Corresponds to: add rd, rn, #uimm12 to provide the low order
         12 bits of the page offset following
         BFD_RELOC_AARCH64_ADR_HI21_PCREL which computes the
         (pc-relative) page base.  */
      contents = reencode_add_imm (contents, addend);
      break;

    case BFD_RELOC_AARCH64_LDST8_LO12:
    case BFD_RELOC_AARCH64_LDST16_LO12:
    case BFD_RELOC_AARCH64_LDST32_LO12:
    case BFD_RELOC_AARCH64_LDST64_LO12:
    case BFD_RELOC_AARCH64_LDST128_LO12:
    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
    case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
    case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
    case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
    case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
      if (old_addend & ((1 << howto->rightshift) - 1))
	return bfd_reloc_overflow;
      /* Used for ldr*|str* rt, [rn, #uimm12] to provide the low order
         12 bits of the page offset following BFD_RELOC_AARCH64_ADR_HI21_PCREL
         which computes the (pc-relative) page base.  */
      contents = reencode_ldst_pos_imm (contents, addend);
      break;

      /* Group relocations to create high bits of a 16, 32, 48 or 64
         bit signed data or abs address inline. Will change
         instruction to MOVN or MOVZ depending on sign of calculated
         value.  */

    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
    case BFD_RELOC_AARCH64_MOVW_G0_S:
    case BFD_RELOC_AARCH64_MOVW_G1_S:
    case BFD_RELOC_AARCH64_MOVW_G2_S:
      /* NOTE: We can only come here with movz or movn.  */
      if (addend < 0)
	{
	  /* Force use of MOVN.  */
	  addend = ~addend;
	  contents = reencode_movzn_to_movn (contents);
	}
      else
	{
	  /* Force use of MOVZ.  */
	  contents = reencode_movzn_to_movz (contents);
	}
      /* fall through */

      /* Group relocations to create a 16, 32, 48 or 64 bit unsigned
         data or abs address inline.  */

    case BFD_RELOC_AARCH64_MOVW_G0:
    case BFD_RELOC_AARCH64_MOVW_G0_NC:
    case BFD_RELOC_AARCH64_MOVW_G1:
    case BFD_RELOC_AARCH64_MOVW_G1_NC:
    case BFD_RELOC_AARCH64_MOVW_G2:
    case BFD_RELOC_AARCH64_MOVW_G2_NC:
    case BFD_RELOC_AARCH64_MOVW_G3:
      contents = reencode_movw_imm (contents, addend);
      break;

    default:
      /* Repack simple data */
      if (howto->dst_mask & (howto->dst_mask + 1))
	return bfd_reloc_notsupported;

      contents = ((contents & ~howto->dst_mask) | (addend & howto->dst_mask));
      break;
    }

  switch (size)
    {
    case 2:
      bfd_put_16 (abfd, contents, address);
      break;
    case 4:
      if (howto->dst_mask != 0xffffffff)
	/* must be 32-bit instruction, always little-endian */
	bfd_putl32 (contents, address);
      else
	/* must be 32-bit data (endianness dependent) */
	bfd_put_32 (abfd, contents, address);
      break;
    case 8:
      bfd_put_64 (abfd, contents, address);
      break;
    default:
      abort ();
    }

  return status;
}
Beispiel #3
0
static void
build_link_order (lang_statement_union_type *statement)
{
  switch (statement->header.type)
    {
    case lang_data_statement_enum:
      {
	asection *output_section;
	struct bfd_link_order *link_order;
	bfd_vma value;
	bfd_boolean big_endian = FALSE;

	output_section = statement->data_statement.output_section;
	ASSERT (output_section->owner == link_info.output_bfd);

	if (!((output_section->flags & SEC_HAS_CONTENTS) != 0
	      || ((output_section->flags & SEC_LOAD) != 0
		  && (output_section->flags & SEC_THREAD_LOCAL))))
	  break;

	link_order = bfd_new_link_order (link_info.output_bfd, output_section);
	if (link_order == NULL)
	  einfo (_("%F%P: bfd_new_link_order failed\n"));

	link_order->type = bfd_data_link_order;
	link_order->offset = statement->data_statement.output_offset;
	link_order->u.data.contents = (bfd_byte *) xmalloc (QUAD_SIZE);

	value = statement->data_statement.value;

	/* If the endianness of the output BFD is not known, then we
	   base the endianness of the data on the first input file.
	   By convention, the bfd_put routines for an unknown
	   endianness are big endian, so we must swap here if the
	   input file is little endian.  */
	if (bfd_big_endian (link_info.output_bfd))
	  big_endian = TRUE;
	else if (bfd_little_endian (link_info.output_bfd))
	  big_endian = FALSE;
	else
	  {
	    bfd_boolean swap;

	    swap = FALSE;
	    if (command_line.endian == ENDIAN_BIG)
	      big_endian = TRUE;
	    else if (command_line.endian == ENDIAN_LITTLE)
	      {
		big_endian = FALSE;
		swap = TRUE;
	      }
	    else if (command_line.endian == ENDIAN_UNSET)
	      {
		big_endian = TRUE;
		{
		  LANG_FOR_EACH_INPUT_STATEMENT (s)
		  {
		    if (s->the_bfd != NULL)
		      {
			if (bfd_little_endian (s->the_bfd))
			  {
			    big_endian = FALSE;
			    swap = TRUE;
			  }
			break;
		      }
		  }
		}
	      }

	    if (swap)
	      {
		bfd_byte buffer[8];

		switch (statement->data_statement.type)
		  {
		  case QUAD:
		  case SQUAD:
		    if (sizeof (bfd_vma) >= QUAD_SIZE)
		      {
			bfd_putl64 (value, buffer);
			value = bfd_getb64 (buffer);
			break;
		      }
		    /* Fall through.  */
		  case LONG:
		    bfd_putl32 (value, buffer);
		    value = bfd_getb32 (buffer);
		    break;
		  case SHORT:
		    bfd_putl16 (value, buffer);
		    value = bfd_getb16 (buffer);
		    break;
		  case BYTE:
		    break;
		  default:
		    abort ();
		  }
	      }
	  }

	ASSERT (output_section->owner == link_info.output_bfd);
	switch (statement->data_statement.type)
	  {
	  case QUAD:
	  case SQUAD:
	    if (sizeof (bfd_vma) >= QUAD_SIZE)
	      bfd_put_64 (link_info.output_bfd, value,
			  link_order->u.data.contents);
	    else
	      {
		bfd_vma high;

		if (statement->data_statement.type == QUAD)
		  high = 0;
		else if ((value & 0x80000000) == 0)
		  high = 0;
		else
		  high = (bfd_vma) -1;
		bfd_put_32 (link_info.output_bfd, high,
			    (link_order->u.data.contents
			     + (big_endian ? 0 : 4)));
		bfd_put_32 (link_info.output_bfd, value,
			    (link_order->u.data.contents
			     + (big_endian ? 4 : 0)));
	      }
	    link_order->size = QUAD_SIZE;
	    break;
	  case LONG:
	    bfd_put_32 (link_info.output_bfd, value,
			link_order->u.data.contents);
	    link_order->size = LONG_SIZE;
	    break;
	  case SHORT:
	    bfd_put_16 (link_info.output_bfd, value,
			link_order->u.data.contents);
	    link_order->size = SHORT_SIZE;
	    break;
	  case BYTE:
	    bfd_put_8 (link_info.output_bfd, value,
		       link_order->u.data.contents);
	    link_order->size = BYTE_SIZE;
	    break;
	  default:
	    abort ();
	  }
	link_order->u.data.size = link_order->size;
      }
      break;

    case lang_reloc_statement_enum:
      {
	lang_reloc_statement_type *rs;
	asection *output_section;
	struct bfd_link_order *link_order;

	rs = &statement->reloc_statement;

	output_section = rs->output_section;
	ASSERT (output_section->owner == link_info.output_bfd);

	if (!((output_section->flags & SEC_HAS_CONTENTS) != 0
	      || ((output_section->flags & SEC_LOAD) != 0
		  && (output_section->flags & SEC_THREAD_LOCAL))))
	  break;

	link_order = bfd_new_link_order (link_info.output_bfd, output_section);
	if (link_order == NULL)
	  einfo (_("%F%P: bfd_new_link_order failed\n"));

	link_order->offset = rs->output_offset;
	link_order->size = bfd_get_reloc_size (rs->howto);

	link_order->u.reloc.p = (struct bfd_link_order_reloc *)
	  xmalloc (sizeof (struct bfd_link_order_reloc));

	link_order->u.reloc.p->reloc = rs->reloc;
	link_order->u.reloc.p->addend = rs->addend_value;

	if (rs->name == NULL)
	  {
	    link_order->type = bfd_section_reloc_link_order;
	    if (rs->section->owner == link_info.output_bfd)
	      link_order->u.reloc.p->u.section = rs->section;
	    else
	      {
		link_order->u.reloc.p->u.section = rs->section->output_section;
		link_order->u.reloc.p->addend += rs->section->output_offset;
	      }
	  }
	else
	  {
	    link_order->type = bfd_symbol_reloc_link_order;
	    link_order->u.reloc.p->u.name = rs->name;
	  }
      }
      break;

    case lang_input_section_enum:
      {
	/* Create a new link_order in the output section with this
	   attached */
	asection *i = statement->input_section.section;

	if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
	    && (i->flags & SEC_EXCLUDE) == 0)
	  {
	    asection *output_section = i->output_section;
	    struct bfd_link_order *link_order;

	    ASSERT (output_section->owner == link_info.output_bfd);

	    if (!((output_section->flags & SEC_HAS_CONTENTS) != 0
		  || ((output_section->flags & SEC_LOAD) != 0
		      && (output_section->flags & SEC_THREAD_LOCAL))))
	      break;

	    link_order = bfd_new_link_order (link_info.output_bfd,
					     output_section);
	    if (link_order == NULL)
	      einfo (_("%F%P: bfd_new_link_order failed\n"));

	    if ((i->flags & SEC_NEVER_LOAD) != 0
		&& (i->flags & SEC_DEBUGGING) == 0)
	      {
		/* We've got a never load section inside one which is
		   going to be output, we'll change it into a fill.  */
		link_order->type = bfd_data_link_order;
		link_order->u.data.contents = (unsigned char *) "";
		link_order->u.data.size = 1;
	      }
	    else
	      {
		link_order->type = bfd_indirect_link_order;
		link_order->u.indirect.section = i;
		ASSERT (i->output_section == output_section);
	      }
	    link_order->size = i->size;
	    link_order->offset = i->output_offset;
	  }
      }
      break;

    case lang_padding_statement_enum:
      /* Make a new link_order with the right filler */
      {
	asection *output_section;
	struct bfd_link_order *link_order;

	output_section = statement->padding_statement.output_section;
	ASSERT (statement->padding_statement.output_section->owner
		== link_info.output_bfd);

	if (!((output_section->flags & SEC_HAS_CONTENTS) != 0
	      || ((output_section->flags & SEC_LOAD) != 0
		  && (output_section->flags & SEC_THREAD_LOCAL))))
	  break;

	link_order = bfd_new_link_order (link_info.output_bfd,
					 output_section);
	if (link_order == NULL)
	  einfo (_("%F%P: bfd_new_link_order failed\n"));
	link_order->type = bfd_data_link_order;
	link_order->size = statement->padding_statement.size;
	link_order->offset = statement->padding_statement.output_offset;
	link_order->u.data.contents = statement->padding_statement.fill->data;
	link_order->u.data.size = statement->padding_statement.fill->size;
      }
      break;

    default:
      /* All the other ones fall through */
      break;
    }
Beispiel #4
0
void
ldctor_build_sets (void)
{
  static bfd_boolean called;
  bfd_boolean header_printed;
  struct set_info *p;

  /* The emulation code may call us directly, but we only want to do
     this once.  */
  if (called)
    return;
  called = TRUE;

  if (constructors_sorted)
    {
      for (p = sets; p != NULL; p = p->next)
	{
	  int c, i;
	  struct set_element *e;
	  struct set_element **array;

	  if (p->elements == NULL)
	    continue;

	  c = 0;
	  for (e = p->elements; e != NULL; e = e->next)
	    ++c;

	  array = xmalloc (c * sizeof *array);

	  i = 0;
	  for (e = p->elements; e != NULL; e = e->next)
	    {
	      array[i] = e;
	      ++i;
	    }

	  qsort (array, c, sizeof *array, ctor_cmp);

	  e = array[0];
	  p->elements = e;
	  for (i = 0; i < c - 1; i++)
	    array[i]->next = array[i + 1];
	  array[i]->next = NULL;

	  free (array);
	}
    }

  lang_list_init (&constructor_list);
  push_stat_ptr (&constructor_list);

  header_printed = FALSE;
  for (p = sets; p != NULL; p = p->next)
    {
      struct set_element *e;
      reloc_howto_type *howto;
      int reloc_size, size;

      /* If the symbol is defined, we may have been invoked from
	 collect, and the sets may already have been built, so we do
	 not do anything.  */
      if (p->h->type == bfd_link_hash_defined
	  || p->h->type == bfd_link_hash_defweak)
	continue;

      /* For each set we build:
	   set:
	     .long number_of_elements
	     .long element0
	     ...
	     .long elementN
	     .long 0
	 except that we use the right size instead of .long.  When
	 generating relocatable output, we generate relocs instead of
	 addresses.  */
      howto = bfd_reloc_type_lookup (link_info.output_bfd, p->reloc);
      if (howto == NULL)
	{
	  if (link_info.relocatable)
	    {
	      einfo (_("%P%X: %s does not support reloc %s for set %s\n"),
		     bfd_get_target (link_info.output_bfd),
		     bfd_get_reloc_code_name (p->reloc),
		     p->h->root.string);
	      continue;
	    }

	  /* If this is not a relocatable link, all we need is the
	     size, which we can get from the input BFD.  */
	  if (p->elements->section->owner != NULL)
	    howto = bfd_reloc_type_lookup (p->elements->section->owner,
					   p->reloc);
	  if (howto == NULL)
	    {
	      einfo (_("%P%X: %s does not support reloc %s for set %s\n"),
		     bfd_get_target (p->elements->section->owner),
		     bfd_get_reloc_code_name (p->reloc),
		     p->h->root.string);
	      continue;
	    }
	}

      reloc_size = bfd_get_reloc_size (howto);
      switch (reloc_size)
	{
	case 1: size = BYTE; break;
	case 2: size = SHORT; break;
	case 4: size = LONG; break;
	case 8:
	  if (howto->complain_on_overflow == complain_overflow_signed)
	    size = SQUAD;
	  else
	    size = QUAD;
	  break;
	default:
	  einfo (_("%P%X: Unsupported size %d for set %s\n"),
		 bfd_get_reloc_size (howto), p->h->root.string);
	  size = LONG;
	  break;
	}

      lang_add_assignment (exp_assop ('=', ".",
				      exp_unop (ALIGN_K,
						exp_intop (reloc_size))));
      lang_add_assignment (exp_assop ('=', p->h->root.string,
				      exp_nameop (NAME, ".")));
      lang_add_data (size, exp_intop (p->count));

      for (e = p->elements; e != NULL; e = e->next)
	{
	  if (config.map_file != NULL)
	    {
	      int len;

	      if (! header_printed)
		{
		  minfo (_("\nSet                 Symbol\n\n"));
		  header_printed = TRUE;
		}

	      minfo ("%s", p->h->root.string);
	      len = strlen (p->h->root.string);

	      if (len >= 19)
		{
		  print_nl ();
		  len = 0;
		}
	      while (len < 20)
		{
		  print_space ();
		  ++len;
		}

	      if (e->name != NULL)
		minfo ("%T\n", e->name);
	      else
		minfo ("%G\n", e->section->owner, e->section, e->value);
	    }

	  /* Need SEC_KEEP for --gc-sections.  */
	  if (! bfd_is_abs_section (e->section))
	    e->section->flags |= SEC_KEEP;

	  if (link_info.relocatable)
	    lang_add_reloc (p->reloc, howto, e->section, e->name,
			    exp_intop (e->value));
	  else
	    lang_add_data (size, exp_relop (e->section, e->value));
	}

      lang_add_data (size, exp_intop (0));
    }

  pop_stat_ptr ();
}