aboutsummaryrefslogtreecommitdiff
path: root/ld/ldexp.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-09-18 09:14:25 +0930
committerAlan Modra <amodra@gmail.com>2015-09-18 12:39:16 +0930
commit975f8a9e3144e4d3d3f391e907c8bf94b23dc8b6 (patch)
tree1e0766556406a33ec0f6fcd83b270087ae88897f /ld/ldexp.c
parentb29b8669ad250df649a0f02c5575e7163a2cd9e4 (diff)
downloadgdb-975f8a9e3144e4d3d3f391e907c8bf94b23dc8b6.zip
gdb-975f8a9e3144e4d3d3f391e907c8bf94b23dc8b6.tar.gz
gdb-975f8a9e3144e4d3d3f391e907c8bf94b23dc8b6.tar.bz2
Delay converting linker script defined symbols from absolute
Giving linker script symbols defined outside of output sections a section-relative value early, leads to them being used in expressions as if they were defined inside an output section. This can mean loss of the section VMA, and wrong results. ld/ PR ld/18963 * ldexp.h (struct ldexp_control): Add rel_from_abs. (ldexp_finalize_syms): Declare. * ldexp.c (new_rel_from_abs): Keep absolute for expressions outside of output section statements. Set rel_from_abs. (make_abs, exp_fold_tree, exp_fold_tree_no_dot): Clear rel_from_abs. (struct definedness_hash_entry): Add final_sec, and comment. (update_definedness): Set final_sec. (set_sym_sections, ldexp_finalize_syms): New functions. * ldlang.c (lang_process): Call ldexp_finalize_syms. ld/testsuite PR ld/18963 * ld-scripts/pr18963.d, * ld-scripts/pr18963.t: New test. * ld-scripts/expr.exp: Run it. * ld-elf/provide-hidden-2.ld: Explicitly make "dot" absolute. * ld-mips-elf/gp-hidden.sd: Don't care about _gp section. * ld-mips-elf/no-shared-1-n32.d: Don't care about symbol shown at start of .data section. * ld-mips-elf/no-shared-1-n64.d: Likewise. * ld-mips-elf/no-shared-1-o32.d: Likewise.
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r--ld/ldexp.c55
1 files changed, 52 insertions, 3 deletions
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 1140881..b7b6e6c 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -49,13 +49,25 @@ segment_type *segments;
struct ldexp_control expld;
/* This structure records symbols for which we need to keep track of
- definedness for use in the DEFINED () test. */
+ definedness for use in the DEFINED () test. It is also used in
+ making absolute symbols section relative late in the link. */
struct definedness_hash_entry
{
struct bfd_hash_entry root;
+
+ /* If this symbol was assigned from "dot" outside of an output
+ section statement, the section we'd like it relative to. */
+ asection *final_sec;
+
+ /* Symbol was defined by an object file. */
unsigned int by_object : 1;
+
+ /* Symbols was defined by a script. */
unsigned int by_script : 1;
+
+ /* Low bit of iteration count. Symbols with matching iteration have
+ been defined in this pass over the script. */
unsigned int iteration : 1;
};
@@ -174,6 +186,7 @@ make_abs (void)
if (expld.result.section != NULL)
expld.result.value += expld.result.section->vma;
expld.result.section = bfd_abs_section_ptr;
+ expld.rel_from_abs = FALSE;
}
static void
@@ -249,8 +262,7 @@ new_rel_from_abs (bfd_vma value)
{
asection *s = expld.section;
- if (s == bfd_abs_section_ptr && expld.phase == lang_final_phase_enum)
- s = section_for_dot ();
+ expld.rel_from_abs = TRUE;
expld.result.valid_p = TRUE;
expld.result.value = value - s->vma;
expld.result.str = NULL;
@@ -322,6 +334,11 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h)
defentry->by_script = 1;
defentry->iteration = lang_statement_iteration;
+ defentry->final_sec = bfd_abs_section_ptr;
+ if (expld.phase == lang_final_phase_enum
+ && expld.rel_from_abs
+ && expld.result.section == bfd_abs_section_ptr)
+ defentry->final_sec = section_for_dot ();
return ret;
}
@@ -1189,6 +1206,7 @@ exp_fold_tree_1 (etree_type *tree)
void
exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
{
+ expld.rel_from_abs = FALSE;
expld.dot = *dotp;
expld.dotp = dotp;
expld.section = current_section;
@@ -1198,6 +1216,7 @@ exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
void
exp_fold_tree_no_dot (etree_type *tree)
{
+ expld.rel_from_abs = FALSE;
expld.dot = 0;
expld.dotp = NULL;
expld.section = bfd_abs_section_ptr;
@@ -1581,6 +1600,36 @@ ldexp_init (void)
einfo (_("%P%F: can not create hash table: %E\n"));
}
+/* Convert absolute symbols defined by a script from "dot" (also
+ SEGMENT_START or ORIGIN) outside of an output section statement,
+ to section relative. */
+
+static bfd_boolean
+set_sym_sections (struct bfd_hash_entry *bh, void *inf ATTRIBUTE_UNUSED)
+{
+ struct definedness_hash_entry *def = (struct definedness_hash_entry *) bh;
+ if (def->final_sec != bfd_abs_section_ptr)
+ {
+ struct bfd_link_hash_entry *h;
+ h = bfd_link_hash_lookup (link_info.hash, bh->string,
+ FALSE, FALSE, TRUE);
+ if (h != NULL
+ && h->type == bfd_link_hash_defined
+ && h->u.def.section == bfd_abs_section_ptr)
+ {
+ h->u.def.value -= def->final_sec->vma;
+ h->u.def.section = def->final_sec;
+ }
+ }
+ return TRUE;
+}
+
+void
+ldexp_finalize_syms (void)
+{
+ bfd_hash_traverse (&definedness_table, set_sym_sections, NULL);
+}
+
void
ldexp_finish (void)
{