* 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>
* 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 LOADADDR expression was added to the linker script language.
Changes since version 2.6:
* New option --cref to print out a cross reference table.

View File

@ -1582,6 +1582,14 @@ SECTIONS@{ @dots{}
@end group
@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})
@cindex rounding up location counter
@item ALIGN(@var{exp})

View File

@ -1,5 +1,5 @@
/* 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).
This file is part of GLD, the Gnu Linker.
@ -99,6 +99,7 @@ exp_print_token (code)
{ NEXT,"NEXT" },
{ SIZEOF,"SIZEOF" },
{ ADDR,"ADDR" },
{ LOADADDR,"LOADADDR" },
{ MEMORY,"MEMORY" },
{ DEFINED,"DEFINED" },
{ TARGET_K,"TARGET" },
@ -146,15 +147,13 @@ new_abs (value)
static void
check (os, name, op)
lang_output_section_statement_type *os;
CONST char *name;
CONST char *op;
const char *name;
const char *op;
{
if (os == (lang_output_section_statement_type *)NULL) {
einfo("%F%P: %s uses undefined section %s\n", op, name);
}
if (os->processed == false) {
einfo("%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 *
@ -401,27 +400,47 @@ fold_name (tree, current_section, allocation_done, dot)
break;
case ADDR:
if (allocation_done != lang_first_phase_enum)
{
lang_output_section_statement_type *os;
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();
}
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;
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->_raw_size));
}
else {
result = invalid();
}
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, "SIZEOF");
result = new_abs (os->bfd_section->_raw_size);
}
else
result = invalid ();
break;
default:
@ -441,15 +460,18 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
{
etree_value_type result;
if (tree == (etree_type *)NULL) {
result.valid = false;
}
else {
switch (tree->type.node_class)
if (tree == NULL)
{
case etree_value:
result = new_rel(tree->value.value, current_section);
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;
@ -459,114 +481,121 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
+ 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 == true)
{
switch(tree->type.node_code)
case etree_unary:
result = exp_fold_tree (tree->unary.child,
current_section,
allocation_done, dot, dotp);
if (result.valid)
{
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)
switch (tree->type.node_code)
{
result.value += result.section->bfd_section->vma;
result.section = abs_output_section;
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;
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
{
result = exp_fold_tree (tree->assign.src,
@ -574,12 +603,15 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
dot, dotp);
if (result.valid)
{
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,
(tree->type.node_class == etree_assign
? true : false),
false, false);
create, false, false);
if (h == (struct bfd_link_hash_entry *) NULL)
{
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)
{
/* Do nothing. The symbol was defined by some
object. */
object. */
}
else
{
@ -602,21 +634,21 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
h->u.def.section = result.section->bfd_section;
}
}
}
}
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;
}
static etree_value_type
exp_fold_tree_no_dot (tree, current_section, allocation_done)
etree_type *tree;
@ -774,14 +806,12 @@ exp_print_tree (tree)
{
switch (tree->type.node_class) {
case etree_value:
print_address(tree->value.value);
minfo ("0x%v", tree->value.value);
return;
case etree_rel:
if (tree->rel.section->owner != NULL)
fprintf (config.map_file, "%s:",
bfd_get_filename (tree->rel.section->owner));
fprintf (config.map_file, "%s+", tree->rel.section->name);
print_address (tree->rel.value);
minfo ("%B:", tree->rel.section->owner);
minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
return;
case etree_assign:
#if 0
@ -793,7 +823,7 @@ exp_print_tree (tree)
fprintf(config.map_file,"%s (UNDEFINED)",tree->assign.dst->name);
}
#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_tree(tree->assign.src);
break;
@ -846,30 +876,24 @@ exp_print_tree (tree)
}
}
bfd_vma
exp_get_vma (tree, def, name, allocation_done)
etree_type *tree;
bfd_vma def;
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,
abs_output_section,
allocation_done);
if (r.valid == false && name) {
einfo("%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

View File

@ -113,7 +113,7 @@ static int error_index;
%token MEMORY DEFSYMEND
%token NOLOAD DSECT COPY INFO OVERLAY
%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 ORIGIN FILL
%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
@ -668,6 +668,8 @@ exp :
{ $$ = exp_nameop(SIZEOF,$3); }
| ADDR '(' NAME ')'
{ $$ = exp_nameop(ADDR,$3); }
| LOADADDR '(' NAME ')'
{ $$ = exp_nameop(LOADADDR,$3); }
| ABSOLUTE '(' exp ')'
{ $$ = exp_unop(ABSOLUTE, $3); }
| ALIGN_K '(' exp ')'

View File

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

View File

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