Exemplo n.º 1
0
/*
 * update_section_info()
 *
 * Update section info after allocation
 *
 * If section was a heap or stack, set some globals.
 *
 * Note: argument region is currently unused.
 *
 */
static void
update_section_info(bfd_vma alloc_addr,
                    struct pic32_section *s,
                    struct memory_region_struct *region) {

  lang_output_section_statement_type *os;
  char *name;

  update_section_addr(s->sec, alloc_addr);

  if (pic32_debug) {
    printf("    updating section info:"
           "  vma = %lx, lma = %lx\n", s->sec->vma, s->sec->lma);
  }

  /* create a unique name for the output section */
    name = (s->sec->size > 0) ?
    unique_section_name(s->sec->name) :
    unique_zero_length_section_name(s->sec->name);

  /* create an output section (statement) */
  os = lang_output_section_statement_lookup (name, 0, TRUE);


  if (pic32_debug)
    printf("    creating output section statement \"%s\"\n\n", os->name);

  /* lang_add_section() will call init_os() if needed */
  lang_add_section (&os->children, s->sec, os);

  finish_section_info(s, os);
  region = region;
} /* update_section_info() */
Exemplo n.º 2
0
static bfd_boolean
gldelf64ltsmip_place_orphan (lang_input_statement_type *file, asection *s)
{
  static struct orphan_save hold_text;
  static struct orphan_save hold_rodata;
  static struct orphan_save hold_data;
  static struct orphan_save hold_bss;
  static struct orphan_save hold_rel;
  static struct orphan_save hold_interp;
  static struct orphan_save hold_sdata;
  static int count = 1;
  struct orphan_save *place;
  lang_statement_list_type *old;
  lang_statement_list_type add;
  etree_type *address;
  const char *secname;
  const char *ps = NULL;
  lang_output_section_statement_type *os;
  lang_statement_union_type **os_tail;
  etree_type *load_base;
  int isdyn = 0;

  secname = bfd_get_section_name (s->owner, s);
  if (! link_info.relocatable
      && link_info.combreloc
      && (s->flags & SEC_ALLOC)
      && strncmp (secname, ".rel", 4) == 0)
    {
      if (secname[4] == 'a')
	secname = ".rela.dyn";
      else
	secname = ".rel.dyn";
      isdyn = 1;
    }

  if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname)))
    {
      /* Look through the script to see where to place this section.  */
      os = lang_output_section_find (secname);

      if (os != NULL
	  && (os->bfd_section == NULL
	      || ((s->flags ^ os->bfd_section->flags)
		  & (SEC_LOAD | SEC_ALLOC)) == 0))
	{
	  /* We already have an output section statement with this
	     name, and its bfd section, if any, has compatible flags.  */
	  lang_add_section (&os->children, s, os, file);
	  return TRUE;
	}
    }

  if (hold_text.os == NULL)
    hold_text.os = lang_output_section_find (".text");

  /* If this is a final link, then always put .gnu.warning.SYMBOL
     sections into the .text section to get them out of the way.  */
  if (link_info.executable
      && ! link_info.relocatable
      && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
      && hold_text.os != NULL)
    {
      lang_add_section (&hold_text.os->children, s, hold_text.os, file);
      return TRUE;
    }

  /* Decide which segment the section should go in based on the
     section name and section flags.  We put loadable .note sections
     right after the .interp section, so that the PT_NOTE segment is
     stored right after the program headers where the OS can read it
     in the first page.  */
