aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binutils/ChangeLog4
-rw-r--r--binutils/NEWS3
-rw-r--r--ld/ChangeLog28
-rw-r--r--ld/ld.texinfo104
-rw-r--r--ld/ldexp.c177
-rw-r--r--ld/ldlang.c17
-rw-r--r--ld/testsuite/ChangeLog4
-rw-r--r--ld/testsuite/ld-scripts/memory.t14
8 files changed, 227 insertions, 124 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 4ec74da..624bab1 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -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
diff --git a/binutils/NEWS b/binutils/NEWS
index 92f894d..a1ba9ac 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -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
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 30cb4eb..e0873ae 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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.
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 8928350..7470c53 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -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.
+
+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}.
+
+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,
-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.
+@smallexample
+@group
+SECTIONS
+ @{
+ . = 0x100;
+ __executable_start = 0x100;
+ .data :
+ @{
+ . = 0x10;
+ __data_start = 0x10;
+ *(.data)
+ @}
+ @dots{}
+ @}
+@end group
+@end smallexample
-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.
+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.
-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.
+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})
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 050227d..0549f19 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -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;
}
@@ -190,6 +191,15 @@ exp_relop (asection *section, bfd_vma value)
}
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;
@@ -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)
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 41ab2ee..2b9971a 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -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"));
{
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index c15a44e..dd7ee77 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -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
diff --git a/ld/testsuite/ld-scripts/memory.t b/ld/testsuite/ld-scripts/memory.t
index 6623b28..129bd7c 100644
--- a/ld/testsuite/ld-scripts/memory.t
+++ b/ld/testsuite/ld-scripts/memory.t
@@ -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 = .;