+#include "write.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+struct symbol_flags
+{
+ /* Whether the symbol is a local_symbol. */
+ unsigned int local_symbol : 1;
+
+ /* Weather symbol has been written. */
+ unsigned int written : 1;
+
+ /* Whether symbol value has been completely resolved (used during
+ final pass over symbol table). */
+ unsigned int resolved : 1;
+
+ /* Whether the symbol value is currently being resolved (used to
+ detect loops in symbol dependencies). */
+ unsigned int resolving : 1;
+
+ /* Whether the symbol value is used in a reloc. This is used to
+ ensure that symbols used in relocs are written out, even if they
+ are local and would otherwise not be. */
+ unsigned int used_in_reloc : 1;
+
+ /* Whether the symbol is used as an operand or in an expression.
+ NOTE: Not all the backends keep this information accurate;
+ backends which use this bit are responsible for setting it when
+ a symbol is used in backend routines. */
+ unsigned int used : 1;
+
+ /* Whether the symbol can be re-defined. */
+ unsigned int volatil : 1;
+
+ /* Whether the symbol is a forward reference. */
+ unsigned int forward_ref : 1;
+
+ /* This is set if the symbol is defined in an MRI common section.
+ We handle such sections as single common symbols, so symbols
+ defined within them must be treated specially by the relocation
+ routines. */
+ unsigned int mri_common : 1;
+
+ /* This is set if the symbol is set with a .weakref directive. */
+ unsigned int weakrefr : 1;
+
+ /* This is set when the symbol is referenced as part of a .weakref
+ directive, but only if the symbol was not in the symbol table
+ before. It is cleared as soon as any direct reference to the
+ symbol is present. */
+ unsigned int weakrefd : 1;
+};
+
+/* A pointer in the symbol may point to either a complete symbol
+ (struct symbol below) or to a local symbol (struct local_symbol
+ defined here). The symbol code can detect the case by examining
+ the first field which is present in both structs.
+
+ We do this because we ordinarily only need a small amount of
+ information for a local symbol. The symbol table takes up a lot of
+ space, and storing less information for a local symbol can make a
+ big difference in assembler memory usage when assembling a large
+ file. */
+
+struct local_symbol
+{
+ /* Symbol flags. Only local_symbol and resolved are relevant. */
+ struct symbol_flags flags;
+
+ /* Hash value calculated from name. */
+ hashval_t hash;
+
+ /* The symbol name. */
+ const char *name;
+
+ /* The symbol frag. */
+ fragS *frag;
+
+ /* The symbol section. */
+ asection *section;
+
+ /* The value of the symbol. */
+ valueT value;
+};
+
+/* The information we keep for a symbol. The symbol table holds
+ pointers both to this and to local_symbol structures. The first
+ three fields must be identical to struct local_symbol, and the size
+ should be the same as or smaller than struct local_symbol.
+ Fields that don't fit go to an extension structure. */
+
+struct symbol
+{
+ /* Symbol flags. */
+ struct symbol_flags flags;
+
+ /* Hash value calculated from name. */
+ hashval_t hash;
+
+ /* The symbol name. */
+ const char *name;
+
+ /* Pointer to the frag this symbol is attached to, if any.
+ Otherwise, NULL. */
+ fragS *frag;
+
+ /* BFD symbol */
+ asymbol *bsym;
+
+ /* Extra symbol fields that won't fit. */
+ struct xsymbol *x;
+};
+
+/* Extra fields to make up a full symbol. */
+
+struct xsymbol
+{
+ /* The value of the symbol. */
+ expressionS value;
+
+ /* Forwards and backwards chain pointers. */
+ struct symbol *next;
+ struct symbol *previous;
+
+#ifdef OBJ_SYMFIELD_TYPE
+ OBJ_SYMFIELD_TYPE obj;
+#endif
+
+#ifdef TC_SYMFIELD_TYPE
+ TC_SYMFIELD_TYPE tc;
+#endif
+};
+
+typedef union symbol_entry
+{
+ struct local_symbol lsy;
+ struct symbol sy;
+} symbol_entry_t;
+
+/* Hash function for a symbol_entry. */
+
+static hashval_t
+hash_symbol_entry (const void *e)
+{
+ symbol_entry_t *entry = (symbol_entry_t *) e;
+ if (entry->sy.hash == 0)
+ entry->sy.hash = htab_hash_string (entry->sy.name);
+
+ return entry->sy.hash;
+}
+
+/* Equality function for a symbol_entry. */
+
+static int
+eq_symbol_entry (const void *a, const void *b)
+{
+ const symbol_entry_t *ea = (const symbol_entry_t *) a;
+ const symbol_entry_t *eb = (const symbol_entry_t *) b;
+
+ return (ea->sy.hash == eb->sy.hash
+ && strcmp (ea->sy.name, eb->sy.name) == 0);
+}
+
+static void *
+symbol_entry_find (htab_t table, const char *name)
+{
+ hashval_t hash = htab_hash_string (name);
+ symbol_entry_t needle = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ hash, name, 0, 0, 0 } };
+ return htab_find_with_hash (table, &needle, hash);
+}