cd5b2babea
There is a call to update_definedness between code that evaluates an assignment expression value and code that transfers symbol attributes. When script assignment expressions contain DEFINED, that can mean the wrong symbol type is copied. This patch tracks symbols read during expression evaluation, rather than examining the expression and re-evaluating conditionals. Not only does this simplify the code, it also means ld can now copy symbol types in more complex expressions. An unfortunate side effect of copying symbol type for more complex expressions affects mmix, which uses PROVIDE (Main = DEFINED (Main) ? Main : (DEFINED (_start) ? _start : _start.)); in a default script. So now _start or _start. symbol type may be copied, losing the function type specially set up for Main. This can be avoided by making bfd_copy_link_hash_symbol_type do nothing for mmix. bfd/ * elf64-mmix.c (bfd_elf64_bfd_copy_link_hash_symbol_type): Define. ld/ * ldexp.h (struct ldexp_control): Add "assign_src". * ldexp.c (fold_trinary): Save and restore assign_src around condition evaluation. (fold_name <NAME>): Set expld.assign_src. (try_copy_symbol_type): Delete. (exp_fold_tree_1): Set symbol type using expld.assign_src.
244 lines
6.1 KiB
C
244 lines
6.1 KiB
C
/* ldexp.h -
|
|
Copyright (C) 1991-2017 Free Software Foundation, Inc.
|
|
|
|
This file is part of the GNU Binutils.
|
|
|
|
This program 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#ifndef LDEXP_H
|
|
#define LDEXP_H
|
|
|
|
/* The result of an expression tree */
|
|
typedef struct {
|
|
bfd_vma value;
|
|
char *str;
|
|
asection *section;
|
|
bfd_boolean valid_p;
|
|
} etree_value_type;
|
|
|
|
enum node_tree_enum {
|
|
etree_binary,
|
|
etree_trinary,
|
|
etree_unary,
|
|
etree_name,
|
|
etree_assign,
|
|
etree_provide,
|
|
etree_provided,
|
|
etree_value,
|
|
etree_assert,
|
|
etree_rel
|
|
};
|
|
|
|
typedef struct {
|
|
int node_code;
|
|
unsigned int lineno;
|
|
const char *filename;
|
|
enum node_tree_enum node_class;
|
|
} node_type;
|
|
|
|
typedef union etree_union {
|
|
node_type type;
|
|
struct {
|
|
node_type type;
|
|
union etree_union *lhs;
|
|
union etree_union *rhs;
|
|
} binary;
|
|
struct {
|
|
node_type type;
|
|
union etree_union *cond;
|
|
union etree_union *lhs;
|
|
union etree_union *rhs;
|
|
} trinary;
|
|
struct {
|
|
node_type type;
|
|
const char *dst;
|
|
union etree_union *src;
|
|
bfd_boolean defsym;
|
|
bfd_boolean hidden;
|
|
} assign;
|
|
struct {
|
|
node_type type;
|
|
union etree_union *child;
|
|
} unary;
|
|
struct {
|
|
node_type type;
|
|
const char *name;
|
|
} name;
|
|
struct {
|
|
node_type type;
|
|
bfd_vma value;
|
|
char *str;
|
|
} value;
|
|
struct {
|
|
node_type type;
|
|
asection *section;
|
|
bfd_vma value;
|
|
} rel;
|
|
struct {
|
|
node_type type;
|
|
union etree_union *child;
|
|
const char *message;
|
|
} assert_s;
|
|
} etree_type;
|
|
|
|
/* Expression evaluation control. */
|
|
typedef enum
|
|
{
|
|
/* Parsing linker script. Will only return "valid" for expressions
|
|
that evaluate to a constant. */
|
|
lang_first_phase_enum,
|
|
/* Prior to section sizing. */
|
|
lang_mark_phase_enum,
|
|
/* During section sizing. */
|
|
lang_allocating_phase_enum,
|
|
/* During assignment of symbol values when relaxation in progress. */
|
|
lang_assigning_phase_enum,
|
|
/* Final assignment of symbol values. */
|
|
lang_final_phase_enum
|
|
} lang_phase_type;
|
|
|
|
union lang_statement_union;
|
|
|
|
enum phase_enum {
|
|
/* We step through the first four states here as we see the
|
|
associated linker script tokens. */
|
|
exp_seg_none,
|
|
exp_seg_align_seen,
|
|
exp_seg_relro_seen,
|
|
exp_seg_end_seen,
|
|
/* The last three states are final, and affect the value returned
|
|
by XXX_SEGMENT_ALIGN. */
|
|
exp_seg_relro_adjust,
|
|
exp_seg_adjust,
|
|
exp_seg_done
|
|
};
|
|
|
|
enum relro_enum {
|
|
exp_seg_relro_none,
|
|
exp_seg_relro_start,
|
|
exp_seg_relro_end,
|
|
};
|
|
|
|
typedef struct {
|
|
enum phase_enum phase;
|
|
|
|
bfd_vma base, relro_offset, relro_end, end, pagesize, maxpagesize;
|
|
|
|
enum relro_enum relro;
|
|
|
|
union lang_statement_union *relro_start_stat;
|
|
union lang_statement_union *relro_end_stat;
|
|
} seg_align_type;
|
|
|
|
struct ldexp_control {
|
|
/* Modify expression evaluation depending on this. */
|
|
lang_phase_type phase;
|
|
|
|
/* Principally used for diagnostics. */
|
|
bfd_boolean assigning_to_dot;
|
|
|
|
/* Set if the current expression used "dot", SEGMENT_START or
|
|
ORIGIN, but not ABSOLUTE or combined symbols in a way that forces
|
|
an absolute result. Used in tracking symbols assigned from dot
|
|
outside of output section statements, in order to later convert
|
|
them from absolute. */
|
|
bfd_boolean rel_from_abs;
|
|
|
|
/* If evaluating an assignment, the destination. Cleared if an
|
|
etree_name NAME matches this, to signal a self-assignment.
|
|
Note that an etree_name DEFINED does not clear this field, nor
|
|
does the false branch of a trinary expression. */
|
|
const char *assign_name;
|
|
|
|
/* If evaluating an assignment, the source if it is an expression
|
|
referencing single etree_name NAME, or a trinary expression where
|
|
the true branch references a single etree_name NAME. */
|
|
struct bfd_link_hash_entry *assign_src;
|
|
|
|
/* Working results. */
|
|
etree_value_type result;
|
|
bfd_vma dot;
|
|
|
|
/* Current dot and section passed to ldexp folder. */
|
|
bfd_vma *dotp;
|
|
asection *section;
|
|
|
|
/* State machine and results for DATASEG. */
|
|
seg_align_type dataseg;
|
|
};
|
|
|
|
extern struct ldexp_control expld;
|
|
|
|
/* A maps from a segment name to a base address. */
|
|
typedef struct segment_struct {
|
|
/* The next segment in the linked list. */
|
|
struct segment_struct *next;
|
|
/* The name of the sgement. */
|
|
const char *name;
|
|
/* The base address for the segment. */
|
|
bfd_vma value;
|
|
/* True if a SEGMENT_START directive corresponding to this segment
|
|
has been seen. */
|
|
bfd_boolean used;
|
|
} segment_type;
|
|
|
|
/* The segments specified by the user on the command-line. */
|
|
extern segment_type *segments;
|
|
|
|
typedef struct _fill_type fill_type;
|
|
|
|
etree_type *exp_intop
|
|
(bfd_vma);
|
|
etree_type *exp_bigintop
|
|
(bfd_vma, char *);
|
|
etree_type *exp_relop
|
|
(asection *, bfd_vma);
|
|
void exp_fold_tree
|
|
(etree_type *, asection *, bfd_vma *);
|
|
void exp_fold_tree_no_dot
|
|
(etree_type *);
|
|
etree_type *exp_binop
|
|
(int, etree_type *, etree_type *);
|
|
etree_type *exp_trinop
|
|
(int,etree_type *, etree_type *, etree_type *);
|
|
etree_type *exp_unop
|
|
(int, etree_type *);
|
|
etree_type *exp_nameop
|
|
(int, const char *);
|
|
etree_type *exp_assign
|
|
(const char *, etree_type *, bfd_boolean);
|
|
etree_type *exp_defsym
|
|
(const char *, etree_type *);
|
|
etree_type *exp_provide
|
|
(const char *, etree_type *, bfd_boolean);
|
|
etree_type *exp_assert
|
|
(etree_type *, const char *);
|
|
void exp_print_tree
|
|
(etree_type *);
|
|
bfd_vma exp_get_vma
|
|
(etree_type *, bfd_vma, char *);
|
|
int exp_get_value_int
|
|
(etree_type *, int, char *);
|
|
fill_type *exp_get_fill
|
|
(etree_type *, fill_type *, char *);
|
|
bfd_vma exp_get_abs_int
|
|
(etree_type *, int, char *);
|
|
void ldexp_init (void);
|
|
void ldexp_finalize_syms (void);
|
|
void ldexp_finish (void);
|
|
|
|
#endif
|