* ldgram.y (LOADADDR): New terminal.

(exp): Handle LOADADDR.
	* ldlex.l: Recognize LOADADDR.
	* ldexp.c (exp_print_token): Add LOADADDR.
	(fold_name): Implement LOADADDR.
	* ldlang.c (exp_init_os): Treat LOADADDR like ADDR.
	* ld.texinfo (Arithmetic Functions): Document LOADADDR.
This commit is contained in:
Ian Lance Taylor 1996-08-02 19:01:58 +00:00
parent 10a14e3639
commit 5735ac9e57
7 changed files with 217 additions and 169 deletions

View File

@ -1,3 +1,13 @@
Fri Aug 2 14:57:49 1996 Ian Lance Taylor <ian@cygnus.com>
* ldgram.y (LOADADDR): New terminal.
(exp): Handle LOADADDR.
* ldlex.l: Recognize LOADADDR.
* ldexp.c (exp_print_token): Add LOADADDR.
(fold_name): Implement LOADADDR.
* ldlang.c (exp_init_os): Treat LOADADDR like ADDR.
* ld.texinfo (Arithmetic Functions): Document LOADADDR.
Thu Aug 1 12:52:19 1996 Ian Lance Taylor <ian@cygnus.com> Thu Aug 1 12:52:19 1996 Ian Lance Taylor <ian@cygnus.com>
* ld.h (check_nocrossrefs): Declare. * ld.h (check_nocrossrefs): Declare.

View File

@ -7,6 +7,8 @@ Changes since version 2.7:
* The NOCROSSREFS command was added to the linker script language. * The NOCROSSREFS command was added to the linker script language.
* The LOADADDR expression was added to the linker script language.
Changes since version 2.6: Changes since version 2.6:
* New option --cref to print out a cross reference table. * New option --cref to print out a cross reference table.

View File