#define HAVE_SECTION(hold, name) (hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)

  if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocatable)
    {
      if (s->output_section == NULL)
	s->output_section = bfd_abs_section_ptr;
      return TRUE;
    }

  place = NULL;
  if ((s->flags & SEC_ALLOC) == 0)
    ;
  else if ((s->flags & SEC_LOAD) != 0
	   && strncmp (secname, ".note", 5) == 0
	   && HAVE_SECTION (hold_interp, ".interp"))
    place = &hold_interp;
  else if ((s->flags & SEC_HAS_CONTENTS) == 0
	   && HAVE_SECTION (hold_bss, ".bss"))
    place = &hold_bss;
  else if ((s->flags & SEC_SMALL_DATA) != 0
	   && HAVE_SECTION (hold_sdata, ".sdata"))
    place = &hold_sdata;
  else if ((s->flags & SEC_READONLY) == 0
	   && HAVE_SECTION (hold_data, ".data"))
    place = &hold_data;
  else if (strncmp (secname, ".rel", 4) == 0
	   && (s->flags & SEC_LOAD) != 0
	   && (hold_rel.os != NULL
	       || (hold_rel.os = output_rel_find (s, isdyn)) != NULL))
    place = &hold_rel;
  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
	   && HAVE_SECTION (hold_rodata, ".rodata"))
    place = &hold_rodata;
  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
	   && hold_text.os != NULL)
    place = &hold_text;

