This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: Linker script PROVIDE statements
Alan Modra wrote:
No. The point of PROVIDE is to only create the symbol if it is
referenced. Try changing ldexp.c:fold_name to create an undefined
symbol.
Oh, yeah, I'd missed that bit in the manual. Thanks for suggesting an
alternative.
Simply creating an undefined symbol in fold_name is insufficient. We
need to cause the name to be folded earlier on, hence the tweak in
lang_size_sections_1 wrt data statements. Unfortunately, doing that
folding causes LONG (SIZEOF (section)) to fail if 'section' is forward
referenced. Thus the removal of 'check' and its error message from
fold_name (whilst there I tidied up 'invalid'). I changed the error
message in lang_size_sections_1, to cover the cases that check would
have done so. Also, whilst there I made 'processed' tri-valued so that
one can write
section LOADADDR (section) + ${OFFSET} : AT (someexpr) {...}
which I'd find slightly more convenient when laying down ROM images.
tested on i686-pc-linux-gnu, ok? Or let me know if you'd like it splitting
up into a preparatory patch dealing with just the check, invalid and
processed field reworking, followed by a second one to do the PROVIDE stuff.
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
nathan@codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk
2004-02-20 Nathan Sidwell <nathan@codesourcery.com>
* ldlang.h (struct lang_output_section_state): Change processed
field's type.
* ldexp.c (check, invalid): Remove.
(fold_name): Move valid_p assignments. Create undefined symbol
when needed. Directly exampine section's processd flag.
(fold_tree): Reorganize assignment processing.
* ldlang.c (lang_output_section_statement_lookup): Adjust
processed field init.
(lang_size_sections_1): Allow LOADADDR when determining section's
VMA. Adjust error message. Fold data statement's expr.
(lang_size_sections): Correctly increment lang_statement_iteration.
* ld-scripts/provide.exp: New.
* ld-scripts/provide-{1,2,3}.{s,t,d}.exp: New.
Index: ld/ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.28
diff -c -3 -p -r1.28 ldexp.c
*** ld/ldexp.c 20 Feb 2004 15:31:09 -0000 1.28
--- ld/ldexp.c 20 Feb 2004 16:49:15 -0000
*************** new_abs (bfd_vma value)
*** 141,157 ****
return new;
}
- static void
- check (lang_output_section_statement_type *os,
- const char *name,
- const char *op)
- {
- 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 (bfd_vma value)
{
--- 141,146 ----
*************** fold_trinary (etree_type *tree,
*** 460,473 ****
return result;
}
- etree_value_type
- invalid (void)
- {
- etree_value_type new;
- new.valid_p = FALSE;
- return new;
- }
-
static etree_value_type
fold_name (etree_type *tree,
lang_output_section_statement_type *current_section,
--- 449,454 ----
*************** fold_name (etree_type *tree,
*** 476,500 ****
{
etree_value_type result;
switch (tree->type.node_code)
{
case SIZEOF_HEADERS:
if (allocation_done != lang_first_phase_enum)
! {
! result = new_abs (bfd_sizeof_headers (output_bfd,
! link_info.relocatable));
! }
! else
! {
! result.valid_p = FALSE;
! }
break;
case DEFINED:
if (allocation_done == lang_first_phase_enum)
! {
! lang_track_definedness (tree->name.name);
! result.valid_p = FALSE;
! }
else
{
struct bfd_link_hash_entry *h;
--- 457,474 ----
{
etree_value_type result;
+ result.valid_p = FALSE;
+
switch (tree->type.node_code)
{
case SIZEOF_HEADERS:
if (allocation_done != lang_first_phase_enum)
! result = new_abs (bfd_sizeof_headers (output_bfd,
! link_info.relocatable));
break;
case DEFINED:
if (allocation_done == lang_first_phase_enum)
! lang_track_definedness (tree->name.name);
else
{
struct bfd_link_hash_entry *h;
*************** fold_name (etree_type *tree,
*** 515,527 ****
}
break;
case NAME:
- result.valid_p = 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)
{
--- 489,498 ----
*************** fold_name (etree_type *tree,
*** 529,538 ****
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);
--- 500,510 ----
h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,
tree->name.name,
! TRUE, FALSE, TRUE);
! if (!h)
! einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
! else if (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);
*************** fold_name (etree_type *tree,
*** 565,570 ****
--- 537,548 ----
else if (allocation_done == lang_final_phase_enum)
einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"),
tree->name.name);
+ else if (h->type == bfd_link_hash_new)
+ {
+ h->type = bfd_link_hash_undefined;
+ h->u.undef.abfd = NULL;
+ bfd_link_add_undef (link_info.hash, h);
+ }
}
break;
*************** fold_name (etree_type *tree,
*** 574,584 ****
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
! check (os, tree->name.name, "ADDR");
! result = new_rel (0, NULL, os);
}
- else
- result = invalid ();
break;
case LOADADDR:
--- 552,560 ----
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
! if (os && os->processed > 0)
! result = new_rel (0, NULL, os);
}
break;
case LOADADDR:
*************** fold_name (etree_type *tree,
*** 587,602 ****
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, NULL, os);
! else
! result = exp_fold_tree_no_dot (os->load_base,
! abs_output_section,
! allocation_done);
}
- else
- result = invalid ();
break;
case SIZEOF:
--- 563,578 ----
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
! if (os && os->processed != 0)
! {
! if (os->load_base == NULL)
! result = new_rel (0, NULL, os);
! else
! result = exp_fold_tree_no_dot (os->load_base,
! abs_output_section,
! allocation_done);
! }
}
break;
case SIZEOF:
*************** fold_name (etree_type *tree,
*** 606,616 ****
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 / opb);
}
- else
- result = invalid ();
break;
default:
--- 582,590 ----
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
! if (os && os->processed > 0)
! result = new_abs (os->bfd_section->_raw_size / opb);
}
break;
default:
*************** exp_fold_tree (etree_type *tree,
*** 727,732 ****
--- 701,707 ----
{
bfd_boolean create;
struct bfd_link_hash_entry *h;
+ bfd_boolean update;
if (tree->type.node_class == etree_assign)
create = TRUE;
*************** exp_fold_tree (etree_type *tree,
*** 736,756 ****
create, FALSE, FALSE);
if (h == NULL)
{
! if (tree->type.node_class == etree_assign)
einfo (_("%P%F:%s: hash creation failed\n"),
! tree->assign.dst);
}
! 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? */
lang_update_definedness (tree->assign.dst, h);
h->type = bfd_link_hash_defined;
h->u.def.value = result.value;
--- 711,759 ----
create, FALSE, FALSE);
if (h == NULL)
{
! if (create)
einfo (_("%P%F:%s: hash creation failed\n"),
! tree->assign.dst);
! update = FALSE;
}
! else if (h->type == bfd_link_hash_new
! || h->type == bfd_link_hash_undefined
! || h->type == bfd_link_hash_common)
! update = TRUE;
! else if (h->type != bfd_link_hash_defined
! && h->type != bfd_link_hash_defweak)
! update = FALSE;
! else if (!bfd_is_abs_section (h->u.def.section)
! && (bfd_is_abs_section
! (h->u.def.section->output_section)))
! /* If it's already defined to a symbol with an
! absolute output section, it's not really a
! redefinition, because that is how we indicate
! sections that will be discarded. */
! update = TRUE;
! else if (tree->type.node_class == etree_assign)
{
! #if 0
! /* This test breaks shared object linking, as those
! have their own etext, __bss_start etc, which
! conflicts. The dynamic linking scripts should be
! fixed. */
! if (lang_statement_iteration == 1
! && (result.value != h->u.def.value
! || result.section->bfd_section != h->u.def.section))
! einfo (
! _("%F%P:%s: symbol defined in linker script and object file\n"),
! tree->assign.dst);
! #endif
! update = TRUE;
}
+ else if (tree->type.node_class == etree_provided)
+ update = TRUE;
else
+ update = FALSE;
+
+ if (update)
{
lang_update_definedness (tree->assign.dst, h);
h->type = bfd_link_hash_defined;
h->u.def.value = result.value;
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.137
diff -c -3 -p -r1.137 ldlang.c
*** ld/ldlang.c 19 Feb 2004 14:08:31 -0000 1.137
--- ld/ldlang.c 20 Feb 2004 16:49:25 -0000
*************** lang_output_section_statement_lookup (co
*** 622,628 ****
lookup->next = NULL;
lookup->bfd_section = NULL;
! lookup->processed = FALSE;
lookup->sectype = normal_section;
lookup->addr_tree = NULL;
lang_list_init (&lookup->children);
--- 622,628 ----
lookup->next = NULL;
lookup->bfd_section = NULL;
! lookup->processed = 0;
lookup->sectype = normal_section;
lookup->addr_tree = NULL;
lang_list_init (&lookup->children);
*************** lang_size_sections_1
*** 2984,2995 ****
{
etree_value_type r;
r = exp_fold_tree (os->addr_tree,
abs_output_section,
lang_allocating_phase_enum,
dot, &dot);
if (!r.valid_p)
! einfo (_("%F%S: non constant address expression for section %s\n"),
os->name);
dot = r.value + r.section->bfd_section->vma;
--- 2984,2998 ----
{
etree_value_type r;
+ os->processed = -1;
r = exp_fold_tree (os->addr_tree,
abs_output_section,
lang_allocating_phase_enum,
dot, &dot);
+ os->processed = 0;
+
if (!r.valid_p)
! einfo (_("%F%S: non constant or forward reference address expression for section %s\n"),
os->name);
dot = r.value + r.section->bfd_section->vma;
*************** lang_size_sections_1
*** 3027,3033 ****
= TO_SIZE (after - os->bfd_section->vma);
dot = os->bfd_section->vma + TO_ADDR (os->bfd_section->_raw_size);
! os->processed = TRUE;
if (os->update_dot_tree != 0)
exp_fold_tree (os->update_dot_tree, abs_output_section,
--- 3030,3036 ----
= TO_SIZE (after - os->bfd_section->vma);
dot = os->bfd_section->vma + TO_ADDR (os->bfd_section->_raw_size);
! os->processed = 1;
if (os->update_dot_tree != 0)
exp_fold_tree (os->update_dot_tree, abs_output_section,
*************** lang_size_sections_1
*** 3089,3094 ****
--- 3092,3102 ----
s->data_statement.output_section =
output_section_statement->bfd_section;
+ /* We might refer to provided symbols in the expression, and
+ need to mark them as needed. */
+ exp_fold_tree (s->data_statement.exp, abs_output_section,
+ lang_allocating_phase_enum, dot, &dot);
+
switch (s->data_statement.type)
{
default:
*************** lang_size_sections
*** 3294,3299 ****
--- 3302,3308 ----
&& first + last <= exp_data_seg.pagesize)
{
exp_data_seg.phase = exp_dataseg_adjust;
+ lang_statement_iteration++;
result = lang_size_sections_1 (s, output_section_statement, prev,
fill, dot, relax, check_regions);
}
Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.34
diff -c -3 -p -r1.34 ldlang.h
*** ld/ldlang.h 13 Jan 2004 11:10:53 -0000 1.34
--- ld/ldlang.h 20 Feb 2004 16:49:26 -0000
*************** typedef struct lang_output_section_state
*** 134,140 ****
union lang_statement_union *next;
const char *name;
! bfd_boolean processed;
asection *bfd_section;
flagword flags; /* Or together of all input sections. */
--- 134,140 ----
union lang_statement_union *next;
const char *name;
! int processed;
asection *bfd_section;
flagword flags; /* Or together of all input sections. */
Index: ld/testsuite/ld-scripts/provide-1.d
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-1.d
diff -N ld/testsuite/ld-scripts/provide-1.d
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-1.d 20 Feb 2004 16:49:30 -0000
***************
*** 0 ****
--- 1,8 ----
+ #source: provide-1.s
+ #ld: -T provide-1.t
+ #objdump: -s -j .data
+
+ .*: file format .*
+
+ Contents of section .data:
+ 0000 (08)?000000(08)? (0c)?000000(0c)? 00000000 ............
Index: ld/testsuite/ld-scripts/provide-1.s
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-1.s
diff -N ld/testsuite/ld-scripts/provide-1.s
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-1.s 20 Feb 2004 16:49:30 -0000
***************
*** 0 ****
--- 1,3 ----
+ .data
+ .globl foo
+ foo: .long 0
Index: ld/testsuite/ld-scripts/provide-1.t
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-1.t
diff -N ld/testsuite/ld-scripts/provide-1.t
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-1.t 20 Feb 2004 16:49:30 -0000
***************
*** 0 ****
--- 1,11 ----
+ SECTIONS
+ {
+ .data :
+ {
+ LONG (foo)
+ LONG (bar)
+ *(.data)
+ }
+ PROVIDE (foo = .);
+ PROVIDE (bar = .);
+ }
Index: ld/testsuite/ld-scripts/provide-2.d
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-2.d
diff -N ld/testsuite/ld-scripts/provide-2.d
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-2.d 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,6 ----
+ #source: provide-2.s
+ #ld: -T provide-2.t
+ #nm: -B
+ 0+3 A baz
+ 0+0 D foo
+
Index: ld/testsuite/ld-scripts/provide-2.s
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-2.s
diff -N ld/testsuite/ld-scripts/provide-2.s
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-2.s 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,6 ----
+ .data
+ .globl foo
+ foo: .long 0
+
+ .globl baz
+ .long baz
Index: ld/testsuite/ld-scripts/provide-2.t
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-2.t
diff -N ld/testsuite/ld-scripts/provide-2.t
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-2.t 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,10 ----
+ SECTIONS
+ {
+ PROVIDE (foo = 1);
+ PROVIDE (bar = 2);
+ PROVIDE (baz = 3);
+ .data :
+ {
+ *(.data)
+ }
+ }
Index: ld/testsuite/ld-scripts/provide-3.d
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-3.d
diff -N ld/testsuite/ld-scripts/provide-3.d
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-3.d 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,3 ----
+ #source: provide-2.s
+ #ld: -T provide-2.t
+ #error: symbol defined in linker script and object file
Index: ld/testsuite/ld-scripts/provide-3.s
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-3.s
diff -N ld/testsuite/ld-scripts/provide-3.s
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-3.s 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,3 ----
+ .data
+ .globl foo
+ foo: .long 0
Index: ld/testsuite/ld-scripts/provide-3.s~
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-3.s~
diff -N ld/testsuite/ld-scripts/provide-3.s~
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-3.s~ 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,3 ----
+ .data
+ .globl foo
+ foo: .long 0
Index: ld/testsuite/ld-scripts/provide-3.t
===================================================================
RCS file: ld/testsuite/ld-scripts/provide-3.t
diff -N ld/testsuite/ld-scripts/provide-3.t
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide-3.t 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,11 ----
+ SECTIONS
+ {
+ .data :
+ {
+ LONG (foo)
+ LONG (bar)
+ *(.data)
+ }
+ foo = .;
+ bar = .;
+ }
Index: ld/testsuite/ld-scripts/provide.exp
===================================================================
RCS file: ld/testsuite/ld-scripts/provide.exp
diff -N ld/testsuite/ld-scripts/provide.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-scripts/provide.exp 20 Feb 2004 16:49:31 -0000
***************
*** 0 ****
--- 1,25 ----
+ # Test PROVIDE in a linker script.
+ # By Nathan Sidwell, CodeSourcery LLC
+ # Copyright 2004
+ # Free Software Foundation, Inc.
+ #
+ # This file 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 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ set testname "provide"
+
+ run_dump_test provide-1
+ run_dump_test provide-2
+ setup_xfail *-*-*
+ run_dump_test provide-3