/* ldexp.h -
   Copyright (C) 1991-2024 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;
  bool 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;
    bool 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,
  /* Run after symbol values have been fixed, for lang_map.  */
  lang_fixed_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,
};

struct lang_output_section_statement_struct;

typedef struct {
  enum phase_enum phase;

  bfd_vma base, relro_offset, relro_end, end;
  /* MAXPAGESIZE and COMMMONPAGESIZE as passed to DATA_SEGMENT_ALIGN.
     relropagesize sets the alignment of the end of the relro segment.  */
  bfd_vma maxpagesize, commonpagesize, relropagesize;

  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.  */
  bool 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.  */
  bool 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.  SECTION will be
     bfd_abs_section for expressions outside of an output section
     statement.  */
  bfd_vma *dotp;
  asection *section;

  /* Last output section statement.  For expressions within an output
     section statement, this will be the current output section
     statement being processed.  */
  struct lang_output_section_statement_struct *last_os;

  /* 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.  */
  bool 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 *, struct lang_output_section_statement_struct *,
   asection *, bfd_vma *);
void exp_fold_tree_no_dot
  (etree_type *, struct lang_output_section_statement_struct *);
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 *, bool);
etree_type *exp_defsym
  (const char *, etree_type *);
etree_type *exp_provide
  (const char *, etree_type *, bool);
etree_type *exp_assert
  (etree_type *, const char *);
void exp_print_tree
  (etree_type *);
bfd_vma exp_get_vma
  (etree_type *, struct lang_output_section_statement_struct *, bfd_vma, char *);
int exp_get_power
  (etree_type *, struct lang_output_section_statement_struct *, 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);
bool ldexp_is_final_sym_absolute (const struct bfd_link_hash_entry *);
void ldexp_finish (void);

#endif