#undef HAVE_SECTION

  /* Choose a unique name for the section.  This will be needed if the
     same section name appears in the input file with different
     loadable or allocatable characteristics.  */
  if (bfd_get_section_by_name (output_bfd, secname) != NULL)
    {
      secname = bfd_get_unique_section_name (output_bfd, secname, &count);
      if (secname == NULL)
	einfo ("%F%P: place_orphan failed: %E\n");
    }

  /* Start building a list of statements for this section.
     First save the current statement pointer.  */
  old = stat_ptr;

  /* If we have found an appropriate place for the output section
     statements for this orphan, add them to our own private list,
     inserting them later into the global statement list.  */
  if (place != NULL)
    {
      stat_ptr = &add;
      lang_list_init (stat_ptr);
    }

  if (config.build_constructors)
    {
      /* If the name of the section is representable in C, then create
	 symbols to mark the start and the end of the section.  */
      for (ps = secname; *ps != '\0'; ps++)
	if (! ISALNUM (*ps) && *ps != '_')
	  break;
      if (*ps == '\0')
	{
	  char *symname;
	  etree_type *e_align;

	  symname = (char *) xmalloc (ps - secname + sizeof "__start_");
	  sprintf (symname, "__start_%s", secname);
	  e_align = exp_unop (ALIGN_K,
			      exp_intop ((bfd_vma) 1 << s->alignment_power));
	  lang_add_assignment (exp_assop ('=', symname, e_align));
	}
    }

  address = NULL;
  if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
    address = exp_intop ((bfd_vma) 0);

  load_base = NULL;
  if (place != NULL && place->os->load_base != NULL)
    {
      etree_type *lma_from_vma;
      lma_from_vma = exp_binop ('-', place->os->load_base,
				exp_nameop (ADDR, place->os->name));
      load_base = exp_binop ('+', lma_from_vma,
			     exp_nameop (ADDR, secname));
    }

  os_tail = lang_output_section_statement.tail;
  os = lang_enter_output_section_statement (secname, address, 0,
					    (bfd_vma) 0,
					    (etree_type *) NULL,
					    (etree_type *) NULL,
					    load_base);

  lang_add_section (&os->children, s, os, file);

  lang_leave_output_section_statement
    ((bfd_vma) 0, "*default*",
     (struct lang_output_section_phdr_list *) NULL, NULL);

  if (config.build_constructors && *ps == '\0')
    {
      char *symname;

      /* lang_leave_ouput_section_statement resets stat_ptr.  Put
	 stat_ptr back where we want it.  */
      if (place != NULL)
	stat_ptr = &add;

      symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
      sprintf (symname, "__stop_%s", secname);
      lang_add_assignment (exp_assop ('=', symname,
				      exp_nameop (NAME, ".")));
    }

  /* Restore the global list pointer.  */
  stat_ptr = old;

  if (place != NULL && os->bfd_section != NULL)
    {
      asection *snew, **pps;

      snew = os->bfd_section;

      /* Shuffle the bfd section list to make the output file look
	 neater.  This is really only cosmetic.  */
      if (place->section == NULL)
	{
	  asection *bfd_section = place->os->bfd_section;

	  /* If the output statement hasn't been used to place
	     any input sections (and thus doesn't have an output
	     bfd_section), look for the closest prior output statement
	     having an output section.  */
	  if (bfd_section == NULL)
	    bfd_section = output_prev_sec_find (place->os);

	  if (bfd_section != NULL && bfd_section != snew)
	    place->section = &bfd_section->next;
	}

      if (place->section != NULL)
	{
	  /* Unlink the section.  */
	  for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
	    ;
	  bfd_section_list_remove (output_bfd, pps);

	  /* Now tack it on to the "place->os" section list.  */
	  bfd_section_list_insert (output_bfd, place->section, snew);
	}

      /* Save the end of this list.  Further ophans of this type will
	 follow the one we've just added.  */
      place->section = &snew->next;

      /* The following is non-cosmetic.  We try to put the output
	 statements in some sort of reasonable order here, because
	 they determine the final load addresses of the orphan
	 sections.  In addition, placing output statements in the
	 wrong order may require extra segments.  For instance,
	 given a typical situation of all read-only sections placed
	 in one segment and following that a segment containing all
	 the read-write sections, we wouldn't want to place an orphan
	 read/write section before or amongst the read-only ones.  */
      if (add.head != NULL)
	{
	  lang_statement_union_type *newly_added_os;

	  if (place->stmt == NULL)
	    {
	      /* Put the new statement list right at the head.  */
	      *add.tail = place->os->header.next;
	      place->os->header.next = add.head;

	      place->os_tail = &place->os->next;
	    }
	  else
	    {
	      /* Put it after the last orphan statement we added.  */
	      *add.tail = *place->stmt;
	      *place->stmt = add.head;
	    }

	  /* Fix the global list pointer if we happened to tack our
	     new list at the tail.  */
	  if (*old->tail == add.head)
	    old->tail = add.tail;

	  /* Save the end of this list.  */
	  place->stmt = add.tail;

	  /* Do the same for the list of output section statements.  */
	  newly_added_os = *os_tail;
	  *os_tail = NULL;
	  newly_added_os->output_section_statement.next = *place->os_tail;
	  *place->os_tail = newly_added_os;
	  place->os_tail = &newly_added_os->output_section_statement.next;

	  /* Fixing the global list pointer here is a little different.
	     We added to the list in lang_enter_output_section_statement,
	     trimmed off the new output_section_statment above when
	     assigning *os_tail = NULL, but possibly added it back in
	     the same place when assigning *place->os_tail.  */
	  if (*os_tail == NULL)
	    lang_output_section_statement.tail = os_tail;
	}
    }

  return TRUE;
}
Exemplo n.º 3
0
/*
 * allocate_data_memory()
 *
 * This function attempts to allocate data memory sections.
 *
 * Called by: allocate_memory()
 *
 * Calls:     build_section_list()
 *            build_free_block_list()
 *            locate_sections()
 *
 * Returns:   status code
 *            (0 = success)
 *
 * Notes: List "data_memory_free_blocks" is needed by
 *        bfd_pic322_finish() to allocate the stack
 *        and heap, so don't exit this function early.
 *
 *        EDS allocation is tricky. Although these sections
 *        can be allocated anywhere, we need to preserve
 *        low memory for the stack. In the first pass,
 *        we exclude memory below the stack limit altogether.
 *        In the second pass, we scan free blocks in reverse
 *        only, which helps when a block crosses the
 *        stack limit boundary. Eventually we'll take
 *        whatever memory we need to, and leave the rest
 *        for the stack and heap.
 *
 *        We also support allocation of stack and heap
 *        that are defined with section attributes.
 *
 *        See comments below for additional info
 *        about stack allocation.
 */
