X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fsymbols.c;h=acf394330dfce03e213f3dc06e33d567e989bd5d;hb=a350efd4fb368a35ada608f6bc26ccd3bed0ae6b;hp=9115d7ec6d65ae1eceea14d607fffc01ec458a2a;hpb=2b0f37619f797bf640b2d45acb615817dd202954;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/symbols.c b/gas/symbols.c index 9115d7ec6d..acf394330d 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -1,5 +1,5 @@ /* symbols.c -symbol table- - Copyright (C) 1987-2016 Free Software Foundation, Inc. + Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -24,7 +24,141 @@ #include "safe-ctype.h" #include "obstack.h" /* For "symbols.h" */ #include "subsegs.h" -#include "struc-symbol.h" +#include "write.h" + +struct symbol_flags +{ + /* Whether the symbol is a local_symbol. */ + unsigned int sy_local_symbol : 1; + + /* Weather symbol has been written. */ + unsigned int sy_written : 1; + + /* Whether symbol value has been completely resolved (used during + final pass over symbol table). */ + unsigned int sy_resolved : 1; + + /* Whether the symbol value is currently being resolved (used to + detect loops in symbol dependencies). */ + unsigned int sy_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 sy_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 sy_used : 1; + + /* Whether the symbol can be re-defined. */ + unsigned int sy_volatile : 1; + + /* Whether the symbol is a forward reference. */ + unsigned int sy_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 sy_mri_common : 1; + + /* This is set if the symbol is set with a .weakref directive. */ + unsigned int sy_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 sy_weakrefd : 1; +}; + +/* The information we keep for a symbol. Note that the symbol table + holds pointers both to this and to local_symbol structures. See + below. */ + +struct symbol +{ + /* Symbol flags. */ + struct symbol_flags sy_flags; + + /* BFD symbol */ + asymbol *bsym; + + /* The value of the symbol. */ + expressionS sy_value; + + /* Forwards and (optionally) backwards chain pointers. */ + struct symbol *sy_next; + struct symbol *sy_previous; + + /* Pointer to the frag this symbol is attached to, if any. + Otherwise, NULL. */ + struct frag *sy_frag; + +#ifdef OBJ_SYMFIELD_TYPE + OBJ_SYMFIELD_TYPE sy_obj; +#endif + +#ifdef TC_SYMFIELD_TYPE + TC_SYMFIELD_TYPE sy_tc; +#endif + +#ifdef TARGET_SYMBOL_FIELDS + TARGET_SYMBOL_FIELDS +#endif +}; + +/* A pointer in the symbol may point to either a complete symbol + (struct symbol above) 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 sy_local_symbol and sy_resolved are relevant. */ + struct symbol_flags lsy_flags; + + /* The symbol section. This also serves as a flag. If this is + reg_section, then this symbol has been converted into a regular + symbol, and lsy_sym points to it. */ + segT lsy_section; + + /* The symbol name. */ + const char *lsy_name; + + /* The symbol frag or the real symbol, depending upon the value in + lsy_section. */ + union + { + fragS *lsy_frag; + symbolS *lsy_sym; + } u; + + /* The value of the symbol. */ + valueT lsy_value; + +#ifdef TC_LOCAL_SYMFIELD_TYPE + TC_LOCAL_SYMFIELD_TYPE lsy_tc; +#endif +}; + +#define local_symbol_converted_p(l) ((l)->lsy_section == reg_section) +#define local_symbol_mark_converted(l) ((l)->lsy_section = reg_section) +#define local_symbol_resolved_p(l) ((l)->lsy_flags.sy_resolved) +#define local_symbol_mark_resolved(l) ((l)->lsy_flags.sy_resolved = 1) +#define local_symbol_get_frag(l) ((l)->u.lsy_frag) +#define local_symbol_set_frag(l, f) ((l)->u.lsy_frag = (f)) +#define local_symbol_get_real_symbol(l) ((l)->u.lsy_sym) +#define local_symbol_set_real_symbol(l, s) ((l)->u.lsy_sym = (s)) /* This is non-zero if symbols are case sensitive, which is the default. */ @@ -107,6 +241,7 @@ save_symbol_name (const char *name) size_t name_length; char *ret; + gas_assert (name != NULL); name_length = strlen (name) + 1; /* +1 for \0. */ obstack_grow (¬es, name, name_length); ret = (char *) obstack_finish (¬es); @@ -192,14 +327,14 @@ local_symbol_make (const char *name, segT section, valueT val, fragS *frag) { const char *name_copy; struct local_symbol *ret; + struct symbol_flags flags = { .sy_local_symbol = 1, .sy_resolved = 0 }; ++local_symbol_count; name_copy = save_symbol_name (name); ret = (struct local_symbol *) obstack_alloc (¬es, sizeof *ret); - ret->lsy_flags.sy_local_symbol = 1; - ret->lsy_flags.sy_resolved = 0; + ret->lsy_flags = flags; ret->lsy_name = name_copy; ret->lsy_section = section; local_symbol_set_frag (ret, frag); @@ -406,8 +541,7 @@ colon (/* Just seen "x:" - rattle symbols & frags. */ } else { -#if (!defined (OBJ_AOUT) && !defined (OBJ_MAYBE_AOUT) \ - && !defined (OBJ_BOUT) && !defined (OBJ_MAYBE_BOUT)) +#if (!defined (OBJ_AOUT) && !defined (OBJ_MAYBE_AOUT)) static const char *od_buf = ""; #else char od_buf[100]; @@ -618,9 +752,22 @@ symbol_clone (symbolS *orgsymP, int replace) return newsymP; } +/* If S is a local symbol that has been converted, return the + converted symbol. Otherwise return S. */ + +static inline symbolS * +get_real_sym (symbolS *s) +{ + if (s != NULL + && s->sy_flags.sy_local_symbol + && local_symbol_converted_p ((struct local_symbol *) s)) + s = local_symbol_get_real_symbol ((struct local_symbol *) s); + return s; +} + /* Referenced symbols, if they are forward references, need to be cloned (without replacing the original) so that the value of the referenced - symbols at the point of use . */ + symbols at the point of use is saved by the clone. */ #undef symbol_clone_if_forward_ref symbolS * @@ -628,8 +775,10 @@ symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward) { if (symbolP && !LOCAL_SYMBOL_CHECK (symbolP)) { - symbolS *add_symbol = symbolP->sy_value.X_add_symbol; - symbolS *op_symbol = symbolP->sy_value.X_op_symbol; + symbolS *orig_add_symbol = get_real_sym (symbolP->sy_value.X_add_symbol); + symbolS *orig_op_symbol = get_real_sym (symbolP->sy_value.X_op_symbol); + symbolS *add_symbol = orig_add_symbol; + symbolS *op_symbol = orig_op_symbol; if (symbolP->sy_flags.sy_forward_ref) is_forward = 1; @@ -658,8 +807,8 @@ symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward) } if (symbolP->sy_flags.sy_forward_ref - || add_symbol != symbolP->sy_value.X_add_symbol - || op_symbol != symbolP->sy_value.X_op_symbol) + || add_symbol != orig_add_symbol + || op_symbol != orig_op_symbol) { if (symbolP != &dot_symbol) { @@ -694,6 +843,12 @@ symbol_temp_new_now (void) return symbol_temp_new (now_seg, frag_now_fix (), frag_now); } +symbolS * +symbol_temp_new_now_octets (void) +{ + return symbol_temp_new (now_seg, frag_now_fix_octets (), frag_now); +} + symbolS * symbol_temp_make (void) { @@ -768,14 +923,12 @@ symbol_find_noref (const char *name, int noref) *copy++ = TOUPPER (c); *copy = '\0'; - if (copy2 != NULL) - free (copy2); + free (copy2); copy = (char *) name; } result = symbol_find_exact_noref (name, noref); - if (copy != NULL) - free (copy); + free (copy); return result; } @@ -912,6 +1065,20 @@ verify_symbol_chain (symbolS *rootP, symbolS *lastP) gas_assert (lastP == symbolP); } +int +symbol_on_chain (symbolS *s, symbolS *rootPP, symbolS *lastPP) +{ + return (!LOCAL_SYMBOL_CHECK (s) + && ((s->sy_next != s + && s->sy_next != NULL + && s->sy_next->sy_previous == s) + || s == lastPP) + && ((s->sy_previous != s + && s->sy_previous != NULL + && s->sy_previous->sy_next == s) + || s == rootPP)); +} + #ifdef OBJ_COMPLEX_RELC static int @@ -922,19 +1089,6 @@ use_complex_relocs_for (symbolS * symp) case O_constant: return 0; - case O_symbol: - case O_symbol_rva: - case O_uminus: - case O_bit_not: - case O_logical_not: - if ( (S_IS_COMMON (symp->sy_value.X_add_symbol) - || S_IS_LOCAL (symp->sy_value.X_add_symbol)) - && - (S_IS_DEFINED (symp->sy_value.X_add_symbol) - && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section)) - return 0; - break; - case O_multiply: case O_divide: case O_modulus: @@ -954,18 +1108,22 @@ use_complex_relocs_for (symbolS * symp) case O_gt: case O_logical_and: case O_logical_or: - - if ( (S_IS_COMMON (symp->sy_value.X_add_symbol) - || S_IS_LOCAL (symp->sy_value.X_add_symbol)) - && - (S_IS_COMMON (symp->sy_value.X_op_symbol) + if ((S_IS_COMMON (symp->sy_value.X_op_symbol) || S_IS_LOCAL (symp->sy_value.X_op_symbol)) - - && S_IS_DEFINED (symp->sy_value.X_add_symbol) && S_IS_DEFINED (symp->sy_value.X_op_symbol) - && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section && S_GET_SEGMENT (symp->sy_value.X_op_symbol) != expr_section) - return 0; + { + case O_symbol: + case O_symbol_rva: + case O_uminus: + case O_bit_not: + case O_logical_not: + if ((S_IS_COMMON (symp->sy_value.X_add_symbol) + || S_IS_LOCAL (symp->sy_value.X_add_symbol)) + && S_IS_DEFINED (symp->sy_value.X_add_symbol) + && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section) + return 0; + } break; default: @@ -1046,7 +1204,7 @@ valueT resolve_symbol_value (symbolS *symp) { int resolved; - valueT final_val = 0; + valueT final_val; segT final_seg; if (LOCAL_SYMBOL_CHECK (symp)) @@ -1057,7 +1215,13 @@ resolve_symbol_value (symbolS *symp) if (local_symbol_resolved_p (locsym)) return final_val; - final_val += local_symbol_get_frag (locsym)->fr_address / OCTETS_PER_BYTE; + /* Symbols whose section has SEC_ELF_OCTETS set, + resolve to octets instead of target bytes. */ + if (locsym->lsy_section->flags & SEC_OCTETS) + final_val += local_symbol_get_frag (locsym)->fr_address; + else + final_val += (local_symbol_get_frag (locsym)->fr_address + / OCTETS_PER_BYTE); if (finalize_syms) { @@ -1070,10 +1234,25 @@ resolve_symbol_value (symbolS *symp) if (symp->sy_flags.sy_resolved) { + final_val = 0; + while (symp->sy_value.X_op == O_symbol) + { + final_val += symp->sy_value.X_add_number; + symp = symp->sy_value.X_add_symbol; + if (LOCAL_SYMBOL_CHECK (symp)) + { + struct local_symbol *locsym = (struct local_symbol *) symp; + final_val += locsym->lsy_value; + return final_val; + } + if (!symp->sy_flags.sy_resolved) + return 0; + } if (symp->sy_value.X_op == O_constant) - return (valueT) symp->sy_value.X_add_number; + final_val += symp->sy_value.X_add_number; else - return 0; + final_val = 0; + return final_val; } resolved = 0; @@ -1130,6 +1309,7 @@ resolve_symbol_value (symbolS *symp) resolved = 1; } + final_val = 0; final_seg = undefined_section; goto exit_dont_set_value; } @@ -1161,7 +1341,12 @@ resolve_symbol_value (symbolS *symp) /* Fall through. */ case O_constant: - final_val += symp->sy_frag->fr_address / OCTETS_PER_BYTE; + /* Symbols whose section has SEC_ELF_OCTETS set, + resolve to octets instead of target bytes. */ + if (symp->bsym->section->flags & SEC_OCTETS) + final_val += symp->sy_frag->fr_address; + else + final_val += symp->sy_frag->fr_address / OCTETS_PER_BYTE; if (final_seg == expr_section) final_seg = absolute_section; /* Fall through. */ @@ -1200,6 +1385,12 @@ resolve_symbol_value (symbolS *symp) break; } + /* Don't leave symbol loops. */ + if (finalize_syms + && !LOCAL_SYMBOL_CHECK (add_symbol) + && add_symbol->sy_flags.sy_resolving) + break; + if (finalize_syms && final_val == 0) { if (LOCAL_SYMBOL_CHECK (add_symbol)) @@ -1214,11 +1405,16 @@ resolve_symbol_value (symbolS *symp) relocation to detect this case, and convert the relocation to be against the symbol to which this symbol is equated. */ - if (! S_IS_DEFINED (add_symbol) + if (seg_left == undefined_section + || bfd_is_com_section (seg_left) #if defined (OBJ_COFF) && defined (TE_PE) || S_IS_WEAK (add_symbol) #endif - || S_IS_COMMON (add_symbol)) + || (finalize_syms + && ((final_seg == expr_section + && seg_left != expr_section + && seg_left != absolute_section) + || symbol_shadow_p (symp)))) { if (finalize_syms) { @@ -1229,25 +1425,6 @@ resolve_symbol_value (symbolS *symp) symp->sy_value.X_op_symbol = add_symbol; } final_seg = seg_left; - final_val = 0; - resolved = symbol_resolved_p (add_symbol); - symp->sy_flags.sy_resolving = 0; - goto exit_dont_set_value; - } - else if (finalize_syms - && ((final_seg == expr_section && seg_left != expr_section) - || symbol_shadow_p (symp))) - { - /* If the symbol is an expression symbol, do similarly - as for undefined and common syms above. Handles - "sym +/- expr" where "expr" cannot be evaluated - immediately, and we want relocations to be against - "sym", eg. because it is weak. */ - symp->sy_value.X_op = O_symbol; - symp->sy_value.X_add_symbol = add_symbol; - symp->sy_value.X_add_number = final_val; - symp->sy_value.X_op_symbol = add_symbol; - final_seg = seg_left; final_val += symp->sy_frag->fr_address + left; resolved = symbol_resolved_p (add_symbol); symp->sy_flags.sy_resolving = 0; @@ -1355,7 +1532,7 @@ resolve_symbol_value (symbolS *symp) operands must be absolute. We already handled the case of addition or subtraction of a constant above. This will probably need to be changed for an object file format which - supports arbitrary expressions, such as IEEE-695. */ + supports arbitrary expressions. */ if (!(seg_left == absolute_section && seg_right == absolute_section) && !(op == O_eq || op == O_ne) @@ -1429,7 +1606,16 @@ resolve_symbol_value (symbolS *symp) case O_gt: left = left > right ? ~ (offsetT) 0 : 0; break; case O_logical_and: left = left && right; break; case O_logical_or: left = left || right; break; - default: abort (); + + case O_illegal: + case O_absent: + case O_constant: + /* See PR 20895 for a reproducer. */ + as_bad (_("Invalid operation on symbol")); + goto exit_dont_set_value; + + default: + abort (); } final_val += symp->sy_frag->fr_address + left; @@ -1463,7 +1649,7 @@ resolve_symbol_value (symbolS *symp) if (finalize_syms) S_SET_VALUE (symp, final_val); -exit_dont_set_value: + exit_dont_set_value: /* Always set the segment, even if not finalizing the value. The segment is used to determine whether a symbol is defined. */ S_SET_SEGMENT (symp, final_seg); @@ -1552,9 +1738,23 @@ snapshot_symbol (symbolS **symbolPP, valueT *valueP, segT *segP, fragS **fragPP) } *symbolPP = symbolP; - *valueP = exp.X_add_number; - *segP = symbolP->bsym->section; - *fragPP = symbolP->sy_frag; + + /* A bogus input file can result in resolve_expression() + generating a local symbol, so we have to check again. */ + if (LOCAL_SYMBOL_CHECK (symbolP)) + { + struct local_symbol *locsym = (struct local_symbol *) symbolP; + + *valueP = locsym->lsy_value; + *segP = locsym->lsy_section; + *fragPP = local_symbol_get_frag (locsym); + } + else + { + *valueP = exp.X_add_number; + *segP = symbolP->bsym->section; + *fragPP = symbolP->sy_frag; + } if (*segP == expr_section) switch (exp.X_op) @@ -2082,16 +2282,20 @@ S_IS_DEFINED (symbolS *s) int S_FORCE_RELOC (symbolS *s, int strict) { + segT sec; if (LOCAL_SYMBOL_CHECK (s)) - return ((struct local_symbol *) s)->lsy_section == undefined_section; - - return ((strict + sec = ((struct local_symbol *) s)->lsy_section; + else + { + if ((strict && ((s->bsym->flags & BSF_WEAK) != 0 || (EXTERN_FORCE_RELOC && (s->bsym->flags & BSF_GLOBAL) != 0))) - || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0 - || s->bsym->section == undefined_section - || bfd_is_com_section (s->bsym->section)); + || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0) + return TRUE; + sec = s->bsym->section; + } + return bfd_is_und_section (sec) || bfd_is_com_section (sec); } int @@ -2119,14 +2323,14 @@ S_IS_LOCAL (symbolS *s) if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL)) abort (); - if (bfd_get_section (s->bsym) == reg_section) + if (bfd_asymbol_section (s->bsym) == reg_section) return 1; if (flag_strip_local_absolute /* Keep BSF_FILE symbols in order to allow debuggers to identify the source file even when the object file is stripped. */ && (flags & (BSF_GLOBAL | BSF_FILE)) == 0 - && bfd_get_section (s->bsym) == absolute_section) + && bfd_asymbol_section (s->bsym) == absolute_section) return 1; name = S_GET_NAME (s); @@ -2134,6 +2338,9 @@ S_IS_LOCAL (symbolS *s) && ! S_IS_DEBUG (s) && (strchr (name, DOLLAR_LABEL_CHAR) || strchr (name, LOCAL_LABEL_CHAR) +#if FAKE_LABEL_CHAR != DOLLAR_LABEL_CHAR + || strchr (name, FAKE_LABEL_CHAR) +#endif || TC_LABEL_IS_LOCAL (name) || (! flag_keep_locals && (bfd_is_local_label (stdoutput, s->bsym) @@ -2431,12 +2638,8 @@ symbol_set_value_expression (symbolS *s, const expressionS *exp) int symbol_same_p (symbolS *s1, symbolS *s2) { - if (s1->sy_flags.sy_local_symbol - && local_symbol_converted_p ((struct local_symbol *) s1)) - s1 = local_symbol_get_real_symbol ((struct local_symbol *) s1); - if (s2->sy_flags.sy_local_symbol - && local_symbol_converted_p ((struct local_symbol *) s2)) - s2 = local_symbol_get_real_symbol ((struct local_symbol *) s2); + s1 = get_real_sym (s1); + s2 = get_real_sym (s2); return s1 == s2; } @@ -2691,6 +2894,18 @@ symbol_shadow_p (symbolS *s) return s->sy_next == s; } +/* If S was created as a struct symbol, return S, otherwise if S is a + converted local_symbol return the converted symbol, otherwise + return NULL. */ + +symbolS * +symbol_symbolS (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + return NULL; + return s; +} + /* Return the BFD symbol for a symbol. */ asymbol * @@ -3058,9 +3273,9 @@ symbol_relc_make_sym (symbolS * sym) is defined as an expression or a plain value. */ if ( S_GET_SEGMENT (sym) == expr_section || S_GET_SEGMENT (sym) == absolute_section) - return symbol_relc_make_expr (& sym->sy_value); + return symbol_relc_make_expr (symbol_get_value_expression (sym)); - /* This may be a "fake symbol" L0\001, referring to ".". + /* This may be a "fake symbol", referring to ".". Write out a special null symbol to refer to this position. */ if (! strcmp (S_GET_NAME (sym), FAKE_LABEL_NAME)) return xstrdup (".");