char * pic32_section_attr_string (asection *sec)
{
#undef MAX_LEN
#define MAX_LEN 120
#define A1 "attributes = "

  int i,b;
  unsigned int map = pic32_attribute_map(sec);
  char *result = (char *) bfd_malloc (MAX_LEN);

  if (result == (char *) NULL)
    return result;

  result[0] = 0; /* start with a null terminator */
  result = strcat( result, A1 );

  for (i = 0; i < 31; i++) {
    b = map & 1;
    if (b) {
      result = strncat( result, names[i], MAX_LEN - strlen(result) -2);
      result = strcat( result, " " );
    }
    map >>= 1;
  }

  return result;

}
int
pic32_set_implied_attributes(asection *sec, unsigned char flag_debug)
{
  int result = 0;  /* default = quiet, no conflicts */
  unsigned int mask;
  long map = pic32_attribute_map(sec);

  if (flag_debug || pic32_debug)
    printf ("--> pic32_set_implied_attributes::begin\n");

  if (flag_debug || pic32_debug)
    printf ("    pic32_set_implied_attributes::map = %lx\n", map);


#undef ATTR
#undef ATTR_IS
#undef MASK1
#undef MASK2
#undef MASK3
#undef MASK4
#define MASK4(id,quiet,c,d)                                               \
  }  else if SECTION(id) {                                                 \
      mask = (1<<c);         /* set type */                               \
      if (d) mask |= (1<<d); /* and modifier (if any) */                  \
      if (flag_debug || pic32_debug) {                                                   \
        printf ("    pic32_set_implied_attributes::section = %s\n", #id); \
        printf ("    pic32_set_implied_attributes::mask = %x\n", mask);   \
      }                                                                   \
      if ((map & mask) == mask)                                           \
        {} /* do nothing */                                               \
      else if (pic32_is_valid_attributes((map|mask), flag_debug))         \
        { /* set the implied attributes */                                \
          pic32_set_attributes(sec, mask, flag_debug);                    \
          result = !(quiet); }                                            \
      else                                                                \
        result = -1; /* report the conflict */

 if (0) {
#include "pic32-attributes.h"
 } else                           /* a section by any other name... */
   if ((map &                     /* if no type attribute is set    */
        (TYPE_ATTR_MASK | INFO_ATTR_MASK)) == 0)
       PIC32_SET_DATA_ATTR(sec);  /* set the default, quietly       */

  if (flag_debug || pic32_debug)
    printf ("<-- pic32_set_implied_attributes::exit(%d)\n", result);

  return result;

} /* pic32_set_implied_attributes() */
/*
 * 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() */