binutils/

* NEWS: Mention change in linker script expression evaluation.
ld/
	* ld.texinfo (Expression Section): Detail expression evaluation.
	(Builtin Functions <ADDR>): Correct.
	(Builtin Functions <LOADADDR>): Don't mention LOADADDR normally
	the same as ADDR.
	(Builtin Functions <SEGMENT_START>): Typo fix.
	* ldexp.c (new_number): New function.
	(make_abs, exp_get_abs_int): Cope with NULL expld.result.section.
	(fold_unary <'~', '!', '-'>): Don't make_abs.
	(fold_binary): Simplify result section logic.  Return NULL section
	for logical ops.
	(fold_binary <SEGMENT_START>): Use new_rel_from_abs to set value to
	a consistent result.
	(fold_name <SIZEOF_HEADERS>): Return new_number, not new_abs.
	(fold_name <DEFINED, SIZEOF, ALIGNOF, LENGTH, CONSTANT>): Likewise.
	(fold_name <NAME>): No need to handle absolute symbols differently
	from relative ones.
	(fold_name <ORIGIN>): Don't return valid result when
	lang_first_phase_enum.  Return new_rel_from_abs, not new_abs.
	(exp_fold_tree_1 <etree_value>): Return new_number, not new_rel.
	(exp_fold_tree_1): Ajust for NULL expld.result.section.  When assigning
	a plain number to dot, assume the value is relative to expld.section.
	Make terms not in an output section, absolute.
	* ldlang.c (print_assignment): Fix style nit.
	(lang_size_sections_1): Cope with NULL expld.result.section.
	(lang_do_assignments_1): Likewise.
ld/testsuite/
	* ld-scripts/memory.t: Remove ORIGIN fudge.
This commit is contained in:
Alan Modra 2010-08-19 05:51:50 +00:00
parent 56f75c03fc
commit 7542af2ae8
8 changed files with 227 additions and 124 deletions

View File

@ -1,3 +1,7 @@
2010-08-19 Alan Modra <amodra@gmail.com>
* NEWS: Mention change in linker script expression evaluation.
2010-08-13 Dan Rosenberg <dan.j.rosenberg@gmail.com>
PR binutils/11889

View File

@ -1,5 +1,8 @@
-*- text -*-
* Linker script expression evaluation is somewhat more sane. This may
break scripts that depend on quirks of the old expression evaluation.
* Add support for the TMS320C6000 (TI C6X) processor family.
* Readelf can now display ARM unwind tables (.ARM.exidx / .ARM.extab) using

View File

@ -1,3 +1,31 @@
2010-08-19 Alan Modra <amodra@gmail.com>
* ld.texinfo (Expression Section): Detail expression evaluation.
(Builtin Functions <ADDR>): Correct.
(Builtin Functions <LOADADDR>): Don't mention LOADADDR normally
the same as ADDR.
(Builtin Functions <SEGMENT_START>): Typo fix.
* ldexp.c (new_number): New function.
(make_abs, exp_get_abs_int): Cope with NULL expld.result.section.
(fold_unary <'~', '!', '-'>): Don't make_abs.
(fold_binary): Simplify result section logic. Return NULL section
for logical ops.
(fold_binary <SEGMENT_START>): Use new_rel_from_abs to set value to
a consistent result.
(fold_name <SIZEOF_HEADERS>): Return new_number, not new_abs.
(fold_name <DEFINED, SIZEOF, ALIGNOF, LENGTH, CONSTANT>): Likewise.
(fold_name <NAME>): No need to handle absolute symbols differently
from relative ones.
(fold_name <ORIGIN>): Don't return valid result when
lang_first_phase_enum. Return new_rel_from_abs, not new_abs.
(exp_fold_tree_1 <etree_value>): Return new_number, not new_rel.
(exp_fold_tree_1): Ajust for NULL expld.result.section. When assigning
a plain number to dot, assume the value is relative to expld.section.
Make terms not in an output section, absolute.
* ldlang.c (print_assignment): Fix style nit.
(lang_size_sections_1): Cope with NULL expld.result.section.
(lang_do_assignments_1): Likewise.
2010-08-12 Alan Modra <amodra@gmail.com>
* ldexp.c (new_rel): Remove "str". Update all call sites.

