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; }
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 (); }
void mri_draw_tree (void) { if (done_tree) return; /* Now build the statements for the ldlang machine. */ /* Attach the addresses of any which have addresses, and add the ones not mentioned. */ if (address != NULL) { struct section_name_struct *alist; struct section_name_struct *olist; if (order == NULL) order = address; for (alist = address; alist != NULL; alist = alist->next) { int done = 0; for (olist = order; done == 0 && olist != NULL; olist = olist->next) { if (strcmp (alist->name, olist->name) == 0) { olist->vma = alist->vma; done = 1; } } if (!done) { /* Add this onto end of order list. */ mri_add_to_list (&order, alist->name, alist->vma, 0, 0, 0); } } } /* If we're only supposed to load a subset of them in, then prune the list. */ if (only_load != NULL) { struct section_name_struct *ptr1; struct section_name_struct *ptr2; if (order == NULL) order = only_load; /* See if this name is in the list, if it is then we can load it. */ for (ptr1 = only_load; ptr1; ptr1 = ptr1->next) for (ptr2 = order; ptr2; ptr2 = ptr2->next) if (strcmp (ptr2->name, ptr1->name) == 0) ptr2->ok_to_load = 1; } else { /* No only load list, so everything is ok to load. */ struct section_name_struct *ptr; for (ptr = order; ptr; ptr = ptr->next) ptr->ok_to_load = 1; } /* Create the order of sections to load. */ if (order != NULL) { /* Been told to output the sections in a certain order. */ struct section_name_struct *p = order; while (p) { struct section_name_struct *aptr; etree_type *align = 0; etree_type *subalign = 0; struct wildcard_list *tmp; /* See if an alignment has been specified. */ for (aptr = alignment; aptr; aptr = aptr->next) if (strcmp (aptr->name, p->name) == 0) align = aptr->align; for (aptr = subalignment; aptr; aptr = aptr->next) if (strcmp (aptr->name, p->name) == 0) subalign = aptr->subalign; if (base == 0) base = p->vma ? p->vma : exp_nameop (NAME, "."); lang_enter_output_section_statement (p->name, base, p->ok_to_load ? 0 : noload_section, align, subalign, NULL, 0); base = 0; tmp = xmalloc (sizeof *tmp); tmp->next = NULL; tmp->spec.name = p->name; tmp->spec.exclude_name_list = NULL; tmp->spec.sorted = none; lang_add_wild (NULL, tmp, FALSE); /* If there is an alias for this section, add it too. */ for (aptr = alias; aptr; aptr = aptr->next) if (strcmp (aptr->alias, p->name) == 0) { tmp = xmalloc (sizeof *tmp); tmp->next = NULL; tmp->spec.name = aptr->name; tmp->spec.exclude_name_list = NULL; tmp->spec.sorted = none; lang_add_wild (NULL, tmp, FALSE); } lang_leave_output_section_statement (0, "*default*", NULL, NULL); p = p->next; } } done_tree = 1; }