X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ld%2Fldexp.c;h=0581517930b119837603d584e5ea04d7e91cc437;hb=fbcfacb75d38128a151e8fe5291c833d028f29f0;hp=a287e5860cb6999e8b0fd38b62f4d684e6ab6dca;hpb=3a399523668c16bb10b42221f278c1cebf812f93;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldexp.c b/ld/ldexp.c index a287e5860c..0581517930 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -1,10 +1,12 @@ -/* Copyright (C) 1991 Free Software Foundation, Inc. +/* This module handles expression trees. +Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +Written by Steve Chamberlain of Cygnus Support (sac@cygnus.com). This file is part of GLD, the Gnu Linker. GLD 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 1, or (at your option) +the Free Software Foundation; either version 2, or (at your option) any later version. GLD is distributed in the hope that it will be useful, @@ -14,152 +16,151 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GLD; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* - $Id$ -*/ +This module is in charge of working out the contents of expressions. -/* - * Written by Steve Chamberlain - * steve@cygnus.com - * - * This module handles expression trees. - */ +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 "sysdep.h" +#include "bfdlink.h" #include "ld.h" #include "ldmain.h" #include "ldmisc.h" #include "ldexp.h" -#include "ldgram.tab.h" -#include "ldsym.h" +#include "ldgram.h" #include "ldlang.h" -extern char *output_filename; -extern unsigned int undefined_global_sym_count; -extern unsigned int defined_global_sym_count; -extern bfd *output_bfd; -extern size_t largest_section; -extern lang_statement_list_type file_chain; -extern args_type command_line; -extern ld_config_type config; - -extern lang_input_statement_type *script_file; -extern unsigned int defined_global_sym_count; - -extern bfd_vma print_dot; - +static void exp_print_token PARAMS ((token_code_type code)); +static void make_abs PARAMS ((etree_value_type *ptr)); +static etree_value_type new_abs PARAMS ((bfd_vma value)); +static void check PARAMS ((lang_output_section_statement_type *os, + const char *name, const char *op)); +static etree_value_type new_rel + PARAMS ((bfd_vma value, lang_output_section_statement_type *section)); +static etree_value_type new_rel_from_section + PARAMS ((bfd_vma value, lang_output_section_statement_type *section)); +static etree_value_type fold_binary + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, bfd_vma *dotp)); +static etree_value_type fold_name + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot)); +static etree_value_type exp_fold_tree_no_dot + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done)); static void -exp_print_token(outfile, code) -FILE *outfile; -token_code_type code; +exp_print_token (code) + token_code_type code; { - static struct { - token_code_type code; - char *name; - } table[] = + static CONST struct { - INT, "int", - CHAR,"char", - NAME,"NAME", - PLUSEQ,"+=", - MINUSEQ,"-=", - MULTEQ,"*=", - DIVEQ,"/=", - LSHIFTEQ,"<<=", - RSHIFTEQ,">>=", - ANDEQ,"&=", - OREQ,"|=", - OROR,"||", - ANDAND,"&&", - EQ,"==", - NE,"!=", - LE,"<=", - GE,">=", - LSHIFT,"<<", - RSHIFT,">>=", - ALIGN_K,"ALIGN", - BLOCK,"BLOCK", - SECTIONS,"SECTIONS", - ALIGNMENT,"ALIGNMENT", - SIZEOF_HEADERS,"SIZEOF_HEADERS", - NEXT,"NEXT", - SIZEOF,"SIZEOF", - ADDR,"ADDR", - MEMORY,"MEMORY", - DSECT,"DSECT", - NOLOAD,"NOLOAD", - COPY,"COPY", - INFO,"INFO", - OVERLAY,"OVERLAY", - DEFINED,"DEFINED", - TARGET_K,"TARGET", - SEARCH_DIR,"SEARCH_DIR", - MAP,"MAP", - LONG,"LONG", - SHORT,"SHORT", - BYTE,"BYTE", - ENTRY,"ENTRY", - 0,(char *)NULL} ; - - - + token_code_type code; + char *name; + } table[] = + { + { INT, "int" }, + { REL, "relocateable" }, + { NAME,"NAME" }, + { PLUSEQ,"+=" }, + { MINUSEQ,"-=" }, + { MULTEQ,"*=" }, + { DIVEQ,"/=" }, + { LSHIFTEQ,"<<=" }, + { RSHIFTEQ,">>=" }, + { ANDEQ,"&=" }, + { OREQ,"|=" }, + { OROR,"||" }, + { ANDAND,"&&" }, + { EQ,"==" }, + { NE,"!=" }, + { LE,"<=" }, + { GE,">=" }, + { LSHIFT,"<<" }, + { RSHIFT,">>=" }, + { ALIGN_K,"ALIGN" }, + { BLOCK,"BLOCK" }, + { SECTIONS,"SECTIONS" }, + { SIZEOF_HEADERS,"SIZEOF_HEADERS" }, + { NEXT,"NEXT" }, + { SIZEOF,"SIZEOF" }, + { ADDR,"ADDR" }, + { LOADADDR,"LOADADDR" }, + { MEMORY,"MEMORY" }, + { DEFINED,"DEFINED" }, + { TARGET_K,"TARGET" }, + { SEARCH_DIR,"SEARCH_DIR" }, + { MAP,"MAP" }, + { QUAD,"QUAD" }, + { LONG,"LONG" }, + { SHORT,"SHORT" }, + { BYTE,"BYTE" }, + { ENTRY,"ENTRY" }, + { 0,(char *)NULL } + }; unsigned int idx; + for (idx = 0; table[idx].name != (char*)NULL; idx++) { if (table[idx].code == code) { - fprintf(outfile, "%s", table[idx].name); + fprintf(config.map_file, "%s", table[idx].name); return; } } /* Not in table, just print it alone */ - fprintf(outfile, "%c",code); + fprintf(config.map_file, "%c",code); } static void -make_abs(ptr) -etree_value_type *ptr; +make_abs (ptr) + etree_value_type *ptr; { - if (ptr->section != (lang_output_section_statement_type *)NULL) { asection *s = ptr->section->bfd_section; ptr->value += s->vma; - ptr->section = (lang_output_section_statement_type *)NULL; - } - + ptr->section = abs_output_section; } -static -etree_value_type new_abs(value) -bfd_vma value; + +static etree_value_type +new_abs (value) + bfd_vma value; { etree_value_type new; new.valid = true; - new.section = (lang_output_section_statement_type *)NULL; + new.section = abs_output_section; new.value = value; return new; } static void -DEFUN(check, (os, name, op), - lang_output_section_statement_type *os AND - CONST char *name AND - CONST char *op) +check (os, name, op) + lang_output_section_statement_type *os; + const char *name; + const char *op; { - if (os == (lang_output_section_statement_type *)NULL) { - info("%F%P %s uses undefined section %s\n", op, name); - } - if (os->processed == false) { - info("%F%P %s forward reference of section %s\n",op, name); - } + if (os == NULL) + einfo ("%F%P: %s uses undefined section %s\n", op, name); + if (! os->processed) + einfo ("%F%P: %s forward reference of section %s\n", op, name); } -etree_type *exp_intop(value) -bfd_vma value; +etree_type * +exp_intop (value) + bfd_vma value; { - etree_type *new = (etree_type *)ldmalloc(sizeof(new->value)); + etree_type *new = (etree_type *) stat_alloc(sizeof(new->value)); new->type.node_code = INT; new->value.value = value; new->type.node_class = etree_value; @@ -167,11 +168,25 @@ bfd_vma value; } +/* Build an expression representing an unnamed relocateable value. */ + +etree_type * +exp_relop (section, value) + asection *section; + bfd_vma value; +{ + etree_type *new = (etree_type *) stat_alloc (sizeof (new->rel)); + new->type.node_code = REL; + new->type.node_class = etree_rel; + new->rel.section = section; + new->rel.value = value; + return new; +} -static -etree_value_type new_rel(value, section) -bfd_vma value; -lang_output_section_statement_type *section; +static etree_value_type +new_rel (value, section) + bfd_vma value; + lang_output_section_statement_type *section; { etree_value_type new; new.valid = true; @@ -180,359 +195,475 @@ lang_output_section_statement_type *section; return new; } -static -etree_value_type new_rel_from_section(value, section) -bfd_vma value; -lang_output_section_statement_type *section; +static etree_value_type +new_rel_from_section (value, section) + bfd_vma value; + lang_output_section_statement_type *section; { etree_value_type new; new.valid = true; new.value = value; new.section = section; - if (new.section != (lang_output_section_statement_type *)NULL) { + new.value -= section->bfd_section->vma; - } + return new; } static etree_value_type -fold_binary(tree, current_section, allocation_done, dot, dotp) -etree_type *tree; -lang_output_section_statement_type *current_section; -lang_phase_type allocation_done; -bfd_vma dot; -bfd_vma *dotp; +fold_binary (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; { etree_value_type result; - result = exp_fold_tree(tree->binary.lhs, current_section, + result = exp_fold_tree (tree->binary.lhs, current_section, allocation_done, dot, dotp); - if (result.valid) { - etree_value_type other; - other = exp_fold_tree(tree->binary.rhs, - current_section, - allocation_done, dot,dotp) ; - if (other.valid) { - /* If values are from different sections, or this is an */ - /* absolute expression, make both source args absolute */ - if (result.section != other.section || - current_section == (lang_output_section_statement_type *)NULL) { - - make_abs(&result); - make_abs(&other); - } - - switch (tree->type.node_code) + if (result.valid) + { + etree_value_type other; + + other = exp_fold_tree (tree->binary.rhs, + current_section, + allocation_done, dot,dotp) ; + if (other.valid) { - case '%': - /* Mod, both absolule*/ + /* If the values are from different sections, or this is an + absolute expression, make both the source arguments + absolute. However, adding or subtracting an absolute + value from a relative value is meaningful, and is an + exception. */ + if (current_section != abs_output_section + && (other.section == abs_output_section + || (result.section == abs_output_section + && tree->type.node_code == '+')) + && (tree->type.node_code == '+' + || tree->type.node_code == '-')) + { + etree_value_type hold; + + /* If there is only one absolute term, make sure it is the + second one. */ + if (other.section != abs_output_section) + { + hold = result; + result = other; + other = hold; + } + } + else if (result.section != other.section + || current_section == abs_output_section) + { + make_abs(&result); + make_abs(&other); + } - if (other.value == 0) { - info("%F%S % by zero\n"); - } - result.value %= other.value; - break; - case '/': - if (other.value == 0) { - info("%F%S / by zero\n"); - } - result.value /= other.value; - break; -#define BOP(x,y) case x : result.value = result.value y other.value;break; - BOP('+',+); - BOP('*',*); - BOP('-',-); - BOP(LSHIFT,<<); - BOP(RSHIFT,>>); - BOP(EQ,==); - BOP(NE,!=); - BOP('<',<); - BOP('>',>); - BOP(LE,<=); - BOP(GE,>=); - BOP('&',&); - BOP('^',^); - BOP('|',|); - BOP(ANDAND,&&); - BOP(OROR,||); - default: - FAIL(); + switch (tree->type.node_code) + { + case '%': + if (other.value == 0) + einfo ("%F%S %% by zero\n"); + result.value = ((bfd_signed_vma) result.value + % (bfd_signed_vma) other.value); + break; + + case '/': + if (other.value == 0) + einfo ("%F%S / by zero\n"); + result.value = ((bfd_signed_vma) result.value + / (bfd_signed_vma) other.value); + break; + +#define BOP(x,y) case x : result.value = result.value y other.value; break; + BOP('+',+); + BOP('*',*); + BOP('-',-); + BOP(LSHIFT,<<); + BOP(RSHIFT,>>); + BOP(EQ,==); + BOP(NE,!=); + BOP('<',<); + BOP('>',>); + BOP(LE,<=); + BOP(GE,>=); + BOP('&',&); + BOP('^',^); + BOP('|',|); + BOP(ANDAND,&&); + BOP(OROR,||); + + default: + FAIL(); + } + } + else + { + result.valid = false; } } - else { - result.valid = false; - } - } + return result; } -etree_value_type invalid() + +etree_value_type +invalid () { etree_value_type new; new.valid = false; return new; } -etree_value_type fold_name(tree, current_section, allocation_done, dot) -etree_type *tree; -lang_output_section_statement_type *current_section; -lang_phase_type allocation_done; -bfd_vma dot; - +static etree_value_type +fold_name (tree, current_section, allocation_done, dot) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; { etree_value_type result; switch (tree->type.node_code) - { - case DEFINED: - result.value = - ldsym_get_soft(tree->name.name) != (ldsym_type *)NULL; - result.section = 0; - result.valid = true; - break; - case NAME: - result.valid = false; - if (tree->name.name[0] == '.' && tree->name.name[1] == 0) { - - if (allocation_done != lang_first_phase_enum) { - result = new_rel_from_section(dot, current_section); - } - else { - result = invalid(); - } - } - else { - if (allocation_done == lang_final_phase_enum) { - ldsym_type *sy = ldsym_get_soft(tree->name.name); - - if (sy) { - asymbol **sdefp = sy->sdefs_chain; - - if (sdefp) { - asymbol *sdef = *sdefp; - if (sdef->section == (asection *)NULL) { - /* This is an absolute symbol */ - result = new_abs(sdef->value); - } - else { - lang_output_section_statement_type *os = - lang_output_section_statement_lookup( sdef->section->output_section->name); - result = new_rel(sdef->value, os); + { + case SIZEOF_HEADERS: + if (allocation_done != lang_first_phase_enum) + { + result = new_abs ((bfd_vma) + bfd_sizeof_headers (output_bfd, + link_info.relocateable)); + } + else + { + result.valid = false; + } + break; + case DEFINED: + if (allocation_done == lang_first_phase_enum) + result.valid = false; + else + { + struct bfd_link_hash_entry *h; + + h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info, + tree->name.name, + false, false, true); + result.value = (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak + || h->type == bfd_link_hash_common)); + result.section = 0; + result.valid = true; + } + break; + case NAME: + result.valid = false; + if (tree->name.name[0] == '.' && tree->name.name[1] == 0) + { + if (allocation_done != lang_first_phase_enum) + result = new_rel_from_section(dot, current_section); + else + result = invalid(); + } + else if (allocation_done != lang_first_phase_enum) + { + struct bfd_link_hash_entry *h; + + h = bfd_wrapped_link_hash_lookup (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)) + { + if (bfd_is_abs_section (h->u.def.section)) + result = new_abs (h->u.def.value); + else if (allocation_done == lang_final_phase_enum + || allocation_done == lang_allocating_phase_enum) + { + lang_output_section_statement_type *os; + + os = (lang_output_section_statement_lookup + (h->u.def.section->output_section->name)); + + /* FIXME: Is this correct if this section is being + linked with -R? */ + result = new_rel ((h->u.def.value + + h->u.def.section->output_offset), + os); + } } - } + else if (allocation_done == lang_final_phase_enum) + einfo ("%F%S: undefined symbol `%s' referenced in expression\n", + tree->name.name); } - if (result.valid == false) { - info("%F%S: undefined symbol `%s' referenced in expression.\n", - tree->name.name); + break; + + case ADDR: + if (allocation_done != lang_first_phase_enum) + { + lang_output_section_statement_type *os; + + os = lang_output_section_find (tree->name.name); + check (os, tree->name.name, "ADDR"); + result = new_rel (0, os); } + else + result = invalid (); + break; - } - } + case LOADADDR: + if (allocation_done != lang_first_phase_enum) + { + lang_output_section_statement_type *os; + + os = lang_output_section_find (tree->name.name); + check (os, tree->name.name, "LOADADDR"); + if (os->load_base == NULL) + result = new_rel (0, os); + else + result = exp_fold_tree_no_dot (os->load_base, + abs_output_section, + allocation_done); + } + else + result = invalid (); + break; - break; + case SIZEOF: + if (allocation_done != lang_first_phase_enum) + { + lang_output_section_statement_type *os; - case ADDR: + os = lang_output_section_find (tree->name.name); + check (os, tree->name.name, "SIZEOF"); + result = new_abs (os->bfd_section->_raw_size); + } + else + result = invalid (); + break; - if (allocation_done != lang_first_phase_enum) { - lang_output_section_statement_type *os = - lang_output_section_find(tree->name.name); - check(os,tree->name.name,"ADDR"); - result = new_rel((bfd_vma)0, os); - } - else { - result = invalid(); - } - break; - case SIZEOF: - if(allocation_done != lang_first_phase_enum) { - lang_output_section_statement_type *os = - lang_output_section_find(tree->name.name); - check(os,tree->name.name,"SIZEOF"); - result = new_abs((bfd_vma)(os->bfd_section->size)); - } - else { - result = invalid(); + default: + FAIL(); + break; } - break; - - default: - FAIL(); - break; - } return result; } -etree_value_type exp_fold_tree(tree, current_section, allocation_done, - dot, dotp) -etree_type *tree; -lang_output_section_statement_type *current_section; -lang_phase_type allocation_done; -bfd_vma dot; -bfd_vma *dotp; +etree_value_type +exp_fold_tree (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; { etree_value_type result; - if (tree == (etree_type *)NULL) { - result.valid = false; - } - else { - switch (tree->type.node_class) - { - case etree_value: - result = new_rel(tree->value.value, current_section); - break; - case etree_unary: - result = exp_fold_tree(tree->unary.child, - current_section, - allocation_done, dot, dotp); - if (result.valid == true) - { - switch(tree->type.node_code) - { - case ALIGN_K: - if (allocation_done != lang_first_phase_enum) { - result = new_rel_from_section(ALIGN(dot, - result.value) , - current_section); + if (tree == NULL) + { + result.valid = false; + return result; + } + + switch (tree->type.node_class) + { + case etree_value: + result = new_rel (tree->value.value, current_section); + break; + + case etree_rel: + if (allocation_done != lang_final_phase_enum) + result.valid = false; + else + result = new_rel ((tree->rel.value + + tree->rel.section->output_section->vma + + tree->rel.section->output_offset), + current_section); + break; + + case etree_unary: + result = exp_fold_tree (tree->unary.child, + current_section, + allocation_done, dot, dotp); + if (result.valid) + { + switch (tree->type.node_code) + { + case ALIGN_K: + if (allocation_done != lang_first_phase_enum) + result = new_rel_from_section (ALIGN_N (dot, result.value), + current_section); + else + result.valid = false; + break; + case ABSOLUTE: + if (allocation_done != lang_first_phase_enum && result.valid) + { + result.value += result.section->bfd_section->vma; + result.section = abs_output_section; } - else { - result.valid = false; + else + result.valid = false; + break; + + case '~': + make_abs (&result); + result.value = ~result.value; + break; + + case '!': + make_abs (&result); + result.value = !result.value; + break; + + case '-': + make_abs (&result); + result.value = -result.value; + break; + + case NEXT: + /* Return next place aligned to value. */ + if (allocation_done == lang_allocating_phase_enum) + { + make_abs (&result); + result.value = ALIGN_N (dot, result.value); } - break; - case '-': - result.value = -result.value; - break; - case NEXT: + else result.valid = false; - break; - default: - FAIL(); - } - } + break; - break; - case etree_trinary: - - result = exp_fold_tree(tree->trinary.cond, - current_section, - allocation_done, dot, dotp); - if (result.valid) { - result = exp_fold_tree(result.value ? - tree->trinary.lhs:tree->trinary.rhs, - current_section, - allocation_done, dot, dotp); + default: + FAIL (); + break; + } } + break; - break; - case etree_binary: - result = fold_binary(tree, current_section, allocation_done, - dot, dotp); - break; - case etree_assign: - if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) { + case etree_trinary: + result = exp_fold_tree (tree->trinary.cond, current_section, + allocation_done, dot, dotp); + if (result.valid) + result = exp_fold_tree ((result.value + ? tree->trinary.lhs + : tree->trinary.rhs), + current_section, + allocation_done, dot, dotp); + break; + + case etree_binary: + result = fold_binary (tree, current_section, allocation_done, + dot, dotp); + break; + + case etree_assign: + case etree_provide: + if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) + { /* Assignment to dot can only be done during allocation */ - if (allocation_done == lang_allocating_phase_enum) { - result = exp_fold_tree(tree->assign.src, - current_section, - lang_allocating_phase_enum, dot, dotp); - if (result.valid == false) { - info("%F%S invalid assignment to location counter\n"); - } - else { - if (current_section == - (lang_output_section_statement_type *)NULL) { - info("%F%S assignment to location counter invalid outside of SECTION\n"); - } - else { - unsigned long nextdot =result.value + - current_section->bfd_section->vma; - if (nextdot < dot) { - info("%F%S cannot move location counter backwards"); - } - else { - *dotp = nextdot; + if (tree->type.node_class == etree_provide) + einfo ("%F%S can not PROVIDE assignment to location counter\n"); + if (allocation_done == lang_allocating_phase_enum + || (allocation_done == lang_final_phase_enum + && current_section == abs_output_section)) + { + result = exp_fold_tree (tree->assign.src, + current_section, + lang_allocating_phase_enum, dot, + dotp); + if (! result.valid) + einfo ("%F%S invalid assignment to location counter\n"); + else + { + if (current_section == NULL) + einfo ("%F%S assignment to location counter invalid outside of SECTION\n"); + else + { + bfd_vma nextdot; + + nextdot = (result.value + + current_section->bfd_section->vma); + if (nextdot < dot + && current_section != abs_output_section) + { + einfo ("%F%S cannot move location counter backwards (from %V to %V)\n", + dot, nextdot); + } + else + *dotp = nextdot; + } } - } } - } } - else { - ldsym_type *sy = ldsym_get(tree->assign.dst); - - /* If this symbol has just been created then we'll place it into - * a section of our choice - */ - result = exp_fold_tree(tree->assign.src, - current_section, allocation_done, - dot, dotp); + else + { + result = exp_fold_tree (tree->assign.src, + current_section, allocation_done, + dot, dotp); if (result.valid) { - asymbol *def; - asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **)); - /* Add this definition to script file */ - def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd); - *def_ptr = def; - - - def->value = result.value; - if (result.section != - (lang_output_section_statement_type *)NULL) { - if (current_section != - (lang_output_section_statement_type *)NULL) { - - def->section = result.section->bfd_section; - def->flags = BSF_GLOBAL | BSF_EXPORT; + boolean create; + struct bfd_link_hash_entry *h; + + if (tree->type.node_class == etree_assign) + create = true; + else + create = false; + h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, + create, false, false); + if (h == (struct bfd_link_hash_entry *) NULL) + { + if (tree->type.node_class == etree_assign) + einfo ("%P%F:%s: hash creation failed\n", + tree->assign.dst); } - else { - /* Force to absolute */ - def->value += result.section->bfd_section->vma; - def->section = (asection *)NULL; - def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE; + else if (tree->type.node_class == etree_provide + && h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Do nothing. The symbol was defined by some + object. */ + } + else + { + /* FIXME: Should we worry if the symbol is already + defined? */ + h->type = bfd_link_hash_defined; + h->u.def.value = result.value; + h->u.def.section = result.section->bfd_section; } - - - } - else { - def->section = (asection *)NULL; - def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE; - } - - - def->udata = (PTR)NULL; - def->name = sy->name; - Q_enter_global_ref(def_ptr); } - } + break; - - break; - case etree_name: - result = fold_name(tree, current_section, allocation_done, dot); - break; - default: - info("%F%S Need more of these %d",tree->type.node_class ); + case etree_name: + result = fold_name (tree, current_section, allocation_done, dot); + break; - } - } + default: + FAIL (); + break; + } return result; } - -etree_value_type exp_fold_tree_no_dot(tree, current_section, allocation_done) -etree_type *tree; -lang_output_section_statement_type *current_section; -lang_phase_type allocation_done; +static etree_value_type +exp_fold_tree_no_dot (tree, current_section, allocation_done) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; { return exp_fold_tree(tree, current_section, allocation_done, (bfd_vma) 0, (bfd_vma *)NULL); } etree_type * -exp_binop(code, lhs, rhs) -int code; -etree_type *lhs; -etree_type *rhs; +exp_binop (code, lhs, rhs) + int code; + etree_type *lhs; + etree_type *rhs; { etree_type value, *new; etree_value_type r; @@ -541,23 +672,24 @@ etree_type *rhs; value.binary.lhs = lhs; value.binary.rhs = rhs; value.type.node_class = etree_binary; - r = exp_fold_tree_no_dot(&value, (lang_output_section_statement_type *)NULL, + r = exp_fold_tree_no_dot(&value, + abs_output_section, lang_first_phase_enum ); if (r.valid) { return exp_intop(r.value); } - new = (etree_type *)ldmalloc(sizeof(new->binary)); + new = (etree_type *) stat_alloc (sizeof (new->binary)); memcpy((char *)new, (char *)&value, sizeof(new->binary)); return new; } etree_type * -exp_trinop(code, cond, lhs, rhs) -int code; -etree_type *cond; -etree_type *lhs; -etree_type *rhs; +exp_trinop (code, cond, lhs, rhs) + int code; + etree_type *cond; + etree_type *lhs; + etree_type *rhs; { etree_type value, *new; etree_value_type r; @@ -571,16 +703,16 @@ etree_type *rhs; if (r.valid) { return exp_intop(r.value); } - new = (etree_type *)ldmalloc(sizeof(new->trinary)); + new = (etree_type *) stat_alloc (sizeof (new->trinary)); memcpy((char *)new,(char *) &value, sizeof(new->trinary)); return new; } etree_type * -exp_unop(code, child) -int code; -etree_type *child; +exp_unop (code, child) + int code; + etree_type *child; { etree_type value, *new; @@ -588,37 +720,36 @@ etree_type *child; value.unary.type.node_code = code; value.unary.child = child; value.unary.type.node_class = etree_unary; -r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL, - lang_first_phase_enum); -if (r.valid) { + r = exp_fold_tree_no_dot(&value,abs_output_section, + lang_first_phase_enum); + if (r.valid) { return exp_intop(r.value); } - new = (etree_type *)ldmalloc(sizeof(new->unary)); + new = (etree_type *) stat_alloc (sizeof (new->unary)); memcpy((char *)new, (char *)&value, sizeof(new->unary)); return new; } etree_type * -exp_nameop(code, name) -int code; -char *name; +exp_nameop (code, name) + int code; + CONST char *name; { - etree_type value, *new; - etree_value_type r; value.name.type.node_code = code; value.name.name = name; value.name.type.node_class = etree_name; - r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL, - lang_first_phase_enum); + r = exp_fold_tree_no_dot(&value, + (lang_output_section_statement_type *)NULL, + lang_first_phase_enum); if (r.valid) { return exp_intop(r.value); } - new = (etree_type *)ldmalloc(sizeof(new->name)); + new = (etree_type *) stat_alloc (sizeof (new->name)); memcpy((char *)new, (char *)&value, sizeof(new->name)); return new; @@ -628,10 +759,10 @@ char *name; etree_type * -exp_assop(code, dst, src) -int code; -char *dst; -etree_type *src; +exp_assop (code, dst, src) + int code; + CONST char *dst; + etree_type *src; { etree_type value, *new; @@ -647,62 +778,96 @@ etree_type *src; return exp_intop(result); } #endif - new = (etree_type*)ldmalloc(sizeof(new->assign)); + new = (etree_type*) stat_alloc (sizeof (new->assign)); memcpy((char *)new, (char *)&value, sizeof(new->assign)); return new; } +/* Handle PROVIDE. */ + +etree_type * +exp_provide (dst, src) + const char *dst; + etree_type *src; +{ + etree_type *n; + + n = (etree_type *) stat_alloc (sizeof (n->assign)); + n->assign.type.node_code = '='; + n->assign.type.node_class = etree_provide; + n->assign.src = src; + n->assign.dst = dst; + return n; +} + void -exp_print_tree(outfile, tree) -FILE *outfile; -etree_type *tree; +exp_print_tree (tree) + etree_type *tree; { switch (tree->type.node_class) { case etree_value: - fprintf(outfile,"0x%08lx",(bfd_vma)(tree->value.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: #if 0 if (tree->assign.dst->sdefs != (asymbol *)NULL){ - fprintf(outfile,"%s (%x) ",tree->assign.dst->name, + fprintf(config.map_file,"%s (%x) ",tree->assign.dst->name, tree->assign.dst->sdefs->value); } else { - fprintf(outfile,"%s (UNDEFINED)",tree->assign.dst->name); + fprintf(config.map_file,"%s (UNDEFINED)",tree->assign.dst->name); } #endif - fprintf(outfile,"%s ",tree->assign.dst); - exp_print_token(outfile,tree->type.node_code); - exp_print_tree(outfile,tree->assign.src); + fprintf(config.map_file,"%s",tree->assign.dst); + exp_print_token(tree->type.node_code); + exp_print_tree(tree->assign.src); + break; + case etree_provide: + fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst); + exp_print_tree (tree->assign.src); + fprintf (config.map_file, ")"); break; case etree_binary: - exp_print_tree(outfile,tree->binary.lhs); - exp_print_token(outfile,tree->type.node_code); - exp_print_tree(outfile,tree->binary.rhs); + fprintf(config.map_file,"("); + exp_print_tree(tree->binary.lhs); + exp_print_token(tree->type.node_code); + exp_print_tree(tree->binary.rhs); + fprintf(config.map_file,")"); break; case etree_trinary: - exp_print_tree(outfile,tree->trinary.cond); - fprintf(outfile,"?"); - exp_print_tree(outfile,tree->trinary.lhs); - fprintf(outfile,":"); - exp_print_tree(outfile,tree->trinary.rhs); + exp_print_tree(tree->trinary.cond); + fprintf(config.map_file,"?"); + exp_print_tree(tree->trinary.lhs); + fprintf(config.map_file,":"); + exp_print_tree(tree->trinary.rhs); break; case etree_unary: - exp_print_token(outfile,tree->unary.type.node_code); - fprintf(outfile,"("); - exp_print_tree(outfile,tree->unary.child); - fprintf(outfile,")"); + exp_print_token(tree->unary.type.node_code); + if (tree->unary.child) + { + + fprintf(config.map_file,"("); + exp_print_tree(tree->unary.child); + fprintf(config.map_file,")"); + } + break; case etree_undef: - fprintf(outfile,"????????"); + fprintf(config.map_file,"????????"); break; case etree_name: if (tree->type.node_code == NAME) { - fprintf(outfile,"%s", tree->name.name); + fprintf(config.map_file,"%s", tree->name.name); } else { - exp_print_token(outfile,tree->type.node_code); - fprintf(outfile,"(%s)", tree->name.name); + exp_print_token(tree->type.node_code); + if (tree->name.name) + fprintf(config.map_file,"(%s)", tree->name.name); } break; default: @@ -711,38 +876,53 @@ etree_type *tree; } } - - - bfd_vma -exp_get_vma(tree, def, name, allocation_done) -etree_type *tree; -bfd_vma def; -char *name; -lang_phase_type allocation_done; +exp_get_vma (tree, def, name, allocation_done) + etree_type *tree; + bfd_vma def; + char *name; + lang_phase_type allocation_done; { etree_value_type r; - if (tree != (etree_type *)NULL) { - r = exp_fold_tree_no_dot(tree, - (lang_output_section_statement_type *)NULL, - allocation_done); - if (r.valid == false && name) { - info("%F%S Nonconstant expression for %s\n",name); + if (tree != NULL) + { + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + if (! r.valid && name != NULL) + einfo ("%F%S nonconstant expression for %s\n", name); + return r.value; } - return r.value; - } - else { + else return def; - } } int -exp_get_value_int(tree,def,name, allocation_done) -etree_type *tree; -int def; -char *name; -lang_phase_type allocation_done; +exp_get_value_int (tree,def,name, allocation_done) + etree_type *tree; + int def; + char *name; + lang_phase_type allocation_done; { return (int)exp_get_vma(tree,(bfd_vma)def,name, allocation_done); } + + +bfd_vma +exp_get_abs_int (tree, def, name, allocation_done) + etree_type *tree; + int def; + char *name; + lang_phase_type allocation_done; +{ + etree_value_type res; + res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + + if (res.valid) + { + res.value += res.section->bfd_section->vma; + } + else { + einfo ("%F%S non constant expression for %s\n",name); + } + return res.value; +}