static int
allocate_data_memory() {
  struct memory_region_struct *region;
  struct pic32_section *s;
  unsigned int mask = data|bss|persist|stack|heap|ramfunc;
  int result = 0;

  if (pic32_debug)
    printf("\nBuilding allocation list for region \"data\"\n"
           "  attribute mask = %x\n", mask);

  build_alloc_section_list(mask);
  region = region_lookup ("kseg1_data_mem");

  build_free_block_list(region, mask);

  if (pic32_debug) {
    pic32_print_section_list(alloc_section_list, "allocation");
  }

  reset_locate_options();
  result |= locate_sections(ramfunc, 0, region);    /* most restrictive  */
  
  if (!bfd_pic32_is_defined_global_symbol("_ramfunc_begin"))
  {
    /* If there are no ram fumctions, add the _ramfunc_begin symbol with value 0 */
    _bfd_generic_link_add_one_symbol (&link_info, link_info.output_bfd, "_ramfunc_begin",
    BSF_GLOBAL, bfd_abs_section_ptr,
    0, "_ramfunc_begin", 1, 0, 0);
  }
  
  if (ramfunc_begin != 0) {
    set_locate_options(EXCLUDE_HIGH_ADDR, ramfunc_begin);
  }
  result |= locate_sections(address, 0, region);
  result |= locate_sections(near, 0, region);       /* less restrictive  */
  result |= locate_sections(all_attr, stack|heap, region);

#if 0
  /* user-defined heap */
  if (ramfunc_begin != 0) {
    set_locate_options(EXCLUDE_HIGH_ADDR, ramfunc_begin);
  }
  result |= locate_sections(heap, 0, region);

  /* user-defined stack */
  if (ramfunc_begin != 0) {
    set_locate_options(EXCLUDE_HIGH_ADDR, ramfunc_begin);
  }
  result |= locate_sections(stack, 0, region);
#else
  /* Don't support user-defined stack sections yet */
  for (s = alloc_section_list; s != NULL; s = s->next) {
    if (s->sec && (PIC32_IS_STACK_ATTR(s->sec) || PIC32_IS_HEAP_ATTR(s->sec))) {
      lang_output_section_statement_type *os;
      s->sec->lma = 0;
      s->sec->vma = 0;
      os = lang_output_section_statement_lookup (".stack", 0, TRUE);
      /* lang_add_section() will call init_os() if needed */
      lang_add_section (&os->children, s->sec, os);
      finish_section_info(s, os);
      pic32_remove_from_section_list(alloc_section_list,s);
      os->bfd_section->flags = s->sec->flags;
    }
  }

#endif

  /* if any sections are left in the allocation list, report an error */
  for (s = alloc_section_list; s != NULL; s = s->next) {
  if (s->attributes != 0) {
    report_allocation_error(s);
    result = 1;
    break;
  }
  }

  /* save the free blocks list */
  data_memory_free_blocks = free_blocks;
  free_blocks = 0;

  return result;
} /* allocate_data_memory() */
Exemplo n.º 4
0
/*
 * allocate_memory()
 *
 * This function attempts to locate sections using
 * a best-fit algorithm. The term "best-fit" implies
 * that the smallest suitable free block will be used
 * for each section. This approach makes efficient use
 * of the free block list and reduces fragmentation.
 *
 * Called by: ldemul_after_allocation()
 *
 * Calls:     allocate_program_memory()
 *            allocate_data_memory()
 *            bfd_map_over_sections()
 *
 * If any of the sub-processes fail, report it
 * and continue. This helps to suppress misleading
 * messages, and follows the general philosophy
 * of doing as much work as we can, despite the
 * occurrence of fatal errors.
 */