View File

@ -5447,23 +5447,82 @@ address}.
@cindex absolute and relocatable symbols
@cindex relocatable and absolute symbols
@cindex symbols, relocatable and absolute
When the linker evaluates an expression, the result is either absolute
or relative to some section. A relative expression is expressed as a
fixed offset from the base of a section.
Addresses and symbols may be section relative, or absolute. A section
relative symbol is relocatable. If you request relocatable output
using the @samp{-r} option, a further link operation may change the
value of a section relative symbol. On the other hand, an absolute
symbol will retain the same value throughout any further link
operations.
The position of the expression within the linker script determines
whether it is absolute or relative. An expression which appears within
an output section definition is relative to the base of the output
section. An expression which appears elsewhere will be absolute.
Some terms in linker expressions are addresses. This is true of all
symbols and for builtin functions that return an address, such as
@code{ADDR}, @code{LOADADDR}, @code{ORIGIN} and @code{SEGMENT_START}.
Other terms are simply numbers, or are builtin functions that return a
non-address value, such as @code{LENGTH}.
A symbol set to a relative expression will be relocatable if you request
relocatable output using the @samp{-r} option. That means that a
further link operation may change the value of the symbol. The symbol's
section will be the section of the relative expression.
When the linker evaluates an expression, the result depends on where
the expression is located in a linker script. Expressions appearing
outside an output section definitions are evaluated with all terms
first being converted to absolute addresses before applying operators,
and evaluate to an absolute address result. Expressions appearing
inside an output section definition are evaluated with more complex
rules, but the aim is to treat terms as relative addresses and produce
a relative address result. In particular, an assignment of a number
to a symbol results in a symbol relative to the output section with an
offset given by the number. So, in the following simple example,
A symbol set to an absolute expression will retain the same value
through any further link operation. The symbol will be absolute, and
will not have any particular associated section.
@smallexample
@group
SECTIONS
@{
. = 0x100;
__executable_start = 0x100;
.data :
@{
. = 0x10;
__data_start = 0x10;
*(.data)
@}
@dots{}
@}
@end group
@end smallexample
both @code{.} and @code{__executable_start} are set to the absolute
address 0x100 in the first two assignments, then both @code{.} and
@code{__data_start} are set to 0x10 relative to the @code{.data}
section in the second two assignments.
For expressions appearing inside an output section definition
involving numbers, relative addresses and absolute addresses, ld
follows these rules to evaluate terms:
@itemize @bullet
@item
Unary operations on a relative address, and binary operations on two
relative addresses in the same section or between one relative address
and a number, apply the operator to the offset part of the address(es).
@item
Unary operations on an absolute address, and binary operations on one
or more absolute addresses or on two relative addresses not in the
same section, first convert any non-absolute term to an absolute
address before applying the operator.
@end itemize
The result section of each sub-expression is as follows:
@itemize @bullet
@item
An operation involving only numbers results in a number.
@item
The result of comparisons, @samp{&&} and @samp{||} is also a number.
@item
The result of other operations on relative addresses (after above
conversions) is a relative address in the same section as the operand(s).
@item
The result of other operations on absolute addresses (after above
conversions) is an absolute address.
@end itemize
You can use the builtin function @code{ABSOLUTE} to force an expression
to be absolute when it would otherwise be relative. For example, to
@ -5479,6 +5538,9 @@ SECTIONS
If @samp{ABSOLUTE} were not used, @samp{_edata} would be relative to the
@samp{.data} section.
Using @code{LOADADDR} also forces an expression absolute, since this
particular builtin function returns an absolute address.
@node Builtin Functions
@subsection Builtin Functions
@cindex functions in expressions
@ -5497,10 +5559,12 @@ normally section relative. @xref{Expression Section}.
@item ADDR(@var{section})
@kindex ADDR(@var{section})
@cindex section address in expression
Return the absolute address (the VMA) of the named @var{section}. Your
Return the address (VMA) of the named @var{section}. Your
script must previously have defined the location of that section. In
the following example, @code{symbol_1} and @code{symbol_2} are assigned
identical values:
the following example, @code{start_of_output_1}, @code{symbol_1} and
@code{symbol_2} are assigned equivalent values, except that
@code{symbol_1} will be relative to the @code{.output1} section while
the other two will be absolute:
@smallexample
@group
SECTIONS @{ @dots{}
@ -5664,9 +5728,7 @@ Return the length of the memory region named @var{memory}.
@item LOADADDR(@var{section})
@kindex LOADADDR(@var{section})
@cindex section load address in expression
Return the absolute LMA of the named @var{section}. This is normally
the same as @code{ADDR}, but it may be different if the @code{AT}
attribute is used in the output section definition (@pxref{Output
Return the absolute LMA of the named @var{section}. (@pxref{Output
Section LMA}).
@kindex MAX
@ -5696,7 +5758,7 @@ value has been given for this segment (with a command-line @samp{-T}
option) that value will be returned; otherwise the value will be
@var{default}. At present, the @samp{-T} command-line option can only
be used to set the base address for the ``text'', ``data'', and
``bss'' sections, but you use @code{SEGMENT_START} with any segment
``bss'' sections, but you can use @code{SEGMENT_START} with any segment
name.
@item SIZEOF(@var{section})

View File

@ -138,7 +138,8 @@ exp_print_token (token_code_type code, int infix_p)
static void
make_abs (void)
{
expld.result.value += expld.result.section->vma;
if (expld.result.section != NULL)
expld.result.value += expld.result.section->vma;
expld.result.section = bfd_abs_section_ptr;
}
@ -189,6 +190,15 @@ exp_relop (asection *section, bfd_vma 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)
{
@ -227,17 +237,14 @@ fold_unary (etree_type *tree)
break;
case '~':
make_abs ();
expld.result.value = ~expld.result.value;
break;
case '!':
make_abs ();
expld.result.value = !expld.result.value;
break;
case '-':
make_abs ();
expld.result.value = -expld.result.value;
break;
@ -293,6 +300,7 @@ fold_binary (etree_type *tree)
{
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;
@ -305,9 +313,7 @@ fold_binary (etree_type *tree)
einfo (_("%P: warning: address of `%s' isn't multiple of maximum page size\n"),
segment_name);
seg->used = TRUE;
expld.result.value = seg->value;
expld.result.str = NULL;
expld.result.section = expld.section;
new_rel_from_abs (seg->value);
break;
}
return;
@ -319,32 +325,20 @@ fold_binary (etree_type *tree)
if (expld.result.valid_p)
{
/* 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 (expld.section != bfd_abs_section_ptr
&& lhs.section == bfd_abs_section_ptr
&& tree->type.node_code == '+')
if (lhs.section != expld.result.section)
{
/* Keep the section of the rhs term. */
expld.result.value = lhs.value + expld.result.value;
return;
}
else if (expld.section != bfd_abs_section_ptr
&& expld.result.section == bfd_abs_section_ptr
&& (tree->type.node_code == '+'
|| tree->type.node_code == '-'))
{
/* Keep the section of the lhs term. */
expld.result.section = lhs.section;
}
else if (expld.result.section != lhs.section
|| expld.section == bfd_abs_section_ptr)
{
make_abs ();
lhs.value += lhs.section->vma;
/* 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;
}
/* If the rhs is just a number, keep the lhs section. */
else if (expld.result.section == NULL)
expld.result.section = lhs.section;
}
switch (tree->type.node_code)
@ -366,26 +360,32 @@ fold_binary (etree_type *tree)
break;
#define BOP(x, y) \
case x: \
expld.result.value = lhs.value y expld.result.value; \
break;
case x: \
expld.result.value = lhs.value y expld.result.value; \
break;
#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 (EQ, ==);
BOP (NE, !=);
BOP ('<', <);
BOP ('>', >);
BOP (LE, <=);
BOP (GE, >=);
BOP ('&', &);
BOP ('^', ^);
BOP ('|', |);
BOP (ANDAND, &&);
BOP (OROR, ||);
BOPN (EQ, ==);
BOPN (NE, !=);
BOPN ('<', <);
BOPN ('>', >);
BOPN (LE, <=);
BOPN (GE, >=);
BOPN (ANDAND, &&);
BOPN (OROR, ||);
case MAX_K:
if (lhs.value > expld.result.value)
@ -499,7 +499,7 @@ fold_name (etree_type *tree)
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_abs (hdr_size);
new_number (hdr_size);
}
break;
@ -516,14 +516,12 @@ fold_name (etree_type *tree)
&link_info,
tree->name.name,
FALSE, FALSE, TRUE);
expld.result.value = (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak
|| h->type == bfd_link_hash_common)
&& (def_iteration == lang_statement_iteration
|| def_iteration == -1));
expld.result.section = expld.section;
expld.result.valid_p = TRUE;
new_number (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak
|| h->type == bfd_link_hash_common)
&& (def_iteration == lang_statement_iteration
|| def_iteration == -1));
}
break;
@ -545,24 +543,19 @@ fold_name (etree_type *tree)
else if (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak)
{
if (bfd_is_abs_section (h->u.def.section))
new_abs (h->u.def.value);
else
{
asection *output_section;
asection *output_section;
output_section = h->u.def.section->output_section;
if (output_section == NULL)
{
if (expld.phase != lang_mark_phase_enum)
einfo (_("%X%S: unresolvable symbol `%s'"
" referenced in expression\n"),
tree->name.name);
}
else
new_rel (h->u.def.value + h->u.def.section->output_offset,
output_section);
output_section = h->u.def.section->output_section;
if (output_section == NULL)
{
if (expld.phase != lang_mark_phase_enum)
einfo (_("%X%S: unresolvable symbol `%s'"
" referenced in expression\n"),
tree->name.name);
}
else
new_rel (h->u.def.value + h->u.def.section->output_offset,
output_section);
}
else if (expld.phase == lang_final_phase_enum
|| expld.assigning_to_dot)
@ -633,7 +626,7 @@ fold_name (etree_type *tree)
if (expld.phase == lang_final_phase_enum)
einfo (_("%F%S: undefined section `%s' referenced in expression\n"),
tree->name.name);
new_abs (0);
new_number (0);
}
else if (os->processed_vma)
{
@ -645,7 +638,7 @@ fold_name (etree_type *tree)
else
val = (bfd_vma)1 << os->bfd_section->alignment_power;
new_abs (val);
new_number (val);
}
}
break;
@ -656,7 +649,7 @@ fold_name (etree_type *tree)
mem = lang_memory_region_lookup (tree->name.name, FALSE);
if (mem != NULL)
new_abs (mem->length);
new_number (mem->length);
else
einfo (_("%F%S: undefined MEMORY region `%s'"
" referenced in expression\n"), tree->name.name);
@ -664,23 +657,24 @@ fold_name (etree_type *tree)
break;
case ORIGIN:
{
lang_memory_region_type *mem;
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_abs (mem->origin);
else
einfo (_("%F%S: undefined MEMORY region `%s'"
" referenced in expression\n"), tree->name.name);
}
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->name.name);
}
break;
case CONSTANT:
if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
new_abs (config.maxpagesize);
new_number (config.maxpagesize);
else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
new_abs (config.commonpagesize);
new_number (config.commonpagesize);
else
einfo (_("%F%S: unknown constant `%s' referenced in expression\n"),
tree->name.name);
@ -704,7 +698,7 @@ exp_fold_tree_1 (etree_type *tree)
switch (tree->type.node_class)
{
case etree_value:
new_rel (tree->value.value, expld.section);
new_number (tree->value.value);
expld.result.str = tree->value.str;
break;
@ -767,7 +761,11 @@ exp_fold_tree_1 (etree_type *tree)
{
bfd_vma nextdot;
nextdot = expld.result.value + expld.result.section->vma;
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"
@ -818,6 +816,8 @@ exp_fold_tree_1 (etree_type *tree)
lang_update_definedness (tree->assign.dst, h);
h->type = bfd_link_hash_defined;
h->u.def.value = expld.result.value;
if (expld.result.section == NULL)
expld.result.section = expld.section;
h->u.def.section = expld.result.section;
if (tree->type.node_class == etree_provide)
tree->type.node_class = etree_provided;
@ -856,6 +856,12 @@ exp_fold_tree_1 (etree_type *tree)
memset (&expld.result, 0, sizeof (expld.result));
break;
}
/* Any value not inside an output section statement is an
absolute value. */
if (expld.result.valid_p
&& expld.section == bfd_abs_section_ptr)
make_abs ();
}
void
@ -1186,7 +1192,8 @@ exp_get_abs_int (etree_type *tree, int def, char *name)
if (expld.result.valid_p)
{
expld.result.value += expld.result.section->vma;
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)