@ -1582,6 +1582,14 @@ SECTIONS@{ @dots{}
@end group @end group
@end smallexample @end smallexample
@kindex LOADADDR(@var{section})
@cindex section load address
@item LOADADDR(@var{section})
Return the absolute load address of the named @var{section}. This is
normally the same as @code{ADDR}, but it may be different if the
@code{AT} keyword is used in the section definition (@pxref{Section
Options}).
@kindex ALIGN(@var{exp}) @kindex ALIGN(@var{exp})
@cindex rounding up location counter @cindex rounding up location counter
@item ALIGN(@var{exp}) @item ALIGN(@var{exp})

View File

@ -1,5 +1,5 @@
/* This module handles expression trees. /* This module handles expression trees.
Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc. Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support (sac@cygnus.com). Written by Steve Chamberlain of Cygnus Support (sac@cygnus.com).
This file is part of GLD, the Gnu Linker. This file is part of GLD, the Gnu Linker.
@ -99,6 +99,7 @@ exp_print_token (code)
{ NEXT,"NEXT" }, { NEXT,"NEXT" },
{ SIZEOF,"SIZEOF" }, { SIZEOF,"SIZEOF" },
{ ADDR,"ADDR" }, { ADDR,"ADDR" },
{ LOADADDR,"LOADADDR" },
{ MEMORY,"MEMORY" }, { MEMORY,"MEMORY" },
{ DEFINED,"DEFINED" }, { DEFINED,"DEFINED" },
{ TARGET_K,"TARGET" }, { TARGET_K,"TARGET" },
@ -146,15 +147,13 @@ new_abs (value)
static void static void
check (os, name, op) check (os, name, op)
lang_output_section_statement_type *os; lang_output_section_statement_type *os;
CONST char *name; const char *name;
CONST char *op; const char *op;
{ {
if (os == (lang_output_section_statement_type *)NULL) { if (os == NULL)
einfo("%F%P: %s uses undefined section %s\n", op, name); einfo ("%F%P: %s uses undefined section %s\n", op, name);
} if (! os->processed)
if (os->processed == false) { einfo ("%F%P: %s forward reference of section %s\n", op, name);
einfo("%F%P: %s forward reference of section %s\n",op, name);
}
} }
etree_type * etree_type *
@ -401,27 +400,47 @@ fold_name (tree, current_section, allocation_done, dot)
break; break;
case ADDR: case ADDR:
if (allocation_done != lang_first_phase_enum)
{
lang_output_section_statement_type *os;
if (allocation_done != lang_first_phase_enum) { os = lang_output_section_find (tree->name.name);
lang_output_section_statement_type *os = check (os, tree->name.name, "ADDR");
lang_output_section_find(tree->name.name); result = new_rel (0, os);
check(os,tree->name.name,"ADDR"); }
result = new_rel((bfd_vma)0, os); else
} result = invalid ();
else {
result = invalid();
}
break; 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;
case SIZEOF: case SIZEOF:
if(allocation_done != lang_first_phase_enum) { if (allocation_done != lang_first_phase_enum)
lang_output_section_statement_type *os = {
lang_output_section_find(tree->name.name); lang_output_section_statement_type *os;
check(os,tree->name.name,"SIZEOF");
result = new_abs((bfd_vma)(os->bfd_section->_raw_size)); os = lang_output_section_find (tree->name.name);
} check (os, tree->name.name, "SIZEOF");
else { result = new_abs (os->bfd_section->_raw_size);
result = invalid(); }
} else
result = invalid ();
break; break;
default: default:
@ -441,15 +460,18 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
{ {
etree_value_type result; etree_value_type result;
if (tree == (etree_type *)NULL) { if (tree == NULL)
result.valid = false;
}
else {
switch (tree->type.node_class)
{ {
case etree_value: result.valid = false;
result = new_rel(tree->value.value, current_section); return result;
}
switch (tree->type.node_class)
{
case etree_value:
result = new_rel (tree->value.value, current_section);
break; break;
case etree_rel: case etree_rel:
if (allocation_done != lang_final_phase_enum) if (allocation_done != lang_final_phase_enum)
result.valid = false; result.valid = false;
@ -459,114 +481,121 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
+ tree->rel.section->output_offset), + tree->rel.section->output_offset),
current_section); current_section);
break; break;
case etree_unary:
result = exp_fold_tree(tree->unary.child, case etree_unary:
current_section, result = exp_fold_tree (tree->unary.child,
allocation_done, dot, dotp); current_section,
if (result.valid == true) allocation_done, dot, dotp);
{ if (result.valid)
switch(tree->type.node_code)
{ {
case ALIGN_K: switch (tree->type.node_code)
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; case ALIGN_K:
result.section = abs_output_section; 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;
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);
}
else
result.valid = false;
break;
default:
FAIL ();
break;
} }
else }
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);
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 (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.valid = false; 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;
}
}
} }
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:
if (allocation_done ==lang_allocating_phase_enum) {
make_abs(&result);
result.value = ALIGN_N(dot, result.value);
}
else {
/* Return next place aligned to value */
result.valid = false;
}
break;
default:
FAIL();
} }
}
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);
}
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 (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 == false) {
einfo("%F%S invalid assignment to location counter\n");
}
else {
if (current_section ==
(lang_output_section_statement_type *)NULL) {
einfo("%F%S assignment to location counter invalid outside of SECTION\n");
}
else {
bfd_vma 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 else
{ {
result = exp_fold_tree (tree->assign.src, result = exp_fold_tree (tree->assign.src,
@ -574,12 +603,15 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
dot, dotp); dot, dotp);
if (result.valid) if (result.valid)
{ {
boolean create;
struct bfd_link_hash_entry *h; 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, h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
(tree->type.node_class == etree_assign create, false, false);
? true : false),
false, false);
if (h == (struct bfd_link_hash_entry *) NULL) if (h == (struct bfd_link_hash_entry *) NULL)
{ {
if (tree->type.node_class == etree_assign) if (tree->type.node_class == etree_assign)
@ -591,7 +623,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
&& h->type != bfd_link_hash_common) && h->type != bfd_link_hash_common)
{ {
/* Do nothing. The symbol was defined by some /* Do nothing. The symbol was defined by some
object. */ object. */
} }
else else
{ {
@ -604,19 +636,19 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
} }
} }
break; break;
case etree_name:
result = fold_name(tree, current_section, allocation_done, dot);
break;
default:
einfo("%F%S need more of these %d\n",tree->type.node_class );
case etree_name:
result = fold_name (tree, current_section, allocation_done, dot);
break;
default:
FAIL ();
break;
} }
}
return result; return result;
} }
static etree_value_type static etree_value_type
exp_fold_tree_no_dot (tree, current_section, allocation_done) exp_fold_tree_no_dot (tree, current_section, allocation_done)
etree_type *tree; etree_type *tree;
@ -774,14 +806,12 @@ exp_print_tree (tree)
{ {
switch (tree->type.node_class) { switch (tree->type.node_class) {
case etree_value: case etree_value:
print_address(tree->value.value); minfo ("0x%v", tree->value.value);
return; return;
case etree_rel: case etree_rel:
if (tree->rel.section->owner != NULL) if (tree->rel.section->owner != NULL)
fprintf (config.map_file, "%s:", minfo ("%B:", tree->rel.section->owner);
bfd_get_filename (tree->rel.section->owner)); minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
fprintf (config.map_file, "%s+", tree->rel.section->name);
print_address (tree->rel.value);
return; return;
case etree_assign: case etree_assign:
#if 0 #if 0
@ -793,7 +823,7 @@ exp_print_tree (tree)
fprintf(config.map_file,"%s (UNDEFINED)",tree->assign.dst->name); fprintf(config.map_file,"%s (UNDEFINED)",tree->assign.dst->name);
} }
#endif #endif
fprintf(config.map_file,"%s ",tree->assign.dst); fprintf(config.map_file,"%s",tree->assign.dst);
exp_print_token(tree->type.node_code); exp_print_token(tree->type.node_code);
exp_print_tree(tree->assign.src); exp_print_tree(tree->assign.src);
break; break;
@ -846,30 +876,24 @@ exp_print_tree (tree)
} }
} }
bfd_vma bfd_vma
exp_get_vma (tree, def, name, allocation_done) exp_get_vma (tree, def, name, allocation_done)
etree_type *tree; etree_type *tree;
bfd_vma def; bfd_vma def;
char *name; char *name;
lang_phase_type allocation_done; lang_phase_type allocation_done;
{ {
etree_value_type r; etree_value_type r;
if (tree != (etree_type *)NULL) { if (tree != NULL)
r = exp_fold_tree_no_dot(tree, {
abs_output_section, r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
allocation_done); if (! r.valid && name != NULL)
if (r.valid == false && name) { einfo ("%F%S nonconstant expression for %s\n", name);
einfo("%F%S nonconstant expression for %s\n",name); return r.value;
} }
return r.value; else
}
else {
return def; return def;
}
} }
int int