static void
allocate_memory() {
  int result;
  lang_output_section_statement_type **last_os;

#define ERR_STR " Link Error: Could not allocate "

  /* save the last output section statement
     after sequential allocation */
  last_os = (lang_output_section_statement_type **) statement_list.tail;

  /*
   * Build an ordered list of output sections
   * that were placed by sequential allocator.
   * It will help identify any gaps between
   * output sections that are available.
   */
  pic32_init_section_list (&pic32_section_list);

  bfd_map_over_sections (link_info.output_bfd, &pic32_build_section_list, NULL);
  bfd_map_over_sections (link_info.output_bfd, &pic32_build_section_list_vma, NULL);

  if (pic32_debug) {
    pic32_print_section_list(unassigned_sections, "unassigned");
    pic32_print_section_list(memory_region_list, "memory region");
  }

  result = allocate_data_memory();
  if (result != 0)
    einfo(_("%F%sdata memory\n"), ERR_STR );

  result = allocate_program_memory();
  if (result != 0)
    einfo(_("%F%sprogram memory\n"), ERR_STR );
#if 0
  if (has_user_defined_memory) {
    result = allocate_user_memory();
    if (result != 0)
      einfo(_("%F%suser-defined memory region\n"), ERR_STR );
  }
#endif
  /* allocate the heap, if required */

  /* allocate the stack, unless the user has defined one */

  /* free the output section list */
  pic32_free_section_list(&pic32_section_list);

  /*
   * Scan over the output section statements
   * and merge any contiguous sections
   * with the same name, unless the
   * --unique option tells us not to.
   *
   * We start where the sequential allocator
   * finished, so that any merges are well understood.
   * For example, all of the best-fit output sections
   * contain a single input section.
   */
  {
    lang_statement_union_type *os, *next;
    asection *sec, *next_sec;
    unsigned int len, match, merge_sec = 0;
    bfd_vma sec_len, next_len = 0, merge_len = 0;
    char *p,*p2;

    if (pic32_debug)
      printf("\nScanning the output statements\n");

    for (os = (lang_statement_union_type *) *last_os;
         os != (lang_statement_union_type *) NULL;
         os = next) {

      /* clear the accumulator, if we didn't just merge */
      if (!merge_sec) merge_len = 0;

      merge_sec = 0;
      next = os->header.next;
      if (os->header.type == lang_output_section_statement_enum) {

        if (os->output_section_statement.bfd_section == NULL)
          /* --gc-sections has discarded this section */
          continue;

        sec = os->output_section_statement.bfd_section;
        if (os->output_section_statement.children.head                                      ->input_section.section->rawsize)
          sec_len = os->output_section_statement.children.head
                    ->input_section.section->rawsize;
        else
          sec_len = os->output_section_statement.children.head
                    ->input_section.section->size;

        if (!sec || !sec->name) continue;

        if (next && (next->header.type == lang_output_section_statement_enum)) {
          next_sec = next->output_section_statement.bfd_section;
	  if (next->output_section_statement.children.head) {
            if (next->output_section_statement.children.head->
                         input_section.section->rawsize)
              next_len = next->output_section_statement.children.head->
                         input_section.section->rawsize;
            else
              next_len = next->output_section_statement.children.head->
                         input_section.section->size;
          }

          if (!next_sec || !next_sec->name) continue;

          if (next->output_section_statement.children.head->
                input_section.section->size == 0) continue;

          /* if section address and len don't match, continue */
          if ((sec->lma + sec_len + merge_len) != next_sec->lma) continue;

          p = strchr(sec->name, '%');
          p2 = strchr(next_sec->name, '%');
          if (p && p2) {
            len = p - sec->name;
            if (len != (unsigned) (p2 - next_sec->name))
              continue;
            match = (strncmp(sec->name, next_sec->name, len) == 0);
          } else
            match = (strcmp(sec->name, next_sec->name) == 0);

          if (match && !config.unique_orphan_sections &&
              !pic32_unique_section(sec->name) &&
              (pic32_attribute_map(sec) == pic32_attribute_map(next_sec))) {

            if (pic32_debug) {
              printf("  Merging output sections %s and %s\n",
                      sec->name, next_sec->name);
              printf("    %s: addr = %lx, len = %lx\n",
                     sec->name, sec->lma, sec_len + merge_len);
              printf("    %s: addr = %lx, len = %lx\n",
                     next_sec->name, next_sec->lma, next_len);
            }

            merge_sec = 1; /* set a flag to indicate we're merging */
            merge_len += next_len;
            next->output_section_statement.children.head->
              input_section.section->output_section = NULL;

            lang_add_section (&os->output_section_statement.children,
                              next->output_section_statement.children.head
                              ->input_section.section,
                              &os->output_section_statement);

            /* remove the merged section from output_bfd */
            remove_section_from_bfd(link_info.output_bfd, next_sec);
          }
        }
      }

      if (merge_sec) {
        os->header.next = next->header.next;  /* unlink the merged statement */
        next = os;                            /* try to merge another one */
      }
    }
  }

} /* allocate_memory() */