View File

@ -3916,7 +3916,7 @@ print_assignment (lang_assignment_statement_type *assignment,
{
value = expld.result.value;
if (expld.result.section)
if (expld.result.section != NULL)
value += expld.result.section->vma;
minfo ("0x%V", value);
@ -3933,7 +3933,7 @@ print_assignment (lang_assignment_statement_type *assignment,
{
value = h->u.def.value;
if (expld.result.section)
if (expld.result.section != NULL)
value += expld.result.section->vma;
minfo ("[0x%V]", value);
@ -4718,7 +4718,11 @@ lang_size_sections_1
exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
if (expld.result.valid_p)
dot = expld.result.value + expld.result.section->vma;
{
dot = expld.result.value;
if (expld.result.section != NULL)
dot += expld.result.section->vma;
}
else if (expld.phase != lang_mark_phase_enum)
einfo (_("%F%S: non constant or forward reference"
" address expression for section %s\n"),
@ -5397,8 +5401,11 @@ lang_do_assignments_1 (lang_statement_union_type *s,
case lang_data_statement_enum:
exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
if (expld.result.valid_p)
s->data_statement.value = (expld.result.value
+ expld.result.section->vma);
{
s->data_statement.value = expld.result.value;
if (expld.result.section != NULL)
s->data_statement.value += expld.result.section->vma;
}
else
einfo (_("%F%P: invalid data statement\n"));
{

View File

@ -1,3 +1,7 @@
2010-08-19 Alan Modra <amodra@gmail.com>
* ld-scripts/memory.t: Remove ORIGIN fudge.
2010-08-13 H.J. Lu <hongjiu.lu@intel.com>
PR ld/11913

View File

@ -15,19 +15,7 @@ SECTIONS
. = 0;
.text :
{
/* The value returned by the ORIGIN operator is a constant.
However it is being assigned to a symbol declared within
a section. Therefore the symbol is section-relative and
its value will include the offset of that section from
the start of memory. ie the declaration:
text_start = ORIGIN (TEXTMEM);
here will result in text_start having a value of 0x200.
Hence we need to subtract the absolute value of the
location counter at this point in order to give text_start
a value that is truely absolute, and which coincidentally
will allow the tests in script.exp to work. */
text_start = ORIGIN(TEXTMEM) - ABSOLUTE (.);
text_start = ORIGIN (TEXTMEM);
*(.text)
*(.pr)
text_end = .;