123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662 |
- /* This module handles expression trees.
- Copyright (C) 1991-2015 Free Software Foundation, Inc.
- Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
- 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 module is in charge of working out the contents of expressions.
- It has to keep track of the relative/absness of a symbol etc. This
- is done by keeping all values in a struct (an etree_value_type)
- which contains a value, a section to which it is relative and a
- valid bit. */
- #include "sysdep.h"
- #include "bfd.h"
- #include "bfdlink.h"
- #include "ld.h"
- #include "ldmain.h"
- #include "ldmisc.h"
- #include "ldexp.h"
- #include "ldlex.h"
- #include <ldgram.h>
- #include "ldlang.h"
- #include "libiberty.h"
- #include "safe-ctype.h"
- static void exp_fold_tree_1 (etree_type *);
- static bfd_vma align_n (bfd_vma, bfd_vma);
- segment_type *segments;
- struct ldexp_control expld;
- /* This structure records symbols for which we need to keep track of
- definedness for use in the DEFINED () test. It is also used in
- making absolute symbols section relative late in the link. */
- struct definedness_hash_entry
- {
- struct bfd_hash_entry root;
- /* If this symbol was assigned from "dot" outside of an output
- section statement, the section we'd like it relative to. */
- asection *final_sec;
- /* Symbol was defined by an object file. */
- unsigned int by_object : 1;
- /* Symbols was defined by a script. */
- unsigned int by_script : 1;
- /* Low bit of iteration count. Symbols with matching iteration have
- been defined in this pass over the script. */
- unsigned int iteration : 1;
- };
- static struct bfd_hash_table definedness_table;
- /* Print the string representation of the given token. Surround it
- with spaces if INFIX_P is TRUE. */
- static void
- exp_print_token (token_code_type code, int infix_p)
- {
- static const struct
- {
- token_code_type code;
- const char * name;
- }
- table[] =
- {
- { INT, "int" },
- { NAME, "NAME" },
- { PLUSEQ, "+=" },
- { MINUSEQ, "-=" },
- { MULTEQ, "*=" },
- { DIVEQ, "/=" },
- { LSHIFTEQ, "<<=" },
- { RSHIFTEQ, ">>=" },
- { ANDEQ, "&=" },
- { OREQ, "|=" },
- { OROR, "||" },
- { ANDAND, "&&" },
- { EQ, "==" },
- { NE, "!=" },
- { LE, "<=" },
- { GE, ">=" },
- { LSHIFT, "<<" },
- { RSHIFT, ">>" },
- { LOG2CEIL, "LOG2CEIL" },
- { ALIGN_K, "ALIGN" },
- { BLOCK, "BLOCK" },
- { QUAD, "QUAD" },
- { SQUAD, "SQUAD" },
- { LONG, "LONG" },
- { SHORT, "SHORT" },
- { BYTE, "BYTE" },
- { SECTIONS, "SECTIONS" },
- { SIZEOF_HEADERS, "SIZEOF_HEADERS" },
- { MEMORY, "MEMORY" },
- { DEFINED, "DEFINED" },
- { TARGET_K, "TARGET" },
- { SEARCH_DIR, "SEARCH_DIR" },
- { MAP, "MAP" },
- { ENTRY, "ENTRY" },
- { NEXT, "NEXT" },
- { ALIGNOF, "ALIGNOF" },
- { SIZEOF, "SIZEOF" },
- { ADDR, "ADDR" },
- { LOADADDR, "LOADADDR" },
- { CONSTANT, "CONSTANT" },
- { ABSOLUTE, "ABSOLUTE" },
- { MAX_K, "MAX" },
- { MIN_K, "MIN" },
- { ASSERT_K, "ASSERT" },
- { REL, "relocatable" },
- { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
- { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
- { DATA_SEGMENT_END, "DATA_SEGMENT_END" },
- { ORIGIN, "ORIGIN" },
- { LENGTH, "LENGTH" },
- { SEGMENT_START, "SEGMENT_START" }
- };
- unsigned int idx;
- for (idx = 0; idx < ARRAY_SIZE (table); idx++)
- if (table[idx].code == code)
- break;
- if (infix_p)
- fputc (' ', config.map_file);
- if (idx < ARRAY_SIZE (table))
- fputs (table[idx].name, config.map_file);
- else if (code < 127)
- fputc (code, config.map_file);
- else
- fprintf (config.map_file, "<code %d>", code);
- if (infix_p)
- fputc (' ', config.map_file);
- }
- static void
- make_log2ceil (void)
- {
- bfd_vma value = expld.result.value;
- bfd_vma result = -1;
- bfd_boolean round_up = FALSE;
- do
- {
- result++;
- /* If more than one bit is set in the value we will need to round up. */
- if ((value > 1) && (value & 1))
- round_up = TRUE;
- }
- while (value >>= 1);
- if (round_up)
- result += 1;
- expld.result.section = NULL;
- expld.result.value = result;
- }
- static void
- make_abs (void)
- {
- if (expld.result.section != NULL)
- expld.result.value += expld.result.section->vma;
- expld.result.section = bfd_abs_section_ptr;
- expld.rel_from_abs = FALSE;
- }
- static void
- new_abs (bfd_vma value)
- {
- expld.result.valid_p = TRUE;
- expld.result.section = bfd_abs_section_ptr;
- expld.result.value = value;
- expld.result.str = NULL;
- }
- etree_type *
- exp_intop (bfd_vma value)
- {
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
- new_e->type.node_code = INT;
- new_e->type.filename = ldlex_filename ();
- new_e->type.lineno = lineno;
- new_e->value.value = value;
- new_e->value.str = NULL;
- new_e->type.node_class = etree_value;
- return new_e;
- }
- etree_type *
- exp_bigintop (bfd_vma value, char *str)
- {
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
- new_e->type.node_code = INT;
- new_e->type.filename = ldlex_filename ();
- new_e->type.lineno = lineno;
- new_e->value.value = value;
- new_e->value.str = str;
- new_e->type.node_class = etree_value;
- return new_e;
- }
- /* Build an expression representing an unnamed relocatable value. */
- etree_type *
- exp_relop (asection *section, bfd_vma value)
- {
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->rel));
- new_e->type.node_code = REL;
- new_e->type.filename = ldlex_filename ();
- new_e->type.lineno = lineno;
- new_e->type.node_class = etree_rel;
- new_e->rel.section = section;
- new_e->rel.value = value;
- return new_e;
- }
- static void
- new_number (bfd_vma value)
- {
- expld.result.valid_p = TRUE;
- expld.result.value = value;
- expld.result.str = NULL;
- expld.result.section = NULL;
- }
- static void
- new_rel (bfd_vma value, asection *section)
- {
- expld.result.valid_p = TRUE;
- expld.result.value = value;
- expld.result.str = NULL;
- expld.result.section = section;
- }
- static void
- new_rel_from_abs (bfd_vma value)
- {
- asection *s = expld.section;
- expld.rel_from_abs = TRUE;
- expld.result.valid_p = TRUE;
- expld.result.value = value - s->vma;
- expld.result.str = NULL;
- expld.result.section = s;
- }
- /* New-function for the definedness hash table. */
- static struct bfd_hash_entry *
- definedness_newfunc (struct bfd_hash_entry *entry,
- struct bfd_hash_table *table ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED)
- {
- struct definedness_hash_entry *ret = (struct definedness_hash_entry *) entry;
- if (ret == NULL)
- ret = (struct definedness_hash_entry *)
- bfd_hash_allocate (table, sizeof (struct definedness_hash_entry));
- if (ret == NULL)
- einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
- ret->by_object = 0;
- ret->by_script = 0;
- ret->iteration = 0;
- return &ret->root;
- }
- /* Called during processing of linker script script expressions.
- For symbols assigned in a linker script, return a struct describing
- where the symbol is defined relative to the current expression,
- otherwise return NULL. */
- static struct definedness_hash_entry *
- symbol_defined (const char *name)
- {
- return ((struct definedness_hash_entry *)
- bfd_hash_lookup (&definedness_table, name, FALSE, FALSE));
- }
- /* Update the definedness state of NAME. Return FALSE if script symbol
- is multiply defining a strong symbol in an object. */
- static bfd_boolean
- update_definedness (const char *name, struct bfd_link_hash_entry *h)
- {
- bfd_boolean ret;
- struct definedness_hash_entry *defentry
- = (struct definedness_hash_entry *)
- bfd_hash_lookup (&definedness_table, name, TRUE, FALSE);
- if (defentry == NULL)
- einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
- /* If the symbol was already defined, and not by a script, then it
- must be defined by an object file or by the linker target code. */
- ret = TRUE;
- if (!defentry->by_script
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak
- || h->type == bfd_link_hash_common))
- {
- defentry->by_object = 1;
- if (h->type == bfd_link_hash_defined
- && h->u.def.section->output_section != NULL
- && !h->linker_def)
- ret = FALSE;
- }
- defentry->by_script = 1;
- defentry->iteration = lang_statement_iteration;
- defentry->final_sec = bfd_abs_section_ptr;
- if (expld.phase == lang_final_phase_enum
- && expld.rel_from_abs
- && expld.result.section == bfd_abs_section_ptr)
- defentry->final_sec = section_for_dot ();
- return ret;
- }
- static void
- fold_unary (etree_type *tree)
- {
- exp_fold_tree_1 (tree->unary.child);
- if (expld.result.valid_p)
- {
- switch (tree->type.node_code)
- {
- case ALIGN_K:
- if (expld.phase != lang_first_phase_enum)
- new_rel_from_abs (align_n (expld.dot, expld.result.value));
- else
- expld.result.valid_p = FALSE;
- break;
- case ABSOLUTE:
- make_abs ();
- break;
- case LOG2CEIL:
- make_log2ceil ();
- break;
- case '~':
- expld.result.value = ~expld.result.value;
- break;
- case '!':
- expld.result.value = !expld.result.value;
- break;
- case '-':
- expld.result.value = -expld.result.value;
- break;
- case NEXT:
- /* Return next place aligned to value. */
- if (expld.phase != lang_first_phase_enum)
- {
- make_abs ();
- expld.result.value = align_n (expld.dot, expld.result.value);
- }
- else
- expld.result.valid_p = FALSE;
- break;
- case DATA_SEGMENT_END:
- if (expld.phase == lang_first_phase_enum
- || expld.section != bfd_abs_section_ptr)
- {
- expld.result.valid_p = FALSE;
- }
- else if (expld.dataseg.phase == exp_dataseg_align_seen
- || expld.dataseg.phase == exp_dataseg_relro_seen)
- {
- expld.dataseg.phase = exp_dataseg_end_seen;
- expld.dataseg.end = expld.result.value;
- }
- else if (expld.dataseg.phase == exp_dataseg_done
- || expld.dataseg.phase == exp_dataseg_adjust
- || expld.dataseg.phase == exp_dataseg_relro_adjust)
- {
- /* OK. */
- }
- else
- expld.result.valid_p = FALSE;
- break;
- default:
- FAIL ();
- break;
- }
- }
- }
- static void
- fold_binary (etree_type *tree)
- {
- etree_value_type lhs;
- exp_fold_tree_1 (tree->binary.lhs);
- /* The SEGMENT_START operator is special because its first
- operand is a string, not the name of a symbol. Note that the
- operands have been swapped, so binary.lhs is second (default)
- operand, binary.rhs is first operand. */
- if (expld.result.valid_p && tree->type.node_code == SEGMENT_START)
- {
- const char *segment_name;
- segment_type *seg;
- /* Check to see if the user has overridden the default
- value. */
- segment_name = tree->binary.rhs->name.name;
- for (seg = segments; seg; seg = seg->next)
- if (strcmp (seg->name, segment_name) == 0)
- {
- if (!seg->used
- && config.magic_demand_paged
- && (seg->value % config.maxpagesize) != 0)
- einfo (_("%P: warning: address of `%s' isn't multiple of maximum page size\n"),
- segment_name);
- seg->used = TRUE;
- new_rel_from_abs (seg->value);
- break;
- }
- return;
- }
- lhs = expld.result;
- exp_fold_tree_1 (tree->binary.rhs);
- expld.result.valid_p &= lhs.valid_p;
- if (expld.result.valid_p)
- {
- if (lhs.section != expld.result.section)
- {
- /* If the values are from different sections, and neither is
- just a number, make both the source arguments absolute. */
- if (expld.result.section != NULL
- && lhs.section != NULL)
- {
- make_abs ();
- lhs.value += lhs.section->vma;
- lhs.section = bfd_abs_section_ptr;
- }
- /* If the rhs is just a number, keep the lhs section. */
- else if (expld.result.section == NULL)
- {
- expld.result.section = lhs.section;
- /* Make this NULL so that we know one of the operands
- was just a number, for later tests. */
- lhs.section = NULL;
- }
- }
- /* At this point we know that both operands have the same
- section, or at least one of them is a plain number. */
- switch (tree->type.node_code)
- {
- /* Arithmetic operators, bitwise AND, bitwise OR and XOR
- keep the section of one of their operands only when the
- other operand is a plain number. Losing the section when
- operating on two symbols, ie. a result of a plain number,
- is required for subtraction and XOR. It's justifiable
- for the other operations on the grounds that adding,
- multiplying etc. two section relative values does not
- really make sense unless they are just treated as
- numbers.
- The same argument could be made for many expressions
- involving one symbol and a number. For example,
- "1 << x" and "100 / x" probably should not be given the
- section of x. The trouble is that if we fuss about such
- things the rules become complex and it is onerous to
- document ld expression evaluation. */
- #define BOP(x, y) \
- case x: \
- expld.result.value = lhs.value y expld.result.value; \
- if (expld.result.section == lhs.section) \
- expld.result.section = NULL; \
- break;
- /* Comparison operators, logical AND, and logical OR always
- return a plain number. */
- #define BOPN(x, y) \
- case x: \
- expld.result.value = lhs.value y expld.result.value; \
- expld.result.section = NULL; \
- break;
- BOP ('+', +);
- BOP ('*', *);
- BOP ('-', -);
- BOP (LSHIFT, <<);
- BOP (RSHIFT, >>);
- BOP ('&', &);
- BOP ('^', ^);
- BOP ('|', |);
- BOPN (EQ, ==);
- BOPN (NE, !=);
- BOPN ('<', <);
- BOPN ('>', >);
- BOPN (LE, <=);
- BOPN (GE, >=);
- BOPN (ANDAND, &&);
- BOPN (OROR, ||);
- case '%':
- if (expld.result.value != 0)
- expld.result.value = ((bfd_signed_vma) lhs.value
- % (bfd_signed_vma) expld.result.value);
- else if (expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S %% by zero\n"), tree->binary.rhs);
- if (expld.result.section == lhs.section)
- expld.result.section = NULL;
- break;
- case '/':
- if (expld.result.value != 0)
- expld.result.value = ((bfd_signed_vma) lhs.value
- / (bfd_signed_vma) expld.result.value);
- else if (expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S / by zero\n"), tree->binary.rhs);
- if (expld.result.section == lhs.section)
- expld.result.section = NULL;
- break;
- case MAX_K:
- if (lhs.value > expld.result.value)
- expld.result.value = lhs.value;
- break;
- case MIN_K:
- if (lhs.value < expld.result.value)
- expld.result.value = lhs.value;
- break;
- case ALIGN_K:
- expld.result.value = align_n (lhs.value, expld.result.value);
- break;
- case DATA_SEGMENT_ALIGN:
- expld.dataseg.relro = exp_dataseg_relro_start;
- if (expld.phase == lang_first_phase_enum
- || expld.section != bfd_abs_section_ptr)
- expld.result.valid_p = FALSE;
- else
- {
- bfd_vma maxpage = lhs.value;
- bfd_vma commonpage = expld.result.value;
- expld.result.value = align_n (expld.dot, maxpage);
- if (expld.dataseg.phase == exp_dataseg_relro_adjust)
- expld.result.value = expld.dataseg.base;
- else if (expld.dataseg.phase == exp_dataseg_adjust)
- {
- if (commonpage < maxpage)
- expld.result.value += ((expld.dot + commonpage - 1)
- & (maxpage - commonpage));
- }
- else
- {
- expld.result.value += expld.dot & (maxpage - 1);
- if (expld.dataseg.phase == exp_dataseg_done)
- {
- /* OK. */
- }
- else if (expld.dataseg.phase == exp_dataseg_none)
- {
- expld.dataseg.phase = exp_dataseg_align_seen;
- expld.dataseg.base = expld.result.value;
- expld.dataseg.pagesize = commonpage;
- expld.dataseg.maxpagesize = maxpage;
- expld.dataseg.relro_end = 0;
- }
- else
- expld.result.valid_p = FALSE;
- }
- }
- break;
- case DATA_SEGMENT_RELRO_END:
- /* Operands swapped! DATA_SEGMENT_RELRO_END(offset,exp)
- has offset in expld.result and exp in lhs. */
- expld.dataseg.relro = exp_dataseg_relro_end;
- expld.dataseg.relro_offset = expld.result.value;
- if (expld.phase == lang_first_phase_enum
- || expld.section != bfd_abs_section_ptr)
- expld.result.valid_p = FALSE;
- else if (expld.dataseg.phase == exp_dataseg_align_seen
- || expld.dataseg.phase == exp_dataseg_adjust
- || expld.dataseg.phase == exp_dataseg_relro_adjust
- || expld.dataseg.phase == exp_dataseg_done)
- {
- if (expld.dataseg.phase == exp_dataseg_align_seen
- || expld.dataseg.phase == exp_dataseg_relro_adjust)
- expld.dataseg.relro_end = lhs.value + expld.result.value;
- if (expld.dataseg.phase == exp_dataseg_relro_adjust
- && (expld.dataseg.relro_end
- & (expld.dataseg.pagesize - 1)))
- {
- expld.dataseg.relro_end += expld.dataseg.pagesize - 1;
- expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1);
- expld.result.value = (expld.dataseg.relro_end
- - expld.result.value);
- }
- else
- expld.result.value = lhs.value;
- if (expld.dataseg.phase == exp_dataseg_align_seen)
- expld.dataseg.phase = exp_dataseg_relro_seen;
- }
- else
- expld.result.valid_p = FALSE;
- break;
- default:
- FAIL ();
- }
- }
- }
- static void
- fold_trinary (etree_type *tree)
- {
- exp_fold_tree_1 (tree->trinary.cond);
- if (expld.result.valid_p)
- exp_fold_tree_1 (expld.result.value
- ? tree->trinary.lhs
- : tree->trinary.rhs);
- }
- static void
- fold_name (etree_type *tree)
- {
- memset (&expld.result, 0, sizeof (expld.result));
- switch (tree->type.node_code)
- {
- case SIZEOF_HEADERS:
- if (expld.phase != lang_first_phase_enum)
- {
- bfd_vma hdr_size = 0;
- /* Don't find the real header size if only marking sections;
- The bfd function may cache incorrect data. */
- if (expld.phase != lang_mark_phase_enum)
- hdr_size = bfd_sizeof_headers (link_info.output_bfd, &link_info);
- new_number (hdr_size);
- }
- break;
- case DEFINED:
- if (expld.phase != lang_first_phase_enum)
- {
- struct bfd_link_hash_entry *h;
- struct definedness_hash_entry *def;
- h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
- &link_info,
- tree->name.name,
- FALSE, FALSE, TRUE);
- new_number (h != NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak
- || h->type == bfd_link_hash_common)
- && ((def = symbol_defined (tree->name.name)) == NULL
- || def->by_object
- || def->iteration == (lang_statement_iteration & 1)));
- }
- break;
- case NAME:
- if (expld.assign_name != NULL
- && strcmp (expld.assign_name, tree->name.name) == 0)
- {
- /* Self-assignment is only allowed for absolute symbols
- defined in a linker script. */
- struct bfd_link_hash_entry *h;
- struct definedness_hash_entry *def;
- h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
- &link_info,
- tree->name.name,
- FALSE, FALSE, TRUE);
- if (!(h != NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- && h->u.def.section == bfd_abs_section_ptr
- && (def = symbol_defined (tree->name.name)) != NULL
- && def->iteration == (lang_statement_iteration & 1)))
- expld.assign_name = NULL;
- }
- if (expld.phase == lang_first_phase_enum)
- ;
- else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
- new_rel_from_abs (expld.dot);
- else
- {
- struct bfd_link_hash_entry *h;
- h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
- &link_info,
- tree->name.name,
- TRUE, FALSE, TRUE);
- if (!h)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
- else if (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- {
- asection *output_section;
- output_section = h->u.def.section->output_section;
- if (output_section == NULL)
- {
- if (expld.phase == lang_mark_phase_enum)
- new_rel (h->u.def.value, h->u.def.section);
- else
- einfo (_("%X%S: unresolvable symbol `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
- else if (output_section == bfd_abs_section_ptr
- && (expld.section != bfd_abs_section_ptr
- || config.sane_expr))
- new_number (h->u.def.value + h->u.def.section->output_offset);
- else
- new_rel (h->u.def.value + h->u.def.section->output_offset,
- output_section);
- }
- else if (expld.phase == lang_final_phase_enum
- || (expld.phase != lang_mark_phase_enum
- && expld.assigning_to_dot))
- einfo (_("%F%S: undefined symbol `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- else if (h->type == bfd_link_hash_new)
- {
- h->type = bfd_link_hash_undefined;
- h->u.undef.abfd = NULL;
- if (h->u.undef.next == NULL && h != link_info.hash->undefs_tail)
- bfd_link_add_undef (link_info.hash, h);
- }
- }
- break;
- case ADDR:
- if (expld.phase != lang_first_phase_enum)
- {
- lang_output_section_statement_type *os;
- os = lang_output_section_find (tree->name.name);
- if (os == NULL)
- {
- if (expld.phase == lang_final_phase_enum)
- einfo (_("%F%S: undefined section `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
- else if (os->processed_vma)
- new_rel (0, os->bfd_section);
- }
- break;
- case LOADADDR:
- if (expld.phase != lang_first_phase_enum)
- {
- lang_output_section_statement_type *os;
- os = lang_output_section_find (tree->name.name);
- if (os == NULL)
- {
- if (expld.phase == lang_final_phase_enum)
- einfo (_("%F%S: undefined section `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
- else if (os->processed_lma)
- {
- if (os->load_base == NULL)
- new_abs (os->bfd_section->lma);
- else
- {
- exp_fold_tree_1 (os->load_base);
- if (expld.result.valid_p)
- make_abs ();
- }
- }
- }
- break;
- case SIZEOF:
- case ALIGNOF:
- if (expld.phase != lang_first_phase_enum)
- {
- lang_output_section_statement_type *os;
- os = lang_output_section_find (tree->name.name);
- if (os == NULL)
- {
- if (expld.phase == lang_final_phase_enum)
- einfo (_("%F%S: undefined section `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- new_number (0);
- }
- else if (os->bfd_section != NULL)
- {
- bfd_vma val;
- if (tree->type.node_code == SIZEOF)
- val = (os->bfd_section->size
- / bfd_octets_per_byte (link_info.output_bfd));
- else
- val = (bfd_vma)1 << os->bfd_section->alignment_power;
- new_number (val);
- }
- else
- new_number (0);
- }
- break;
- case LENGTH:
- {
- if (expld.phase != lang_first_phase_enum)
- {
- lang_memory_region_type *mem;
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
- new_number (mem->length);
- else
- einfo (_("%F%S: undefined MEMORY region `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
- }
- break;
- case ORIGIN:
- if (expld.phase != lang_first_phase_enum)
- {
- lang_memory_region_type *mem;
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
- new_rel_from_abs (mem->origin);
- else
- einfo (_("%F%S: undefined MEMORY region `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
- break;
- case CONSTANT:
- if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
- new_number (config.maxpagesize);
- else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
- new_number (config.commonpagesize);
- else
- einfo (_("%F%S: unknown constant `%s' referenced in expression\n"),
- tree, tree->name.name);
- break;
- default:
- FAIL ();
- break;
- }
- }
- /* Return true if TREE is '.'. */
- static bfd_boolean
- is_dot (const etree_type *tree)
- {
- return (tree->type.node_class == etree_name
- && tree->type.node_code == NAME
- && tree->name.name[0] == '.'
- && tree->name.name[1] == 0);
- }
- /* Return true if TREE is a constant equal to VAL. */
- static bfd_boolean
- is_value (const etree_type *tree, bfd_vma val)
- {
- return (tree->type.node_class == etree_value
- && tree->value.value == val);
- }
- /* Return true if TREE is an absolute symbol equal to VAL defined in
- a linker script. */
- static bfd_boolean
- is_sym_value (const etree_type *tree, bfd_vma val)
- {
- struct bfd_link_hash_entry *h;
- struct definedness_hash_entry *def;
- return (tree->type.node_class == etree_name
- && tree->type.node_code == NAME
- && (def = symbol_defined (tree->name.name)) != NULL
- && def->by_script
- && def->iteration == (lang_statement_iteration & 1)
- && (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
- &link_info,
- tree->name.name,
- FALSE, FALSE, TRUE)) != NULL
- && h->type == bfd_link_hash_defined
- && h->u.def.section == bfd_abs_section_ptr
- && h->u.def.value == val);
- }
- /* Return true if TREE is ". != 0". */
- static bfd_boolean
- is_dot_ne_0 (const etree_type *tree)
- {
- return (tree->type.node_class == etree_binary
- && tree->type.node_code == NE
- && is_dot (tree->binary.lhs)
- && is_value (tree->binary.rhs, 0));
- }
- /* Return true if TREE is ". = . + 0" or ". = . + sym" where sym is an
- absolute constant with value 0 defined in a linker script. */
- static bfd_boolean
- is_dot_plus_0 (const etree_type *tree)
- {
- return (tree->type.node_class == etree_binary
- && tree->type.node_code == '+'
- && is_dot (tree->binary.lhs)
- && (is_value (tree->binary.rhs, 0)
- || is_sym_value (tree->binary.rhs, 0)));
- }
- /* Return true if TREE is "ALIGN (. != 0 ? some_expression : 1)". */
- static bfd_boolean
- is_align_conditional (const etree_type *tree)
- {
- if (tree->type.node_class == etree_unary
- && tree->type.node_code == ALIGN_K)
- {
- tree = tree->unary.child;
- return (tree->type.node_class == etree_trinary
- && is_dot_ne_0 (tree->trinary.cond)
- && is_value (tree->trinary.rhs, 1));
- }
- return FALSE;
- }
- /* Subroutine of exp_fold_tree_1 for copying a symbol type. */
- static void
- try_copy_symbol_type (struct bfd_link_hash_entry * h, etree_type *src)
- {
- if (src->type.node_class == etree_name)
- {
- struct bfd_link_hash_entry *hsrc;
- hsrc = bfd_link_hash_lookup (link_info.hash, src->name.name,
- FALSE, FALSE, TRUE);
- if (hsrc)
- bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
- hsrc);
- }
- }
- static void
- exp_fold_tree_1 (etree_type *tree)
- {
- if (tree == NULL)
- {
- memset (&expld.result, 0, sizeof (expld.result));
- return;
- }
- switch (tree->type.node_class)
- {
- case etree_value:
- if (expld.section == bfd_abs_section_ptr
- && !config.sane_expr)
- new_abs (tree->value.value);
- else
- new_number (tree->value.value);
- expld.result.str = tree->value.str;
- break;
- case etree_rel:
- if (expld.phase != lang_first_phase_enum)
- {
- asection *output_section = tree->rel.section->output_section;
- new_rel (tree->rel.value + tree->rel.section->output_offset,
- output_section);
- }
- else
- memset (&expld.result, 0, sizeof (expld.result));
- break;
- case etree_assert:
- exp_fold_tree_1 (tree->assert_s.child);
- if (expld.phase == lang_final_phase_enum && !expld.result.value)
- einfo ("%X%P: %s\n", tree->assert_s.message);
- break;
- case etree_unary:
- fold_unary (tree);
- break;
- case etree_binary:
- fold_binary (tree);
- break;
- case etree_trinary:
- fold_trinary (tree);
- break;
- case etree_assign:
- case etree_provide:
- case etree_provided:
- if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0)
- {
- if (tree->type.node_class != etree_assign)
- einfo (_("%F%S can not PROVIDE assignment to"
- " location counter\n"), tree);
- if (expld.phase != lang_first_phase_enum)
- {
- /* Notify the folder that this is an assignment to dot. */
- expld.assigning_to_dot = TRUE;
- exp_fold_tree_1 (tree->assign.src);
- expld.assigning_to_dot = FALSE;
- /* If we are assigning to dot inside an output section
- arrange to keep the section, except for certain
- expressions that evaluate to zero. We ignore . = 0,
- . = . + 0, and . = ALIGN (. != 0 ? expr : 1).
- We can't ignore all expressions that evaluate to zero
- because an otherwise empty section might have padding
- added by an alignment expression that changes with
- relaxation. Such a section might have zero size
- before relaxation and so be stripped incorrectly. */
- if (expld.phase == lang_mark_phase_enum
- && expld.section != bfd_abs_section_ptr
- && !(expld.result.valid_p
- && expld.result.value == 0
- && (is_value (tree->assign.src, 0)
- || is_sym_value (tree->assign.src, 0)
- || is_dot_plus_0 (tree->assign.src)
- || is_align_conditional (tree->assign.src))))
- expld.section->flags |= SEC_KEEP;
- if (!expld.result.valid_p)
- {
- if (expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S invalid assignment to"
- " location counter\n"), tree);
- }
- else if (expld.dotp == NULL)
- einfo (_("%F%S assignment to location counter"
- " invalid outside of SECTIONS\n"), tree);
- /* After allocation, assignment to dot should not be
- done inside an output section since allocation adds a
- padding statement that effectively duplicates the
- assignment. */
- else if (expld.phase <= lang_allocating_phase_enum
- || expld.section == bfd_abs_section_ptr)
- {
- bfd_vma nextdot;
- nextdot = expld.result.value;
- if (expld.result.section != NULL)
- nextdot += expld.result.section->vma;
- else
- nextdot += expld.section->vma;
- if (nextdot < expld.dot
- && expld.section != bfd_abs_section_ptr)
- einfo (_("%F%S cannot move location counter backwards"
- " (from %V to %V)\n"),
- tree, expld.dot, nextdot);
- else
- {
- expld.dot = nextdot;
- *expld.dotp = nextdot;
- }
- }
- }
- else
- memset (&expld.result, 0, sizeof (expld.result));
- }
- else
- {
- struct bfd_link_hash_entry *h = NULL;
- if (tree->type.node_class == etree_provide)
- {
- h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- FALSE, FALSE, TRUE);
- if (h == NULL
- || !(h->type == bfd_link_hash_new
- || h->type == bfd_link_hash_undefined
- || h->linker_def))
- {
- /* Do nothing. The symbol was never referenced, or
- was defined in some object file. Undefined weak
- symbols stay undefined. */
- break;
- }
- }
- expld.assign_name = tree->assign.dst;
- exp_fold_tree_1 (tree->assign.src);
- /* expld.assign_name remaining equal to tree->assign.dst
- below indicates the evaluation of tree->assign.src did
- not use the value of tree->assign.dst. We don't allow
- self assignment until the final phase for two reasons:
- 1) Expressions are evaluated multiple times. With
- relaxation, the number of times may vary.
- 2) Section relative symbol values cannot be correctly
- converted to absolute values, as is required by many
- expressions, until final section sizing is complete. */
- if ((expld.result.valid_p
- && (expld.phase == lang_final_phase_enum
- || expld.assign_name != NULL))
- || (expld.phase <= lang_mark_phase_enum
- && tree->type.node_class == etree_assign
- && tree->assign.defsym))
- {
- if (h == NULL)
- {
- h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- TRUE, FALSE, TRUE);
- if (h == NULL)
- einfo (_("%P%F:%s: hash creation failed\n"),
- tree->assign.dst);
- }
- if (expld.result.section == NULL)
- expld.result.section = expld.section;
- if (!update_definedness (tree->assign.dst, h) && 0)
- {
- /* Symbol was already defined. For now this error
- is disabled because it causes failures in the ld
- testsuite: ld-elf/var1, ld-scripts/defined5, and
- ld-scripts/pr14962. Some of these no doubt
- reflect scripts used in the wild. */
- (*link_info.callbacks->multiple_definition)
- (&link_info, h, link_info.output_bfd,
- expld.result.section, expld.result.value);
- }
- h->type = bfd_link_hash_defined;
- h->u.def.value = expld.result.value;
- h->u.def.section = expld.result.section;
- h->linker_def = 0;
- if (tree->type.node_class == etree_provide)
- tree->type.node_class = etree_provided;
- /* Copy the symbol type if this is a simple assignment of
- one symbol to another. Also, handle the case of a foldable
- ternary conditional with names on either side. */
- if (tree->assign.src->type.node_class == etree_name)
- try_copy_symbol_type (h, tree->assign.src);
- else if (tree->assign.src->type.node_class == etree_trinary)
- {
- exp_fold_tree_1 (tree->assign.src->trinary.cond);
- if (expld.result.valid_p)
- {
- if (expld.result.value
- && tree->assign.src->trinary.lhs->type.node_class
- == etree_name)
- try_copy_symbol_type (h, tree->assign.src->trinary.lhs);
- if (!expld.result.value
- && tree->assign.src->trinary.rhs->type.node_class
- == etree_name)
- try_copy_symbol_type (h, tree->assign.src->trinary.rhs);
- }
- }
- }
- else if (expld.phase == lang_final_phase_enum)
- {
- h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- FALSE, FALSE, TRUE);
- if (h != NULL
- && h->type == bfd_link_hash_new)
- h->type = bfd_link_hash_undefined;
- }
- expld.assign_name = NULL;
- }
- break;
- case etree_name:
- fold_name (tree);
- break;
- default:
- FAIL ();
- memset (&expld.result, 0, sizeof (expld.result));
- break;
- }
- }
- void
- exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
- {
- expld.rel_from_abs = FALSE;
- expld.dot = *dotp;
- expld.dotp = dotp;
- expld.section = current_section;
- exp_fold_tree_1 (tree);
- }
- void
- exp_fold_tree_no_dot (etree_type *tree)
- {
- expld.rel_from_abs = FALSE;
- expld.dot = 0;
- expld.dotp = NULL;
- expld.section = bfd_abs_section_ptr;
- exp_fold_tree_1 (tree);
- }
- etree_type *
- exp_binop (int code, etree_type *lhs, etree_type *rhs)
- {
- etree_type value, *new_e;
- value.type.node_code = code;
- value.type.filename = lhs->type.filename;
- value.type.lineno = lhs->type.lineno;
- value.binary.lhs = lhs;
- value.binary.rhs = rhs;
- value.type.node_class = etree_binary;
- exp_fold_tree_no_dot (&value);
- if (expld.result.valid_p)
- return exp_intop (expld.result.value);
- new_e = (etree_type *) stat_alloc (sizeof (new_e->binary));
- memcpy (new_e, &value, sizeof (new_e->binary));
- return new_e;
- }
- etree_type *
- exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs)
- {
- etree_type value, *new_e;
- value.type.node_code = code;
- value.type.filename = cond->type.filename;
- value.type.lineno = cond->type.lineno;
- value.trinary.lhs = lhs;
- value.trinary.cond = cond;
- value.trinary.rhs = rhs;
- value.type.node_class = etree_trinary;
- exp_fold_tree_no_dot (&value);
- if (expld.result.valid_p)
- return exp_intop (expld.result.value);
- new_e = (etree_type *) stat_alloc (sizeof (new_e->trinary));
- memcpy (new_e, &value, sizeof (new_e->trinary));
- return new_e;
- }
- etree_type *
- exp_unop (int code, etree_type *child)
- {
- etree_type value, *new_e;
- value.unary.type.node_code = code;
- value.unary.type.filename = child->type.filename;
- value.unary.type.lineno = child->type.lineno;
- value.unary.child = child;
- value.unary.type.node_class = etree_unary;
- exp_fold_tree_no_dot (&value);
- if (expld.result.valid_p)
- return exp_intop (expld.result.value);
- new_e = (etree_type *) stat_alloc (sizeof (new_e->unary));
- memcpy (new_e, &value, sizeof (new_e->unary));
- return new_e;
- }
- etree_type *
- exp_nameop (int code, const char *name)
- {
- etree_type value, *new_e;
- value.name.type.node_code = code;
- value.name.type.filename = ldlex_filename ();
- value.name.type.lineno = lineno;
- value.name.name = name;
- value.name.type.node_class = etree_name;
- exp_fold_tree_no_dot (&value);
- if (expld.result.valid_p)
- return exp_intop (expld.result.value);
- new_e = (etree_type *) stat_alloc (sizeof (new_e->name));
- memcpy (new_e, &value, sizeof (new_e->name));
- return new_e;
- }
- static etree_type *
- exp_assop (const char *dst,
- etree_type *src,
- enum node_tree_enum class,
- bfd_boolean defsym,
- bfd_boolean hidden)
- {
- etree_type *n;
- n = (etree_type *) stat_alloc (sizeof (n->assign));
- n->assign.type.node_code = '=';
- n->assign.type.filename = src->type.filename;
- n->assign.type.lineno = src->type.lineno;
- n->assign.type.node_class = class;
- n->assign.src = src;
- n->assign.dst = dst;
- n->assign.defsym = defsym;
- n->assign.hidden = hidden;
- return n;
- }
- /* Handle linker script assignments and HIDDEN. */
- etree_type *
- exp_assign (const char *dst, etree_type *src, bfd_boolean hidden)
- {
- return exp_assop (dst, src, etree_assign, FALSE, hidden);
- }
- /* Handle --defsym command-line option. */
- etree_type *
- exp_defsym (const char *dst, etree_type *src)
- {
- return exp_assop (dst, src, etree_assign, TRUE, FALSE);
- }
- /* Handle PROVIDE. */
- etree_type *
- exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
- {
- return exp_assop (dst, src, etree_provide, FALSE, hidden);
- }
- /* Handle ASSERT. */
- etree_type *
- exp_assert (etree_type *exp, const char *message)
- {
- etree_type *n;
- n = (etree_type *) stat_alloc (sizeof (n->assert_s));
- n->assert_s.type.node_code = '!';
- n->assert_s.type.filename = exp->type.filename;
- n->assert_s.type.lineno = exp->type.lineno;
- n->assert_s.type.node_class = etree_assert;
- n->assert_s.child = exp;
- n->assert_s.message = message;
- return n;
- }
- void
- exp_print_tree (etree_type *tree)
- {
- bfd_boolean function_like;
- if (config.map_file == NULL)
- config.map_file = stderr;
- if (tree == NULL)
- {
- minfo ("NULL TREE\n");
- return;
- }
- switch (tree->type.node_class)
- {
- case etree_value:
- minfo ("0x%v", tree->value.value);
- return;
- case etree_rel:
- if (tree->rel.section->owner != NULL)
- minfo ("%B:", tree->rel.section->owner);
- minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
- return;
- case etree_assign:
- fputs (tree->assign.dst, config.map_file);
- exp_print_token (tree->type.node_code, TRUE);
- exp_print_tree (tree->assign.src);
- break;
- case etree_provide:
- case etree_provided:
- fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst);
- exp_print_tree (tree->assign.src);
- fputc (')', config.map_file);
- break;
- case etree_binary:
- function_like = FALSE;
- switch (tree->type.node_code)
- {
- case MAX_K:
- case MIN_K:
- case ALIGN_K:
- case DATA_SEGMENT_ALIGN:
- case DATA_SEGMENT_RELRO_END:
- function_like = TRUE;
- break;
- case SEGMENT_START:
- /* Special handling because arguments are in reverse order and
- the segment name is quoted. */
- exp_print_token (tree->type.node_code, FALSE);
- fputs (" (\"", config.map_file);
- exp_print_tree (tree->binary.rhs);
- fputs ("\", ", config.map_file);
- exp_print_tree (tree->binary.lhs);
- fputc (')', config.map_file);
- return;
- }
- if (function_like)
- {
- exp_print_token (tree->type.node_code, FALSE);
- fputc (' ', config.map_file);
- }
- fputc ('(', config.map_file);
- exp_print_tree (tree->binary.lhs);
- if (function_like)
- fprintf (config.map_file, ", ");
- else
- exp_print_token (tree->type.node_code, TRUE);
- exp_print_tree (tree->binary.rhs);
- fputc (')', config.map_file);
- break;
- case etree_trinary:
- exp_print_tree (tree->trinary.cond);
- fputc ('?', config.map_file);
- exp_print_tree (tree->trinary.lhs);
- fputc (':', config.map_file);
- exp_print_tree (tree->trinary.rhs);
- break;
- case etree_unary:
- exp_print_token (tree->unary.type.node_code, FALSE);
- if (tree->unary.child)
- {
- fprintf (config.map_file, " (");
- exp_print_tree (tree->unary.child);
- fputc (')', config.map_file);
- }
- break;
- case etree_assert:
- fprintf (config.map_file, "ASSERT (");
- exp_print_tree (tree->assert_s.child);
- fprintf (config.map_file, ", %s)", tree->assert_s.message);
- break;
- case etree_name:
- if (tree->type.node_code == NAME)
- fputs (tree->name.name, config.map_file);
- else
- {
- exp_print_token (tree->type.node_code, FALSE);
- if (tree->name.name)
- fprintf (config.map_file, " (%s)", tree->name.name);
- }
- break;
- default:
- FAIL ();
- break;
- }
- }
- bfd_vma
- exp_get_vma (etree_type *tree, bfd_vma def, char *name)
- {
- if (tree != NULL)
- {
- exp_fold_tree_no_dot (tree);
- if (expld.result.valid_p)
- return expld.result.value;
- else if (name != NULL && expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S: nonconstant expression for %s\n"),
- tree, name);
- }
- return def;
- }
- int
- exp_get_value_int (etree_type *tree, int def, char *name)
- {
- return exp_get_vma (tree, def, name);
- }
- fill_type *
- exp_get_fill (etree_type *tree, fill_type *def, char *name)
- {
- fill_type *fill;
- size_t len;
- unsigned int val;
- if (tree == NULL)
- return def;
- exp_fold_tree_no_dot (tree);
- if (!expld.result.valid_p)
- {
- if (name != NULL && expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S: nonconstant expression for %s\n"),
- tree, name);
- return def;
- }
- if (expld.result.str != NULL && (len = strlen (expld.result.str)) != 0)
- {
- unsigned char *dst;
- unsigned char *s;
- fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
- fill->size = (len + 1) / 2;
- dst = fill->data;
- s = (unsigned char *) expld.result.str;
- val = 0;
- do
- {
- unsigned int digit;
- digit = *s++ - '0';
- if (digit > 9)
- digit = (digit - 'A' + '0' + 10) & 0xf;
- val <<= 4;
- val += digit;
- --len;
- if ((len & 1) == 0)
- {
- *dst++ = val;
- val = 0;
- }
- }
- while (len != 0);
- }
- else
- {
- fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1);
- val = expld.result.value;
- fill->data[0] = (val >> 24) & 0xff;
- fill->data[1] = (val >> 16) & 0xff;
- fill->data[2] = (val >> 8) & 0xff;
- fill->data[3] = (val >> 0) & 0xff;
- fill->size = 4;
- }
- return fill;
- }
- bfd_vma
- exp_get_abs_int (etree_type *tree, int def, char *name)
- {
- if (tree != NULL)
- {
- exp_fold_tree_no_dot (tree);
- if (expld.result.valid_p)
- {
- if (expld.result.section != NULL)
- expld.result.value += expld.result.section->vma;
- return expld.result.value;
- }
- else if (name != NULL && expld.phase != lang_mark_phase_enum)
- {
- einfo (_("%F%S: nonconstant expression for %s\n"),
- tree, name);
- }
- }
- return def;
- }
- static bfd_vma
- align_n (bfd_vma value, bfd_vma align)
- {
- if (align <= 1)
- return value;
- value = (value + align - 1) / align;
- return value * align;
- }
- void
- ldexp_init (void)
- {
- /* The value "13" is ad-hoc, somewhat related to the expected number of
- assignments in a linker script. */
- if (!bfd_hash_table_init_n (&definedness_table,
- definedness_newfunc,
- sizeof (struct definedness_hash_entry),
- 13))
- einfo (_("%P%F: can not create hash table: %E\n"));
- }
- /* Convert absolute symbols defined by a script from "dot" (also
- SEGMENT_START or ORIGIN) outside of an output section statement,
- to section relative. */
- static bfd_boolean
- set_sym_sections (struct bfd_hash_entry *bh, void *inf ATTRIBUTE_UNUSED)
- {
- struct definedness_hash_entry *def = (struct definedness_hash_entry *) bh;
- if (def->final_sec != bfd_abs_section_ptr)
- {
- struct bfd_link_hash_entry *h;
- h = bfd_link_hash_lookup (link_info.hash, bh->string,
- FALSE, FALSE, TRUE);
- if (h != NULL
- && h->type == bfd_link_hash_defined
- && h->u.def.section == bfd_abs_section_ptr)
- {
- h->u.def.value -= def->final_sec->vma;
- h->u.def.section = def->final_sec;
- }
- }
- return TRUE;
- }
- void
- ldexp_finalize_syms (void)
- {
- bfd_hash_traverse (&definedness_table, set_sym_sections, NULL);
- }
- void
- ldexp_finish (void)
- {
- bfd_hash_table_free (&definedness_table);
- }
|