123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962 |
- # This shell script emits a C file. -*- C -*-
- # Copyright (C) 2003-2015 Free Software Foundation, Inc.
- #
- # This file is part of the GNU Binutils.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- # MA 02110-1301, USA.
- #
- # This file is sourced from elf32.em, and defines extra xtensa-elf
- # specific routines.
- #
- fragment <<EOF
- #include <xtensa-config.h>
- #include "../bfd/elf-bfd.h"
- #include "../bfd/libbfd.h"
- #include "elf/xtensa.h"
- #include "bfd.h"
- /* Provide default values for new configuration settings. */
- #ifndef XSHAL_ABI
- #define XSHAL_ABI 0
- #endif
- static void xtensa_wild_group_interleave (lang_statement_union_type *);
- static void xtensa_colocate_output_literals (lang_statement_union_type *);
- static void xtensa_strip_inconsistent_linkonce_sections
- (lang_statement_list_type *);
- /* This number is irrelevant until we turn on use_literal_pages */
- static bfd_vma xtensa_page_power = 12; /* 4K pages. */
- /* To force a page break between literals and text, change
- xtensa_use_literal_pages to "TRUE". */
- static bfd_boolean xtensa_use_literal_pages = FALSE;
- #define EXTRA_VALIDATION 0
- static char *
- elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED,
- char **argv ATTRIBUTE_UNUSED)
- {
- if (XCHAL_HAVE_BE)
- return "${BIG_OUTPUT_FORMAT}";
- else
- return "${LITTLE_OUTPUT_FORMAT}";
- }
- static void
- elf_xtensa_before_parse (void)
- {
- /* Just call the default hook.... Tensilica's version of this function
- does some other work that isn't relevant here. */
- gld${EMULATION_NAME}_before_parse ();
- }
- static void
- remove_section (bfd *abfd, asection *os)
- {
- asection **spp;
- for (spp = &abfd->sections; *spp; spp = &(*spp)->next)
- if (*spp == os)
- {
- *spp = os->next;
- os->owner->section_count--;
- break;
- }
- }
- static bfd_boolean
- replace_insn_sec_with_prop_sec (bfd *abfd,
- const char *insn_sec_name,
- const char *prop_sec_name,
- char **error_message)
- {
- asection *insn_sec;
- asection *prop_sec;
- bfd_byte *prop_contents = NULL;
- bfd_byte *insn_contents = NULL;
- unsigned entry_count;
- unsigned entry;
- Elf_Internal_Shdr *rel_hdr;
- Elf_Internal_Rela *internal_relocs = NULL;
- unsigned reloc_count;
- *error_message = "";
- insn_sec = bfd_get_section_by_name (abfd, insn_sec_name);
- if (insn_sec == NULL)
- return TRUE;
- entry_count = insn_sec->size / 8;
- prop_sec = bfd_get_section_by_name (abfd, prop_sec_name);
- if (prop_sec != NULL && insn_sec != NULL)
- {
- *error_message = _("file already has property tables");
- return FALSE;
- }
- if (insn_sec->size != 0)
- {
- insn_contents = (bfd_byte *) bfd_malloc (insn_sec->size);
- if (insn_contents == NULL)
- {
- *error_message = _("out of memory");
- goto cleanup;
- }
- if (! bfd_get_section_contents (abfd, insn_sec, insn_contents,
- (file_ptr) 0, insn_sec->size))
- {
- *error_message = _("failed to read section contents");
- goto cleanup;
- }
- }
- /* Create a property table section for it. */
- prop_sec_name = strdup (prop_sec_name);
- prop_sec = bfd_make_section_with_flags
- (abfd, prop_sec_name, bfd_get_section_flags (abfd, insn_sec));
- if (prop_sec == NULL
- || ! bfd_set_section_alignment (abfd, prop_sec, 2))
- {
- *error_message = _("could not create new section");
- goto cleanup;
- }
- prop_sec->size = entry_count * 12;
- prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size);
- elf_section_data (prop_sec)->this_hdr.contents = prop_contents;
- /* The entry size and size must be set to allow the linker to compute
- the number of relocations since it does not use reloc_count. */
- rel_hdr = _bfd_elf_single_rel_hdr (prop_sec);
- rel_hdr->sh_entsize = sizeof (Elf32_External_Rela);
- rel_hdr->sh_size = _bfd_elf_single_rel_hdr (insn_sec)->sh_size;
- if (prop_contents == NULL && prop_sec->size != 0)
- {
- *error_message = _("could not allocate section contents");
- goto cleanup;
- }
- /* Read the relocations. */
- reloc_count = insn_sec->reloc_count;
- if (reloc_count != 0)
- {
- /* If there is already an internal_reloc, then save it so that the
- read_relocs function freshly allocates a copy. */
- Elf_Internal_Rela *saved_relocs = elf_section_data (insn_sec)->relocs;
- elf_section_data (insn_sec)->relocs = NULL;
- internal_relocs =
- _bfd_elf_link_read_relocs (abfd, insn_sec, NULL, NULL, FALSE);
- elf_section_data (insn_sec)->relocs = saved_relocs;
- if (internal_relocs == NULL)
- {
- *error_message = _("out of memory");
- goto cleanup;
- }
- }
- /* Create a relocation section for the property section. */
- if (internal_relocs != NULL)
- {
- elf_section_data (prop_sec)->relocs = internal_relocs;
- prop_sec->reloc_count = reloc_count;
- }
- /* Now copy each insn table entry to the prop table entry with
- appropriate flags. */
- for (entry = 0; entry < entry_count; ++entry)
- {
- unsigned value;
- unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_NO_TRANSFORM
- | XTENSA_PROP_INSN_NO_REORDER);
- value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0);
- bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0);
- value = bfd_get_32 (abfd, insn_contents + entry * 8 + 4);
- bfd_put_32 (abfd, value, prop_contents + entry * 12 + 4);
- bfd_put_32 (abfd, flags, prop_contents + entry * 12 + 8);
- }
- /* Now copy all of the relocations. Change offsets for the
- instruction table section to offsets in the property table
- section. */
- if (internal_relocs)
- {
- unsigned i;
- for (i = 0; i < reloc_count; i++)
- {
- Elf_Internal_Rela *rela;
- unsigned r_offset;
- rela = &internal_relocs[i];
- /* If this relocation is to the .xt.insn section,
- change the section number and the offset. */
- r_offset = rela->r_offset;
- r_offset += 4 * (r_offset / 8);
- rela->r_offset = r_offset;
- }
- }
- remove_section (abfd, insn_sec);
- if (insn_contents)
- free (insn_contents);
- return TRUE;
- cleanup:
- if (prop_sec && prop_sec->owner)
- remove_section (abfd, prop_sec);
- if (insn_contents)
- free (insn_contents);
- if (internal_relocs)
- free (internal_relocs);
- return FALSE;
- }
- #define PROP_SEC_BASE_NAME ".xt.prop"
- #define INSN_SEC_BASE_NAME ".xt.insn"
- #define LINKONCE_SEC_OLD_TEXT_BASE_NAME ".gnu.linkonce.x."
- static void
- replace_instruction_table_sections (bfd *abfd, asection *sec)
- {
- char *message = "";
- const char *insn_sec_name = NULL;
- char *prop_sec_name = NULL;
- char *owned_prop_sec_name = NULL;
- const char *sec_name;
- sec_name = bfd_get_section_name (abfd, sec);
- if (strcmp (sec_name, INSN_SEC_BASE_NAME) == 0)
- {
- insn_sec_name = INSN_SEC_BASE_NAME;
- prop_sec_name = PROP_SEC_BASE_NAME;
- }
- else if (CONST_STRNEQ (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME))
- {
- insn_sec_name = sec_name;
- owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20);
- prop_sec_name = owned_prop_sec_name;
- strcpy (prop_sec_name, ".gnu.linkonce.prop.t.");
- strcat (prop_sec_name,
- sec_name + strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME));
- }
- if (insn_sec_name != NULL)
- {
- if (! replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name,
- &message))
- {
- einfo (_("%P: warning: failed to convert %s table in %B (%s); subsequent disassembly may be incomplete\n"),
- insn_sec_name, abfd, message);
- }
- }
- if (owned_prop_sec_name)
- free (owned_prop_sec_name);
- }
- /* This is called after all input sections have been opened to convert
- instruction tables (.xt.insn, gnu.linkonce.x.*) tables into property
- tables (.xt.prop) before any section placement. */
- static void
- elf_xtensa_after_open (void)
- {
- /* First call the ELF version. */
- gld${EMULATION_NAME}_after_open ();
- /* Now search the input files looking for instruction table sections. */
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- asection *sec = f->the_bfd->sections;
- asection *next_sec;
- /* Do not use bfd_map_over_sections here since we are removing
- sections as we iterate. */
- while (sec != NULL)
- {
- next_sec = sec->next;
- replace_instruction_table_sections (f->the_bfd, sec);
- sec = next_sec;
- }
- }
- }
- static bfd_boolean
- xt_config_info_unpack_and_check (char *data,
- bfd_boolean *pmismatch,
- char **pmsg)
- {
- char *d, *key;
- unsigned num;
- *pmismatch = FALSE;
- d = data;
- while (*d)
- {
- key = d;
- d = strchr (d, '=');
- if (! d)
- goto error;
- /* Overwrite the equal sign. */
- *d++ = 0;
- /* Check if this is a quoted string or a number. */
- if (*d == '"')
- {
- /* No string values are currently checked by LD;
- just skip over the quotes. */
- d++;
- d = strchr (d, '"');
- if (! d)
- goto error;
- /* Overwrite the trailing quote. */
- *d++ = 0;
- }
- else
- {
- if (*d == 0)
- goto error;
- num = strtoul (d, &d, 0);
- if (! strcmp (key, "ABI"))
- {
- if (num != XSHAL_ABI)
- {
- *pmismatch = TRUE;
- *pmsg = "ABI does not match";
- }
- }
- else if (! strcmp (key, "USE_ABSOLUTE_LITERALS"))
- {
- if (num != XSHAL_USE_ABSOLUTE_LITERALS)
- {
- *pmismatch = TRUE;
- *pmsg = "incompatible use of the Extended L32R option";
- }
- }
- }
- if (*d++ != '\n')
- goto error;
- }
- return TRUE;
- error:
- return FALSE;
- }
- #define XTINFO_NAME "Xtensa_Info"
- #define XTINFO_NAMESZ 12
- #define XTINFO_TYPE 1
- static void
- check_xtensa_info (bfd *abfd, asection *info_sec)
- {
- char *data, *errmsg = "";
- bfd_boolean mismatch;
- data = xmalloc (info_sec->size);
- if (! bfd_get_section_contents (abfd, info_sec, data, 0, info_sec->size))
- einfo (_("%F%P:%B: cannot read contents of section %A\n"), abfd, info_sec);
- if (info_sec->size > 24
- && info_sec->size >= 24 + bfd_get_32 (abfd, data + 4)
- && bfd_get_32 (abfd, data + 0) == XTINFO_NAMESZ
- && bfd_get_32 (abfd, data + 8) == XTINFO_TYPE
- && strcmp (data + 12, XTINFO_NAME) == 0
- && xt_config_info_unpack_and_check (data + 12 + XTINFO_NAMESZ,
- &mismatch, &errmsg))
- {
- if (mismatch)
- einfo (_("%P:%B: warning: incompatible Xtensa configuration (%s)\n"),
- abfd, errmsg);
- }
- else
- einfo (_("%P:%B: warning: cannot parse .xtensa.info section\n"), abfd);
- free (data);
- }
- /* This is called after the sections have been attached to output
- sections, but before any sizes or addresses have been set. */
- static void
- elf_xtensa_before_allocation (void)
- {
- asection *info_sec, *first_info_sec;
- bfd *first_bfd;
- bfd_boolean is_big_endian = XCHAL_HAVE_BE;
- /* Check that the output endianness matches the Xtensa
- configuration. The BFD library always includes both big and
- little endian target vectors for Xtensa, but it only supports the
- detailed instruction encode/decode operations (such as are
- required to process relocations) for the selected Xtensa
- configuration. */
- if (is_big_endian
- && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
- {
- einfo (_("%F%P: little endian output does not match "
- "Xtensa configuration\n"));
- }
- if (!is_big_endian
- && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_BIG)
- {
- einfo (_("%F%P: big endian output does not match "
- "Xtensa configuration\n"));
- }
- /* Keep track of the first input .xtensa.info section, and as a fallback,
- the first input bfd where a .xtensa.info section could be created.
- After the input .xtensa.info has been checked, the contents of the
- first one will be replaced with the output .xtensa.info table. */
- first_info_sec = 0;
- first_bfd = 0;
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- /* Check that the endianness for each input file matches the output.
- The merge_private_bfd_data hook has already reported any mismatches
- as errors, but those errors are not fatal. At this point, we
- cannot go any further if there are any mismatches. */
- if ((is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
- || (!is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_BIG))
- einfo (_("%F%P: cross-endian linking for %B not supported\n"),
- f->the_bfd);
- if (! first_bfd)
- first_bfd = f->the_bfd;
- info_sec = bfd_get_section_by_name (f->the_bfd, ".xtensa.info");
- if (! info_sec)
- continue;
- if (! first_info_sec)
- first_info_sec = info_sec;
- /* Unpack the .xtensa.info section and check it against the current
- Xtensa configuration. */
- check_xtensa_info (f->the_bfd, info_sec);
- /* Do not include this copy of .xtensa.info in the output. */
- info_sec->size = 0;
- info_sec->flags |= SEC_EXCLUDE;
- }
- /* Reuse the first .xtensa.info input section to hold the output
- .xtensa.info; or, if none were found, create a new section in the
- first input bfd (assuming there is one). */
- info_sec = first_info_sec;
- if (! info_sec && first_bfd)
- {
- info_sec = bfd_make_section_with_flags (first_bfd, ".xtensa.info",
- SEC_HAS_CONTENTS | SEC_READONLY);
- if (! info_sec)
- einfo (_("%F%P: failed to create .xtensa.info section\n"));
- }
- if (info_sec)
- {
- int xtensa_info_size;
- char *data;
- info_sec->flags &= ~SEC_EXCLUDE;
- info_sec->flags |= SEC_IN_MEMORY;
- data = xmalloc (100);
- sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
- XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
- xtensa_info_size = strlen (data) + 1;
- /* Add enough null terminators to pad to a word boundary. */
- do
- data[xtensa_info_size++] = 0;
- while ((xtensa_info_size & 3) != 0);
- info_sec->size = 12 + XTINFO_NAMESZ + xtensa_info_size;
- info_sec->contents = xmalloc (info_sec->size);
- bfd_put_32 (info_sec->owner, XTINFO_NAMESZ, info_sec->contents + 0);
- bfd_put_32 (info_sec->owner, xtensa_info_size, info_sec->contents + 4);
- bfd_put_32 (info_sec->owner, XTINFO_TYPE, info_sec->contents + 8);
- memcpy (info_sec->contents + 12, XTINFO_NAME, XTINFO_NAMESZ);
- memcpy (info_sec->contents + 12 + XTINFO_NAMESZ, data, xtensa_info_size);
- free (data);
- }
- /* Enable relaxation by default if the "--no-relax" option was not
- specified. This is done here instead of in the before_parse hook
- because there is a check in main() to prohibit use of --relax and
- -r together and that combination should be allowed for Xtensa. */
- if (RELAXATION_DISABLED_BY_DEFAULT)
- ENABLE_RELAXATION;
- xtensa_strip_inconsistent_linkonce_sections (stat_ptr);
- gld${EMULATION_NAME}_before_allocation ();
- xtensa_wild_group_interleave (stat_ptr->head);
- if (RELAXATION_ENABLED)
- xtensa_colocate_output_literals (stat_ptr->head);
- /* TBD: We need to force the page alignments to here and only do
- them as needed for the entire output section. Finally, if this
- is a relocatable link then we need to add alignment notes so
- that the literals can be separated later. */
- }
- typedef struct wildcard_list section_name_list;
- typedef struct reloc_deps_e_t reloc_deps_e;
- typedef struct reloc_deps_section_t reloc_deps_section;
- typedef struct reloc_deps_graph_t reloc_deps_graph;
- struct reloc_deps_e_t
- {
- asection *src; /* Contains l32rs. */
- asection *tgt; /* Contains literals. */
- reloc_deps_e *next;
- };
- /* Place these in the userdata field. */
- struct reloc_deps_section_t
- {
- reloc_deps_e *preds;
- reloc_deps_e *succs;
- bfd_boolean is_only_literal;
- };
- struct reloc_deps_graph_t
- {
- size_t count;
- size_t size;
- asection **sections;
- };
- static void xtensa_layout_wild
- (const reloc_deps_graph *, lang_wild_statement_type *);
- typedef void (*deps_callback_t) (asection *, /* src_sec */
- bfd_vma, /* src_offset */
- asection *, /* target_sec */
- bfd_vma, /* target_offset */
- void *); /* closure */
- extern bfd_boolean xtensa_callback_required_dependence
- (bfd *, asection *, struct bfd_link_info *, deps_callback_t, void *);
- static void xtensa_ldlang_clear_addresses (lang_statement_union_type *);
- static bfd_boolean ld_local_file_relocations_fit
- (lang_statement_union_type *, const reloc_deps_graph *);
- static bfd_vma ld_assign_relative_paged_dot
- (bfd_vma, lang_statement_union_type *, const reloc_deps_graph *,
- bfd_boolean);
- static bfd_vma ld_xtensa_insert_page_offsets
- (bfd_vma, lang_statement_union_type *, reloc_deps_graph *, bfd_boolean);
- #if EXTRA_VALIDATION
- static size_t ld_count_children (lang_statement_union_type *);
- #endif
- extern lang_statement_list_type constructor_list;
- static reloc_deps_section *
- xtensa_get_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
- asection *sec)
- {
- /* We have a separate function for this so that
- we could in the future keep a completely independent
- structure that maps a section to its dependence edges.
- For now, we place these in the sec->userdata field. */
- reloc_deps_section *sec_deps = sec->userdata;
- return sec_deps;
- }
- static void
- xtensa_set_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
- asection *sec,
- reloc_deps_section *deps_section)
- {
- sec->userdata = deps_section;
- }
- /* This is used to keep a list of all of the sections participating in
- the graph so we can clean them up quickly. */
- static void
- xtensa_append_section_deps (reloc_deps_graph *deps, asection *sec)
- {
- if (deps->size <= deps->count)
- {
- asection **new_sections;
- size_t i;
- size_t new_size;
- new_size = deps->size * 2;
- if (new_size == 0)
- new_size = 20;
- new_sections = xmalloc (sizeof (asection *) * new_size);
- memset (new_sections, 0, sizeof (asection *) * new_size);
- for (i = 0; i < deps->count; i++)
- {
- new_sections[i] = deps->sections[i];
- }
- if (deps->sections != NULL)
- free (deps->sections);
- deps->sections = new_sections;
- deps->size = new_size;
- }
- deps->sections[deps->count] = sec;
- deps->count++;
- }
- static void
- free_reloc_deps_graph (reloc_deps_graph *deps)
- {
- size_t i;
- for (i = 0; i < deps->count; i++)
- {
- asection *sec = deps->sections[i];
- reloc_deps_section *sec_deps;
- sec_deps = xtensa_get_section_deps (deps, sec);
- if (sec_deps)
- {
- reloc_deps_e *next;
- while (sec_deps->succs != NULL)
- {
- next = sec_deps->succs->next;
- free (sec_deps->succs);
- sec_deps->succs = next;
- }
- while (sec_deps->preds != NULL)
- {
- next = sec_deps->preds->next;
- free (sec_deps->preds);
- sec_deps->preds = next;
- }
- free (sec_deps);
- }
- xtensa_set_section_deps (deps, sec, NULL);
- }
- if (deps->sections)
- free (deps->sections);
- free (deps);
- }
- static bfd_boolean
- section_is_source (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
- lang_statement_union_type *s)
- {
- asection *sec;
- const reloc_deps_section *sec_deps;
- if (s->header.type != lang_input_section_enum)
- return FALSE;
- sec = s->input_section.section;
- sec_deps = xtensa_get_section_deps (deps, sec);
- return sec_deps && sec_deps->succs != NULL;
- }
- static bfd_boolean
- section_is_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
- lang_statement_union_type *s)
- {
- asection *sec;
- const reloc_deps_section *sec_deps;
- if (s->header.type != lang_input_section_enum)
- return FALSE;
- sec = s->input_section.section;
- sec_deps = xtensa_get_section_deps (deps, sec);
- return sec_deps && sec_deps->preds != NULL;
- }
- static bfd_boolean
- section_is_source_or_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
- lang_statement_union_type *s)
- {
- return (section_is_source (deps, s)
- || section_is_target (deps, s));
- }
- typedef struct xtensa_ld_iter_stack_t xtensa_ld_iter_stack;
- typedef struct xtensa_ld_iter_t xtensa_ld_iter;
- struct xtensa_ld_iter_t
- {
- lang_statement_union_type *parent; /* Parent of the list. */
- lang_statement_list_type *l; /* List that holds it. */
- lang_statement_union_type **loc; /* Place in the list. */
- };
- struct xtensa_ld_iter_stack_t
- {
- xtensa_ld_iter iterloc; /* List that hold it. */
- xtensa_ld_iter_stack *next; /* Next in the stack. */
- xtensa_ld_iter_stack *prev; /* Back pointer for stack. */
- };
- static void
- ld_xtensa_move_section_after (xtensa_ld_iter *to, xtensa_ld_iter *current)
- {
- lang_statement_union_type *to_next;
- lang_statement_union_type *current_next;
- lang_statement_union_type **e;
- #if EXTRA_VALIDATION
- size_t old_to_count, new_to_count;
- size_t old_current_count, new_current_count;
- #endif
- if (to == current)
- return;
- #if EXTRA_VALIDATION
- old_to_count = ld_count_children (to->parent);
- old_current_count = ld_count_children (current->parent);
- #endif
- to_next = *(to->loc);
- current_next = (*current->loc)->header.next;
- *(to->loc) = *(current->loc);
- *(current->loc) = current_next;
- (*(to->loc))->header.next = to_next;
- /* reset "to" list tail */
- for (e = &to->l->head; *e != NULL; e = &(*e)->header.next)
- ;
- to->l->tail = e;
- /* reset "current" list tail */
- for (e = ¤t->l->head; *e != NULL; e = &(*e)->header.next)
- ;
- current->l->tail = e;
- #if EXTRA_VALIDATION
- new_to_count = ld_count_children (to->parent);
- new_current_count = ld_count_children (current->parent);
- ASSERT ((old_to_count + old_current_count)
- == (new_to_count + new_current_count));
- #endif
- }
- /* Can only be called with lang_statements that have lists. Returns
- FALSE if the list is empty. */
- static bfd_boolean
- iter_stack_empty (xtensa_ld_iter_stack **stack_p)
- {
- return *stack_p == NULL;
- }
- static bfd_boolean
- iter_stack_push (xtensa_ld_iter_stack **stack_p,
- lang_statement_union_type *parent)
- {
- xtensa_ld_iter_stack *stack;
- lang_statement_list_type *l = NULL;
- switch (parent->header.type)
- {
- case lang_output_section_statement_enum:
- l = &parent->output_section_statement.children;
- break;
- case lang_wild_statement_enum:
- l = &parent->wild_statement.children;
- break;
- case lang_group_statement_enum:
- l = &parent->group_statement.children;
- break;
- default:
- ASSERT (0);
- return FALSE;
- }
- /* Empty. do not push. */
- if (l->tail == &l->head)
- return FALSE;
- stack = xmalloc (sizeof (xtensa_ld_iter_stack));
- memset (stack, 0, sizeof (xtensa_ld_iter_stack));
- stack->iterloc.parent = parent;
- stack->iterloc.l = l;
- stack->iterloc.loc = &l->head;
- stack->next = *stack_p;
- stack->prev = NULL;
- if (*stack_p != NULL)
- (*stack_p)->prev = stack;
- *stack_p = stack;
- return TRUE;
- }
- static void
- iter_stack_pop (xtensa_ld_iter_stack **stack_p)
- {
- xtensa_ld_iter_stack *stack;
- stack = *stack_p;
- if (stack == NULL)
- {
- ASSERT (stack != NULL);
- return;
- }
- if (stack->next != NULL)
- stack->next->prev = NULL;
- *stack_p = stack->next;
- free (stack);
- }
- /* This MUST be called if, during iteration, the user changes the
- underlying structure. It will check for a NULL current and advance
- accordingly. */
- static void
- iter_stack_update (xtensa_ld_iter_stack **stack_p)
- {
- if (!iter_stack_empty (stack_p)
- && (*(*stack_p)->iterloc.loc) == NULL)
- {
- iter_stack_pop (stack_p);
- while (!iter_stack_empty (stack_p)
- && ((*(*stack_p)->iterloc.loc)->header.next == NULL))
- {
- iter_stack_pop (stack_p);
- }
- if (!iter_stack_empty (stack_p))
- (*stack_p)->iterloc.loc = &(*(*stack_p)->iterloc.loc)->header.next;
- }
- }
- static void
- iter_stack_next (xtensa_ld_iter_stack **stack_p)
- {
- xtensa_ld_iter_stack *stack;
- lang_statement_union_type *current;
- stack = *stack_p;
- current = *stack->iterloc.loc;
- /* If we are on the first element. */
- if (current != NULL)
- {
- switch (current->header.type)
- {
- case lang_output_section_statement_enum:
- case lang_wild_statement_enum:
- case lang_group_statement_enum:
- /* If the list if not empty, we are done. */
- if (iter_stack_push (stack_p, *stack->iterloc.loc))
- return;
- /* Otherwise increment the pointer as normal. */
- break;
- default:
- break;
- }
- }
- while (!iter_stack_empty (stack_p)
- && ((*(*stack_p)->iterloc.loc)->header.next == NULL))
- {
- iter_stack_pop (stack_p);
- }
- if (!iter_stack_empty (stack_p))
- (*stack_p)->iterloc.loc = &(*(*stack_p)->iterloc.loc)->header.next;
- }
- static lang_statement_union_type *
- iter_stack_current (xtensa_ld_iter_stack **stack_p)
- {
- return *((*stack_p)->iterloc.loc);
- }
- /* The iter stack is a preorder. */
- static void
- iter_stack_create (xtensa_ld_iter_stack **stack_p,
- lang_statement_union_type *parent)
- {
- iter_stack_push (stack_p, parent);
- }
- static void
- iter_stack_copy_current (xtensa_ld_iter_stack **stack_p, xtensa_ld_iter *front)
- {
- *front = (*stack_p)->iterloc;
- }
- static void
- xtensa_colocate_literals (reloc_deps_graph *deps,
- lang_statement_union_type *statement)
- {
- /* Keep a stack of pointers to control iteration through the contours. */
- xtensa_ld_iter_stack *stack = NULL;
- xtensa_ld_iter_stack **stack_p = &stack;
- xtensa_ld_iter front; /* Location where new insertion should occur. */
- xtensa_ld_iter *front_p = NULL;
- xtensa_ld_iter current; /* Location we are checking. */
- xtensa_ld_iter *current_p = NULL;
- bfd_boolean in_literals = FALSE;
- if (deps->count == 0)
- return;
- iter_stack_create (stack_p, statement);
- while (!iter_stack_empty (stack_p))
- {
- bfd_boolean skip_increment = FALSE;
- lang_statement_union_type *l = iter_stack_current (stack_p);
- switch (l->header.type)
- {
- case lang_assignment_statement_enum:
- /* Any assignment statement should block reordering across it. */
- front_p = NULL;
- in_literals = FALSE;
- break;
- case lang_input_section_enum:
- if (front_p == NULL)
- {
- in_literals = (section_is_target (deps, l)
- && !section_is_source (deps, l));
- if (in_literals)
- {
- front_p = &front;
- iter_stack_copy_current (stack_p, front_p);
- }
- }
- else
- {
- bfd_boolean is_target;
- current_p = ¤t;
- iter_stack_copy_current (stack_p, current_p);
- is_target = (section_is_target (deps, l)
- && !section_is_source (deps, l));
- if (in_literals)
- {
- iter_stack_copy_current (stack_p, front_p);
- if (!is_target)
- in_literals = FALSE;
- }
- else
- {
- if (is_target)
- {
- /* Try to insert in place. */
- ld_xtensa_move_section_after (front_p, current_p);
- ld_assign_relative_paged_dot (0x100000,
- statement,
- deps,
- xtensa_use_literal_pages);
- /* We use this code because it's already written. */
- if (!ld_local_file_relocations_fit (statement, deps))
- {
- /* Move it back. */
- ld_xtensa_move_section_after (current_p, front_p);
- /* Reset the literal placement. */
- iter_stack_copy_current (stack_p, front_p);
- }
- else
- {
- /* Move front pointer up by one. */
- front_p->loc = &(*front_p->loc)->header.next;
- /* Do not increment the current pointer. */
- skip_increment = TRUE;
- }
- }
- }
- }
- break;
- default:
- break;
- }
- if (!skip_increment)
- iter_stack_next (stack_p);
- else
- /* Be careful to update the stack_p if it now is a null. */
- iter_stack_update (stack_p);
- }
- lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, statement);
- }
- static void
- xtensa_move_dependencies_to_front (reloc_deps_graph *deps,
- lang_wild_statement_type *w)
- {
- /* Keep a front pointer and a current pointer. */
- lang_statement_union_type **front;
- lang_statement_union_type **current;
- /* Walk to the end of the targets. */
- for (front = &w->children.head;
- (*front != NULL) && section_is_source_or_target (deps, *front);
- front = &(*front)->header.next)
- ;
- if (*front == NULL)
- return;
- current = &(*front)->header.next;
- while (*current != NULL)
- {
- if (section_is_source_or_target (deps, *current))
- {
- /* Insert in place. */
- xtensa_ld_iter front_iter;
- xtensa_ld_iter current_iter;
- front_iter.parent = (lang_statement_union_type *) w;
- front_iter.l = &w->children;
- front_iter.loc = front;
- current_iter.parent = (lang_statement_union_type *) w;
- current_iter.l = &w->children;
- current_iter.loc = current;
- ld_xtensa_move_section_after (&front_iter, ¤t_iter);
- front = &(*front)->header.next;
- }
- else
- {
- current = &(*current)->header.next;
- }
- }
- }
- static bfd_boolean
- deps_has_sec_edge (const reloc_deps_graph *deps, asection *src, asection *tgt)
- {
- const reloc_deps_section *sec_deps;
- const reloc_deps_e *sec_deps_e;
- sec_deps = xtensa_get_section_deps (deps, src);
- if (sec_deps == NULL)
- return FALSE;
- for (sec_deps_e = sec_deps->succs;
- sec_deps_e != NULL;
- sec_deps_e = sec_deps_e->next)
- {
- ASSERT (sec_deps_e->src == src);
- if (sec_deps_e->tgt == tgt)
- return TRUE;
- }
- return FALSE;
- }
- static bfd_boolean
- deps_has_edge (const reloc_deps_graph *deps,
- lang_statement_union_type *src,
- lang_statement_union_type *tgt)
- {
- if (!section_is_source (deps, src))
- return FALSE;
- if (!section_is_target (deps, tgt))
- return FALSE;
- if (src->header.type != lang_input_section_enum)
- return FALSE;
- if (tgt->header.type != lang_input_section_enum)
- return FALSE;
- return deps_has_sec_edge (deps, src->input_section.section,
- tgt->input_section.section);
- }
- static void
- add_deps_edge (reloc_deps_graph *deps, asection *src_sec, asection *tgt_sec)
- {
- reloc_deps_section *src_sec_deps;
- reloc_deps_section *tgt_sec_deps;
- reloc_deps_e *src_edge;
- reloc_deps_e *tgt_edge;
- if (deps_has_sec_edge (deps, src_sec, tgt_sec))
- return;
- src_sec_deps = xtensa_get_section_deps (deps, src_sec);
- if (src_sec_deps == NULL)
- {
- /* Add a section. */
- src_sec_deps = xmalloc (sizeof (reloc_deps_section));
- memset (src_sec_deps, 0, sizeof (reloc_deps_section));
- src_sec_deps->is_only_literal = 0;
- src_sec_deps->preds = NULL;
- src_sec_deps->succs = NULL;
- xtensa_set_section_deps (deps, src_sec, src_sec_deps);
- xtensa_append_section_deps (deps, src_sec);
- }
- tgt_sec_deps = xtensa_get_section_deps (deps, tgt_sec);
- if (tgt_sec_deps == NULL)
- {
- /* Add a section. */
- tgt_sec_deps = xmalloc (sizeof (reloc_deps_section));
- memset (tgt_sec_deps, 0, sizeof (reloc_deps_section));
- tgt_sec_deps->is_only_literal = 0;
- tgt_sec_deps->preds = NULL;
- tgt_sec_deps->succs = NULL;
- xtensa_set_section_deps (deps, tgt_sec, tgt_sec_deps);
- xtensa_append_section_deps (deps, tgt_sec);
- }
- /* Add the edges. */
- src_edge = xmalloc (sizeof (reloc_deps_e));
- memset (src_edge, 0, sizeof (reloc_deps_e));
- src_edge->src = src_sec;
- src_edge->tgt = tgt_sec;
- src_edge->next = src_sec_deps->succs;
- src_sec_deps->succs = src_edge;
- tgt_edge = xmalloc (sizeof (reloc_deps_e));
- memset (tgt_edge, 0, sizeof (reloc_deps_e));
- tgt_edge->src = src_sec;
- tgt_edge->tgt = tgt_sec;
- tgt_edge->next = tgt_sec_deps->preds;
- tgt_sec_deps->preds = tgt_edge;
- }
- static void
- build_deps_graph_callback (asection *src_sec,
- bfd_vma src_offset ATTRIBUTE_UNUSED,
- asection *target_sec,
- bfd_vma target_offset ATTRIBUTE_UNUSED,
- void *closure)
- {
- reloc_deps_graph *deps = closure;
- /* If the target is defined. */
- if (target_sec != NULL)
- add_deps_edge (deps, src_sec, target_sec);
- }
- static reloc_deps_graph *
- ld_build_required_section_dependence (lang_statement_union_type *s)
- {
- reloc_deps_graph *deps;
- xtensa_ld_iter_stack *stack = NULL;
- deps = xmalloc (sizeof (reloc_deps_graph));
- deps->sections = NULL;
- deps->count = 0;
- deps->size = 0;
- for (iter_stack_create (&stack, s);
- !iter_stack_empty (&stack);
- iter_stack_next (&stack))
- {
- lang_statement_union_type *l = iter_stack_current (&stack);
- if (l->header.type == lang_input_section_enum)
- {
- lang_input_section_type *input;
- input = &l->input_section;
- xtensa_callback_required_dependence (input->section->owner,
- input->section,
- &link_info,
- /* Use the same closure. */
- build_deps_graph_callback,
- deps);
- }
- }
- return deps;
- }
- #if EXTRA_VALIDATION
- static size_t
- ld_count_children (lang_statement_union_type *s)
- {
- size_t count = 0;
- xtensa_ld_iter_stack *stack = NULL;
- for (iter_stack_create (&stack, s);
- !iter_stack_empty (&stack);
- iter_stack_next (&stack))
- {
- lang_statement_union_type *l = iter_stack_current (&stack);
- ASSERT (l != NULL);
- count++;
- }
- return count;
- }
- #endif /* EXTRA_VALIDATION */
- /* Check if a particular section is included in the link. This will only
- be true for one instance of a particular linkonce section. */
- static bfd_boolean input_section_found = FALSE;
- static asection *input_section_target = NULL;
- static void
- input_section_linked_worker (lang_statement_union_type *statement)
- {
- if ((statement->header.type == lang_input_section_enum
- && (statement->input_section.section == input_section_target)))
- input_section_found = TRUE;
- }
- static bfd_boolean
- input_section_linked (asection *sec)
- {
- input_section_found = FALSE;
- input_section_target = sec;
- lang_for_each_statement_worker (input_section_linked_worker, stat_ptr->head);
- return input_section_found;
- }
- /* Strip out any linkonce property tables or XCC exception tables where the
- associated linkonce text is from a different object file. Normally,
- a matching set of linkonce sections is taken from the same object file,
- but sometimes the files are compiled differently so that some of the
- linkonce sections are not present in all files. Stripping the
- inconsistent sections like this is not completely robust -- a much
- better solution is to use comdat groups. */
- static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
- static bfd_boolean
- is_inconsistent_linkonce_section (asection *sec)
- {
- bfd *abfd = sec->owner;
- const char *sec_name = bfd_get_section_name (abfd, sec);
- const char *name;
- if ((bfd_get_section_flags (abfd, sec) & SEC_LINK_ONCE) == 0
- || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0)
- return FALSE;
- /* Check if this is an Xtensa property section or an exception table
- for Tensilica's XCC compiler. */
- name = sec_name + linkonce_len;
- if (CONST_STRNEQ (name, "prop."))
- name = strchr (name + 5, '.') ? strchr (name + 5, '.') + 1 : name + 5;
- else if (name[1] == '.'
- && (name[0] == 'p' || name[0] == 'e' || name[0] == 'h'))
- name += 2;
- else
- name = 0;
- if (name)
- {
- char *dep_sec_name = xmalloc (strlen (sec_name) + 1);
- asection *dep_sec;
- /* Get the associated linkonce text section and check if it is
- included in the link. If not, this section is inconsistent
- and should be stripped. */
- strcpy (dep_sec_name, ".gnu.linkonce.t.");
- strcat (dep_sec_name, name);
- dep_sec = bfd_get_section_by_name (abfd, dep_sec_name);
- if (dep_sec == NULL || ! input_section_linked (dep_sec))
- {
- free (dep_sec_name);
- return TRUE;
- }
- free (dep_sec_name);
- }
- return FALSE;
- }
- static void
- xtensa_strip_inconsistent_linkonce_sections (lang_statement_list_type *slist)
- {
- lang_statement_union_type **s_p = &slist->head;
- while (*s_p)
- {
- lang_statement_union_type *s = *s_p;
- lang_statement_union_type *s_next = (*s_p)->header.next;
- switch (s->header.type)
- {
- case lang_input_section_enum:
- if (is_inconsistent_linkonce_section (s->input_section.section))
- {
- s->input_section.section->output_section = bfd_abs_section_ptr;
- *s_p = s_next;
- continue;
- }
- break;
- case lang_constructors_statement_enum:
- xtensa_strip_inconsistent_linkonce_sections (&constructor_list);
- break;
- case lang_output_section_statement_enum:
- if (s->output_section_statement.children.head)
- xtensa_strip_inconsistent_linkonce_sections
- (&s->output_section_statement.children);
- break;
- case lang_wild_statement_enum:
- xtensa_strip_inconsistent_linkonce_sections
- (&s->wild_statement.children);
- break;
- case lang_group_statement_enum:
- xtensa_strip_inconsistent_linkonce_sections
- (&s->group_statement.children);
- break;
- case lang_data_statement_enum:
- case lang_reloc_statement_enum:
- case lang_object_symbols_statement_enum:
- case lang_output_statement_enum:
- case lang_target_statement_enum:
- case lang_input_statement_enum:
- case lang_assignment_statement_enum:
- case lang_padding_statement_enum:
- case lang_address_statement_enum:
- case lang_fill_statement_enum:
- break;
- default:
- FAIL ();
- break;
- }
- s_p = &(*s_p)->header.next;
- }
- /* Reset the tail of the list, in case the last entry was removed. */
- if (s_p != slist->tail)
- slist->tail = s_p;
- }
- static void
- xtensa_wild_group_interleave_callback (lang_statement_union_type *statement)
- {
- lang_wild_statement_type *w;
- reloc_deps_graph *deps;
- if (statement->header.type == lang_wild_statement_enum)
- {
- #if EXTRA_VALIDATION
- size_t old_child_count;
- size_t new_child_count;
- #endif
- bfd_boolean no_reorder;
- w = &statement->wild_statement;
- no_reorder = FALSE;
- /* If it has 0 or 1 section bound, then do not reorder. */
- if (w->children.head == NULL
- || (w->children.head->header.type == lang_input_section_enum
- && w->children.head->header.next == NULL))
- no_reorder = TRUE;
- if (w->filenames_sorted)
- no_reorder = TRUE;
- /* Check for sorting in a section list wildcard spec as well. */
- if (!no_reorder)
- {
- struct wildcard_list *l;
- for (l = w->section_list; l != NULL; l = l->next)
- {
- if (l->spec.sorted == TRUE)
- {
- no_reorder = TRUE;
- break;
- }
- }
- }
- /* Special case until the NOREORDER linker directive is supported:
- *(.init) output sections and *(.fini) specs may NOT be reordered. */
- /* Check for sorting in a section list wildcard spec as well. */
- if (!no_reorder)
- {
- struct wildcard_list *l;
- for (l = w->section_list; l != NULL; l = l->next)
- {
- if (l->spec.name
- && ((strcmp (".init", l->spec.name) == 0)
- || (strcmp (".fini", l->spec.name) == 0)))
- {
- no_reorder = TRUE;
- break;
- }
- }
- }
- #if EXTRA_VALIDATION
- old_child_count = ld_count_children (statement);
- #endif
- /* It is now officially a target. Build the graph of source
- section -> target section (kept as a list of edges). */
- deps = ld_build_required_section_dependence (statement);
- /* If this wildcard does not reorder.... */
- if (!no_reorder && deps->count != 0)
- {
- /* First check for reverse dependences. Fix if possible. */
- xtensa_layout_wild (deps, w);
- xtensa_move_dependencies_to_front (deps, w);
- #if EXTRA_VALIDATION
- new_child_count = ld_count_children (statement);
- ASSERT (new_child_count == old_child_count);
- #endif
- xtensa_colocate_literals (deps, statement);
- #if EXTRA_VALIDATION
- new_child_count = ld_count_children (statement);
- ASSERT (new_child_count == old_child_count);
- #endif
- }
- /* Clean up. */
- free_reloc_deps_graph (deps);
- }
- }
- static void
- xtensa_wild_group_interleave (lang_statement_union_type *s)
- {
- lang_for_each_statement_worker (xtensa_wild_group_interleave_callback, s);
- }
- static void
- xtensa_layout_wild (const reloc_deps_graph *deps, lang_wild_statement_type *w)
- {
- /* If it does not fit initially, we need to do this step. Move all
- of the wild literal sections to a new list, then move each of
- them back in just before the first section they depend on. */
- lang_statement_union_type **s_p;
- #if EXTRA_VALIDATION
- size_t old_count, new_count;
- size_t ct1, ct2;
- #endif
- lang_wild_statement_type literal_wild;
- literal_wild.header.next = NULL;
- literal_wild.header.type = lang_wild_statement_enum;
- literal_wild.filename = NULL;
- literal_wild.filenames_sorted = FALSE;
- literal_wild.section_list = NULL;
- literal_wild.keep_sections = FALSE;
- literal_wild.children.head = NULL;
- literal_wild.children.tail = &literal_wild.children.head;
- #if EXTRA_VALIDATION
- old_count = ld_count_children ((lang_statement_union_type*) w);
- #endif
- s_p = &w->children.head;
- while (*s_p != NULL)
- {
- lang_statement_union_type *l = *s_p;
- if (l->header.type == lang_input_section_enum)
- {
- if (section_is_target (deps, l)
- && ! section_is_source (deps, l))
- {
- /* Detach. */
- *s_p = l->header.next;
- if (*s_p == NULL)
- w->children.tail = s_p;
- l->header.next = NULL;
- /* Append. */
- *literal_wild.children.tail = l;
- literal_wild.children.tail = &l->header.next;
- continue;
- }
- }
- s_p = &(*s_p)->header.next;
- }
- #if EXTRA_VALIDATION
- ct1 = ld_count_children ((lang_statement_union_type*) w);
- ct2 = ld_count_children ((lang_statement_union_type*) &literal_wild);
- ASSERT (old_count == (ct1 + ct2));
- #endif
- /* Now place them back in front of their dependent sections. */
- while (literal_wild.children.head != NULL)
- {
- lang_statement_union_type *lit = literal_wild.children.head;
- bfd_boolean placed = FALSE;
- #if EXTRA_VALIDATION
- ASSERT (ct2 > 0);
- ct2--;
- #endif
- /* Detach. */
- literal_wild.children.head = lit->header.next;
- if (literal_wild.children.head == NULL)
- literal_wild.children.tail = &literal_wild.children.head;
- lit->header.next = NULL;
- /* Find a spot to place it. */
- for (s_p = &w->children.head; *s_p != NULL; s_p = &(*s_p)->header.next)
- {
- lang_statement_union_type *src = *s_p;
- if (deps_has_edge (deps, src, lit))
- {
- /* Place it here. */
- lit->header.next = *s_p;
- *s_p = lit;
- placed = TRUE;
- break;
- }
- }
- if (!placed)
- {
- /* Put it at the end. */
- *w->children.tail = lit;
- w->children.tail = &lit->header.next;
- }
- }
- #if EXTRA_VALIDATION
- new_count = ld_count_children ((lang_statement_union_type*) w);
- ASSERT (new_count == old_count);
- #endif
- }
- static void
- xtensa_colocate_output_literals_callback (lang_statement_union_type *statement)
- {
- reloc_deps_graph *deps;
- if (statement->header.type == lang_output_section_statement_enum)
- {
- /* Now, we walk over the contours of the output section statement.
- First we build the literal section dependences as before.
- At the first uniquely_literal section, we mark it as a good
- spot to place other literals. Continue walking (and counting
- sizes) until we find the next literal section. If this
- section can be moved to the first one, then we move it. If
- we every find a modification of ".", start over. If we find
- a labeling of the current location, start over. Finally, at
- the end, if we require page alignment, add page alignments. */
- #if EXTRA_VALIDATION
- size_t old_child_count;
- size_t new_child_count;
- #endif
- bfd_boolean no_reorder = FALSE;
- #if EXTRA_VALIDATION
- old_child_count = ld_count_children (statement);
- #endif
- /* It is now officially a target. Build the graph of source
- section -> target section (kept as a list of edges). */
- deps = ld_build_required_section_dependence (statement);
- /* If this wildcard does not reorder.... */
- if (!no_reorder)
- {
- /* First check for reverse dependences. Fix if possible. */
- xtensa_colocate_literals (deps, statement);
- #if EXTRA_VALIDATION
- new_child_count = ld_count_children (statement);
- ASSERT (new_child_count == old_child_count);
- #endif
- }
- /* Insert align/offset assignment statement. */
- if (xtensa_use_literal_pages)
- {
- ld_xtensa_insert_page_offsets (0, statement, deps,
- xtensa_use_literal_pages);
- lang_for_each_statement_worker (xtensa_ldlang_clear_addresses,
- statement);
- }
- /* Clean up. */
- free_reloc_deps_graph (deps);
- }
- }
- static void
- xtensa_colocate_output_literals (lang_statement_union_type *s)
- {
- lang_for_each_statement_worker (xtensa_colocate_output_literals_callback, s);
- }
- static void
- xtensa_ldlang_clear_addresses (lang_statement_union_type *statement)
- {
- switch (statement->header.type)
- {
- case lang_input_section_enum:
- {
- asection *bfd_section = statement->input_section.section;
- bfd_section->output_offset = 0;
- }
- break;
- default:
- break;
- }
- }
- static bfd_vma
- ld_assign_relative_paged_dot (bfd_vma dot,
- lang_statement_union_type *s,
- const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
- bfd_boolean lit_align)
- {
- /* Walk through all of the input statements in this wild statement
- assign dot to all of them. */
- xtensa_ld_iter_stack *stack = NULL;
- xtensa_ld_iter_stack **stack_p = &stack;
- bfd_boolean first_section = FALSE;
- bfd_boolean in_literals = FALSE;
- for (iter_stack_create (stack_p, s);
- !iter_stack_empty (stack_p);
- iter_stack_next (stack_p))
- {
- lang_statement_union_type *l = iter_stack_current (stack_p);
- switch (l->header.type)
- {
- case lang_input_section_enum:
- {
- asection *section = l->input_section.section;
- size_t align_pow = section->alignment_power;
- bfd_boolean do_xtensa_alignment = FALSE;
- if (lit_align)
- {
- bfd_boolean sec_is_target = section_is_target (deps, l);
- bfd_boolean sec_is_source = section_is_source (deps, l);
- if (section->size != 0
- && (first_section
- || (in_literals && !sec_is_target)
- || (!in_literals && sec_is_target)))
- {
- do_xtensa_alignment = TRUE;
- }
- first_section = FALSE;
- if (section->size != 0)
- in_literals = (sec_is_target && !sec_is_source);
- }
- if (do_xtensa_alignment && xtensa_page_power != 0)
- dot += (1 << xtensa_page_power);
- dot = align_power (dot, align_pow);
- section->output_offset = dot;
- dot += section->size;
- }
- break;
- case lang_fill_statement_enum:
- dot += l->fill_statement.size;
- break;
- case lang_padding_statement_enum:
- dot += l->padding_statement.size;
- break;
- default:
- break;
- }
- }
- return dot;
- }
- static bfd_boolean
- ld_local_file_relocations_fit (lang_statement_union_type *statement,
- const reloc_deps_graph *deps ATTRIBUTE_UNUSED)
- {
- /* Walk over all of the dependencies that we identified and make
- sure that IF the source and target are here (addr != 0):
- 1) target addr < source addr
- 2) (roundup(source + source_size, 4) - rounddown(target, 4))
- < (256K - (1 << bad align))
- Need a worst-case proof.... */
- xtensa_ld_iter_stack *stack = NULL;
- xtensa_ld_iter_stack **stack_p = &stack;
- size_t max_align_power = 0;
- size_t align_penalty = 256;
- reloc_deps_e *e;
- size_t i;
- /* Find the worst-case alignment requirement for this set of statements. */
- for (iter_stack_create (stack_p, statement);
- !iter_stack_empty (stack_p);
- iter_stack_next (stack_p))
- {
- lang_statement_union_type *l = iter_stack_current (stack_p);
- if (l->header.type == lang_input_section_enum)
- {
- lang_input_section_type *input = &l->input_section;
- asection *section = input->section;
- if (section->alignment_power > max_align_power)
- max_align_power = section->alignment_power;
- }
- }
- /* Now check that everything fits. */
- for (i = 0; i < deps->count; i++)
- {
- asection *sec = deps->sections[i];
- const reloc_deps_section *deps_section =
- xtensa_get_section_deps (deps, sec);
- if (deps_section)
- {
- /* We choose to walk through the successors. */
- for (e = deps_section->succs; e != NULL; e = e->next)
- {
- if (e->src != e->tgt
- && e->src->output_section == e->tgt->output_section
- && e->src->output_offset != 0
- && e->tgt->output_offset != 0)
- {
- bfd_vma l32r_addr =
- align_power (e->src->output_offset + e->src->size, 2);
- bfd_vma target_addr = e->tgt->output_offset & ~3;
- if (l32r_addr < target_addr)
- {
- fflush (stdout);
- fprintf (stderr, "Warning: "
- "l32r target section before l32r\n");
- fflush (stderr);
- return FALSE;
- }
- if (l32r_addr - target_addr > 256 * 1024 - align_penalty)
- return FALSE;
- }
- }
- }
- }
- return TRUE;
- }
- static bfd_vma
- ld_xtensa_insert_page_offsets (bfd_vma dot,
- lang_statement_union_type *s,
- reloc_deps_graph *deps,
- bfd_boolean lit_align)
- {
- xtensa_ld_iter_stack *stack = NULL;
- xtensa_ld_iter_stack **stack_p = &stack;
- bfd_boolean first_section = FALSE;
- bfd_boolean in_literals = FALSE;
- if (!lit_align)
- return FALSE;
- for (iter_stack_create (stack_p, s);
- !iter_stack_empty (stack_p);
- iter_stack_next (stack_p))
- {
- lang_statement_union_type *l = iter_stack_current (stack_p);
- switch (l->header.type)
- {
- case lang_input_section_enum:
- {
- asection *section = l->input_section.section;
- bfd_boolean do_xtensa_alignment = FALSE;
- if (lit_align)
- {
- if (section->size != 0
- && (first_section
- || (in_literals && !section_is_target (deps, l))
- || (!in_literals && section_is_target (deps, l))))
- {
- do_xtensa_alignment = TRUE;
- }
- first_section = FALSE;
- if (section->size != 0)
- {
- in_literals = (section_is_target (deps, l)
- && !section_is_source (deps, l));
- }
- }
- if (do_xtensa_alignment && xtensa_page_power != 0)
- {
- /* Create an expression that increments the current address,
- i.e., "dot", by (1 << xtensa_align_power). */
- etree_type *name_op = exp_nameop (NAME, ".");
- etree_type *addend_op = exp_intop (1 << xtensa_page_power);
- etree_type *add_op = exp_binop ('+', name_op, addend_op);
- etree_type *assign_op = exp_assign (".", add_op, FALSE);
- lang_assignment_statement_type *assign_stmt;
- lang_statement_union_type *assign_union;
- lang_statement_list_type tmplist;
- /* There is hidden state in "lang_add_assignment". It
- appends the new assignment statement to the stat_ptr
- list. Thus, we swap it before and after the call. */
- lang_list_init (&tmplist);
- push_stat_ptr (&tmplist);
- /* Warning: side effect; statement appended to stat_ptr. */
- assign_stmt = lang_add_assignment (assign_op);
- assign_union = (lang_statement_union_type *) assign_stmt;
- pop_stat_ptr ();
- assign_union->header.next = l;
- *(*stack_p)->iterloc.loc = assign_union;
- iter_stack_next (stack_p);
- }
- }
- break;
- default:
- break;
- }
- }
- return dot;
- }
- EOF
- # Define some shell vars to insert bits of code into the standard ELF
- # parse_args and list_options functions.
- #
- PARSE_AND_LIST_PROLOGUE='
- #define OPTION_OPT_SIZEOPT (300)
- #define OPTION_LITERAL_MOVEMENT (OPTION_OPT_SIZEOPT + 1)
- #define OPTION_NO_LITERAL_MOVEMENT (OPTION_LITERAL_MOVEMENT + 1)
- extern int elf32xtensa_size_opt;
- extern int elf32xtensa_no_literal_movement;
- '
- PARSE_AND_LIST_LONGOPTS='
- { "size-opt", no_argument, NULL, OPTION_OPT_SIZEOPT},
- { "literal-movement", no_argument, NULL, OPTION_LITERAL_MOVEMENT},
- { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT},
- '
- PARSE_AND_LIST_OPTIONS='
- fprintf (file, _("\
- --size-opt When relaxing longcalls, prefer size\n\
- optimization over branch target alignment\n"));
- '
- PARSE_AND_LIST_ARGS_CASES='
- case OPTION_OPT_SIZEOPT:
- elf32xtensa_size_opt = 1;
- break;
- case OPTION_LITERAL_MOVEMENT:
- elf32xtensa_no_literal_movement = 0;
- break;
- case OPTION_NO_LITERAL_MOVEMENT:
- elf32xtensa_no_literal_movement = 1;
- break;
- '
- # Replace some of the standard ELF functions with our own versions.
- #
- LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse
- LDEMUL_AFTER_OPEN=elf_xtensa_after_open
- LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target
- LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation
|