View File

@ -113,7 +113,7 @@ static int error_index;
%token MEMORY DEFSYMEND %token MEMORY DEFSYMEND
%token NOLOAD DSECT COPY INFO OVERLAY %token NOLOAD DSECT COPY INFO OVERLAY
%token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY %token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
%token <integer> SIZEOF NEXT ADDR %token <integer> SIZEOF NEXT ADDR LOADADDR
%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS %token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
%token ORIGIN FILL %token ORIGIN FILL
%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS %token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
@ -668,6 +668,8 @@ exp :
{ $$ = exp_nameop(SIZEOF,$3); } { $$ = exp_nameop(SIZEOF,$3); }
| ADDR '(' NAME ')' | ADDR '(' NAME ')'
{ $$ = exp_nameop(ADDR,$3); } { $$ = exp_nameop(ADDR,$3); }
| LOADADDR '(' NAME ')'
{ $$ = exp_nameop(LOADADDR,$3); }
| ABSOLUTE '(' exp ')' | ABSOLUTE '(' exp ')'
{ $$ = exp_unop(ABSOLUTE, $3); } { $$ = exp_unop(ABSOLUTE, $3); }
| ALIGN_K '(' exp ')' | ALIGN_K '(' exp ')'

View File

@ -618,6 +618,7 @@ exp_init_os (exp)
switch (exp->type.node_code) switch (exp->type.node_code)
{ {
case ADDR: case ADDR:
case LOADADDR:
case SIZEOF: case SIZEOF:
{ {
lang_output_section_statement_type *os; lang_output_section_statement_type *os;

View File

@ -228,6 +228,7 @@ NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
<BOTH,SCRIPT>"LENGTH" { RTOKEN(LENGTH);} <BOTH,SCRIPT>"LENGTH" { RTOKEN(LENGTH);}
<EXPRESSION,BOTH,SCRIPT>"ALIGN" { RTOKEN(ALIGN_K);} <EXPRESSION,BOTH,SCRIPT>"ALIGN" { RTOKEN(ALIGN_K);}
<EXPRESSION,BOTH,SCRIPT>"ADDR" { RTOKEN(ADDR);} <EXPRESSION,BOTH,SCRIPT>"ADDR" { RTOKEN(ADDR);}
<EXPRESSION,BOTH,SCRIPT>"LOADADDR" { RTOKEN(LOADADDR);}
<BOTH,SCRIPT>"ENTRY" { RTOKEN(ENTRY);} <BOTH,SCRIPT>"ENTRY" { RTOKEN(ENTRY);}
<EXPRESSION,BOTH,SCRIPT>"NEXT" { RTOKEN(NEXT);} <EXPRESSION,BOTH,SCRIPT>"NEXT" { RTOKEN(NEXT);}
<EXPRESSION,BOTH,SCRIPT>"sizeof_headers" { RTOKEN(SIZEOF_HEADERS);} <EXPRESSION,BOTH,SCRIPT>"sizeof_headers" { RTOKEN(SIZEOF_HEADERS);}