From eb6dce11fca29245eafdde890dbf46ee2e7661bf Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 8 Jul 2022 17:37:07 +0930 Subject: [PATCH] gas: tc-tic54x.c hash tables Cleaning up the subsym_hash memory is a real pain. Keys and values entered into the table are quite diverse. In some cases the key is allocated and thus needs to be freed, in others the key is a const string. Values are similar, and in some cases not even a string. Tidy this by inserting a new subsym_ent_t that describes key/value type. This meant the math_hash table was no longer needed. The patch also tidies how math functions are called, those that are supposed to return int now no longer return their value in a float. * config/tc-tic54x.c (math_hash): Delete. (subsym_proc_entry): Move earlier, make proc a union, merge with.. (math_proc_entry): ..this. Delete type. (math_procs): Merge into subsym_procs. (subsym_ent_t): New. Use this type in subsym_hash.. (stag_add_field_symbols, tic54x_var, tic54x_macro_info): ..here.. (md_begin, subsym_create_or_replace, subsym_lookup): ..and here.. (subsym_substitute): ..and here. Adjust subsym_proc_entry function calls. Free replacement when not returned. (subsym_get_arg): Adjust subsym_lookup. (free_subsym_ent, subsym_htab_create ): New functions, use when creating subsym_hash. (free_local_label_ent, local_label_htab_create): Similarly. (tic54x_remove_local_label): Delete. (tic54x_clear_local_labels): Simplify. (tic54x_asg): Use notes obstack to dup strings. (tic54x_eval): Likewise. (subsym_ismember): Likewise. (math_cvi, math_int, math_sgn): Return int. (tic54x_macro_start): Decrement macro_level before calling as_fatal. (tic54x_md_end): New function. * config/tc-tic54h.c (tic54x_md_end): Declare. (md_end): Define. --- gas/config/tc-tic54x.c | 359 +++++++++++++++++++++++++---------------- gas/config/tc-tic54x.h | 3 + 2 files changed, 223 insertions(+), 139 deletions(-) diff --git a/gas/config/tc-tic54x.c b/gas/config/tc-tic54x.c index ebefcf1c83c..9bc4fa57033 100644 --- a/gas/config/tc-tic54x.c +++ b/gas/config/tc-tic54x.c @@ -182,12 +182,35 @@ static symbolS *last_label_seen = NULL; static int local_label_id; static htab_t subsym_recurse_hash; /* Prevent infinite recurse. */ -static htab_t math_hash; /* Built-in math functions. */ /* Allow maximum levels of macro nesting; level 0 is the main substitution symbol table. The other assembler only does 32 levels, so there! */ #define MAX_SUBSYM_HASH 100 static htab_t subsym_hash[MAX_SUBSYM_HASH]; +typedef struct +{ + const char *name; + union { + int (*s) (char *, char *); + float (*f) (float, float); + int (*i) (float, float); + } proc; + int nargs; + int type; +} subsym_proc_entry; + +typedef struct { + union { + char *s; + const subsym_proc_entry *p; + } u; + unsigned int freekey : 1; + unsigned int freeval : 1; + unsigned int isproc : 1; + unsigned int ismath : 1; +} subsym_ent_t; + + /* Keep track of local labels so we can substitute them before GAS sees them since macros use their own 'namespace' for local labels, use a separate hash @@ -197,7 +220,7 @@ static htab_t subsym_hash[MAX_SUBSYM_HASH]; We use our own macro nesting counter, since GAS overloads it when expanding other things (like conditionals and repeat loops). */ static int macro_level = 0; -static htab_t local_label_hash[100]; +static htab_t local_label_hash[MAX_SUBSYM_HASH]; /* Keep track of struct/union tags. */ static htab_t stag_hash; static htab_t op_hash; @@ -223,7 +246,7 @@ static htab_t misc_symbol_hash; static void subsym_create_or_replace (char *, char *); -static char *subsym_lookup (char *, int); +static subsym_ent_t *subsym_lookup (char *, int); static char *subsym_substitute (char *, int); @@ -334,6 +357,7 @@ tic54x_asg (int x ATTRIBUTE_UNUSED) } else { + size_t len; str = input_line_pointer; while ((c = *input_line_pointer) != ',') { @@ -341,28 +365,30 @@ tic54x_asg (int x ATTRIBUTE_UNUSED) break; ++input_line_pointer; } - *input_line_pointer = 0; + len = input_line_pointer - str; + str = notes_memdup (str, len, len + 1); } if (c != ',') { as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'")); + notes_free (str); ignore_rest_of_line (); return; } ++input_line_pointer; c = get_symbol_name (&name); /* Get terminator. */ + name = notes_strdup (name); + (void) restore_line_pointer (c); if (!ISALPHA (*name)) { as_bad (_("symbols assigned with .asg must begin with a letter")); + notes_free (str); ignore_rest_of_line (); return; } - str = xstrdup (str); - name = xstrdup (name); subsym_create_or_replace (name, str); - (void) restore_line_pointer (c); demand_empty_rest_of_line (); } @@ -407,15 +433,17 @@ tic54x_eval (int x ATTRIBUTE_UNUSED) return; } c = get_symbol_name (&name); /* Get terminator. */ - name = xstrdup (name); - (void) restore_line_pointer (c); if (!ISALPHA (*name)) { as_bad (_("symbols assigned with .eval must begin with a letter")); + (void) restore_line_pointer (c); ignore_rest_of_line (); return; } + name = notes_strdup (name); + (void) restore_line_pointer (c); + symbolP = symbol_new (name, absolute_section, &zero_address_frag, value); SF_SET_LOCAL (symbolP); symbol_table_insert (symbolP); @@ -424,7 +452,7 @@ tic54x_eval (int x ATTRIBUTE_UNUSED) But since there's not written rule as to when, don't even bother trying to match their behavior. */ sprintf (valuestr, "%d", value); - tmp = xstrdup (valuestr); + tmp = notes_strdup (valuestr); subsym_create_or_replace (name, tmp); demand_empty_rest_of_line (); @@ -564,11 +592,14 @@ stag_add_field_symbols (struct stag *stag, } else { - char *replacement; - - replacement = concat (S_GET_NAME (rootsym), "+", root_stag_name, - name + strlen (S_GET_NAME (rootsym)), NULL); - str_hash_insert (subsym_hash[0], name, replacement, 0); + subsym_ent_t *ent = xmalloc (sizeof (*ent)); + ent->u.s = concat (S_GET_NAME (rootsym), "+", root_stag_name, + name + strlen (S_GET_NAME (rootsym)), NULL); + ent->freekey = 1; + ent->freeval = 1; + ent->isproc = 0; + ent->ismath = 0; + str_hash_insert (subsym_hash[0], name, ent, 0); freename = NULL; } @@ -1115,16 +1146,40 @@ tic54x_global (int type) demand_empty_rest_of_line (); } -/* Remove the symbol from the local label hash lookup. */ +static void +free_subsym_ent (void *ent) +{ + string_tuple_t *tuple = (string_tuple_t *) ent; + subsym_ent_t *val = (void *) tuple->value; + if (val->freekey) + free ((void *) tuple->key); + if (val->freeval) + free (val->u.s); + free (val); + free (ent); +} -static int -tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED) +static htab_t +subsym_htab_create (void) { - string_tuple_t *tuple = *((string_tuple_t **) slot); - void *elem = str_hash_find (local_label_hash[macro_level], tuple->key); - str_hash_delete (local_label_hash[macro_level], tuple->key); - free (elem); - return 0; + return htab_create_alloc (16, hash_string_tuple, eq_string_tuple, + free_subsym_ent, xcalloc, free); +} + +static void +free_local_label_ent (void *ent) +{ + string_tuple_t *tuple = (string_tuple_t *) ent; + free ((void *) tuple->key); + free ((void *) tuple->value); + free (ent); +} + +static htab_t +local_label_htab_create (void) +{ + return htab_create_alloc (16, hash_string_tuple, eq_string_tuple, + free_local_label_ent, xcalloc, free); } /* Reset all local labels. */ @@ -1132,7 +1187,7 @@ tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED) static void tic54x_clear_local_labels (int ignored ATTRIBUTE_UNUSED) { - htab_traverse (local_label_hash[macro_level], tic54x_remove_local_label, NULL); + htab_empty (local_label_hash[macro_level]); } /* .text @@ -2215,7 +2270,6 @@ tic54x_sslist (int show) static void tic54x_var (int ignore ATTRIBUTE_UNUSED) { - static char empty[] = ""; char *name; int c; @@ -2236,10 +2290,17 @@ tic54x_var (int ignore ATTRIBUTE_UNUSED) return; } c = get_symbol_name (&name); - /* .var symbols start out with a null string. */ name = xstrdup (name); - str_hash_insert (subsym_hash[macro_level], name, empty, 0); c = restore_line_pointer (c); + + /* .var symbols start out with a null string. */ + subsym_ent_t *ent = xmalloc (sizeof (*ent)); + ent->u.s = (char *) ""; + ent->freekey = 1; + ent->freeval = 0; + ent->isproc = 0; + ent->ismath = 0; + str_hash_insert (subsym_hash[macro_level], name, ent, 0); if (c == ',') { ++input_line_pointer; @@ -2503,11 +2564,12 @@ tic54x_macro_start (void) { if (++macro_level >= MAX_SUBSYM_HASH) { + --macro_level; as_fatal (_("Macro nesting is too deep")); return; } - subsym_hash[macro_level] = str_htab_create (); - local_label_hash[macro_level] = str_htab_create (); + subsym_hash[macro_level] = subsym_htab_create (); + local_label_hash[macro_level] = local_label_htab_create (); } void @@ -2519,11 +2581,14 @@ tic54x_macro_info (const macro_entry *macro) for (entry = macro->formals; entry; entry = entry->next) { char *name = xstrndup (entry->name.ptr, entry->name.len); - char *value = xstrndup (entry->actual.ptr, entry->actual.len); + subsym_ent_t *ent = xmalloc (sizeof (*ent)); - name[entry->name.len] = '\0'; - value[entry->actual.len] = '\0'; - str_hash_insert (subsym_hash[macro_level], name, value, 0); + ent->u.s = xstrndup (entry->actual.ptr, entry->actual.len); + ent->freekey = 1; + ent->freeval = 1; + ent->isproc = 0; + ent->ismath = 0; + str_hash_insert (subsym_hash[macro_level], name, ent, 0); } } @@ -2594,20 +2659,21 @@ subsym_isdefed (char *a, char *ignore ATTRIBUTE_UNUSED) static int subsym_ismember (char *sym, char *list) { - char *elem, *ptr, *listv; + char *elem, *ptr; + subsym_ent_t *listv; if (!list) return 0; listv = subsym_lookup (list, macro_level); - if (!listv) + if (!listv || listv->isproc) { as_bad (_("Undefined substitution symbol '%s'"), list); ignore_rest_of_line (); return 0; } - ptr = elem = xstrdup (listv); + ptr = elem = notes_strdup (listv->u.s); while (*ptr && *ptr != ',') ++ptr; *ptr++ = 0; @@ -2728,7 +2794,7 @@ math_ceil (float arg1, float ignore ATTRIBUTE_UNUSED) return (float) ceil (arg1); } -static float +static int math_cvi (float arg1, float ignore ATTRIBUTE_UNUSED) { return (int) arg1; @@ -2746,10 +2812,10 @@ math_fmod (float arg1, float arg2) return (int) arg1 % (int) arg2; } -static float +static int math_int (float arg1, float ignore ATTRIBUTE_UNUSED) { - return ((float) ((int) arg1)) == arg1; + return arg1 == (float) (int) arg1; } static float @@ -2758,10 +2824,10 @@ math_round (float arg1, float ignore ATTRIBUTE_UNUSED) return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5); } -static float +static int math_sgn (float arg1, float ignore ATTRIBUTE_UNUSED) { - return (arg1 < 0) ? -1 : (arg1 ? 1 : 0); + return arg1 < 0.0f ? -1 : arg1 != 0.0f ? 1 : 0; } static float @@ -2893,72 +2959,53 @@ math_tanh (float arg1, float ignore ATTRIBUTE_UNUSED) } /* Built-in substitution symbol functions and math functions. */ -typedef struct -{ - const char *name; - int (*proc) (char *, char *); - int nargs; -} subsym_proc_entry; - static const subsym_proc_entry subsym_procs[] = { /* Assembler built-in string substitution functions. */ - { "$symlen", subsym_symlen, 1, }, - { "$symcmp", subsym_symcmp, 2, }, - { "$firstch", subsym_firstch, 2, }, - { "$lastch", subsym_lastch, 2, }, - { "$isdefed", subsym_isdefed, 1, }, - { "$ismember", subsym_ismember, 2, }, - { "$iscons", subsym_iscons, 1, }, - { "$isname", subsym_isname, 1, }, - { "$isreg", subsym_isreg, 1, }, - { "$structsz", subsym_structsz, 1, }, - { "$structacc", subsym_structacc, 1, }, - { NULL, NULL, 0 }, -}; - -typedef struct -{ - const char *name; - float (*proc) (float, float); - int nargs; - int int_return; -} math_proc_entry; + { "$symlen", { .s = subsym_symlen }, 1, 0 }, + { "$symcmp", { .s = subsym_symcmp }, 2, 0 }, + { "$firstch", { .s = subsym_firstch }, 2, 0 }, + { "$lastch", { .s = subsym_lastch }, 2, 0 }, + { "$isdefed", { .s = subsym_isdefed }, 1, 0 }, + { "$ismember", { .s = subsym_ismember }, 2, 0 }, + { "$iscons", { .s = subsym_iscons }, 1, 0 }, + { "$isname", { .s = subsym_isname }, 1, 0 }, + { "$isreg", { .s = subsym_isreg }, 1, 0 }, + { "$structsz", { .s = subsym_structsz }, 1, 0 }, + { "$structacc", { .s = subsym_structacc }, 1, 0 }, -static const math_proc_entry math_procs[] = -{ /* Integer-returning built-in math functions. */ - { "$cvi", math_cvi, 1, 1 }, - { "$int", math_int, 1, 1 }, - { "$sgn", math_sgn, 1, 1 }, + { "$cvi", { .i = math_cvi }, 1, 2 }, + { "$int", { .i = math_int }, 1, 2 }, + { "$sgn", { .i = math_sgn }, 1, 2 }, /* Float-returning built-in math functions. */ - { "$acos", math_acos, 1, 0 }, - { "$asin", math_asin, 1, 0 }, - { "$atan", math_atan, 1, 0 }, - { "$atan2", math_atan2, 2, 0 }, - { "$ceil", math_ceil, 1, 0 }, - { "$cosh", math_cosh, 1, 0 }, - { "$cos", math_cos, 1, 0 }, - { "$cvf", math_cvf, 1, 0 }, - { "$exp", math_exp, 1, 0 }, - { "$fabs", math_fabs, 1, 0 }, - { "$floor", math_floor, 1, 0 }, - { "$fmod", math_fmod, 2, 0 }, - { "$ldexp", math_ldexp, 2, 0 }, - { "$log10", math_log10, 1, 0 }, - { "$log", math_log, 1, 0 }, - { "$max", math_max, 2, 0 }, - { "$min", math_min, 2, 0 }, - { "$pow", math_pow, 2, 0 }, - { "$round", math_round, 1, 0 }, - { "$sin", math_sin, 1, 0 }, - { "$sinh", math_sinh, 1, 0 }, - { "$sqrt", math_sqrt, 1, 0 }, - { "$tan", math_tan, 1, 0 }, - { "$tanh", math_tanh, 1, 0 }, - { "$trunc", math_trunc, 1, 0 }, - { NULL, NULL, 0, 0 }, + { "$acos", { .f = math_acos }, 1, 1 }, + { "$asin", { .f = math_asin }, 1, 1 }, + { "$atan", { .f = math_atan }, 1, 1 }, + { "$atan2", { .f = math_atan2 }, 2, 1 }, + { "$ceil", { .f = math_ceil }, 1, 1 }, + { "$cosh", { .f = math_cosh }, 1, 1 }, + { "$cos", { .f = math_cos }, 1, 1 }, + { "$cvf", { .f = math_cvf }, 1, 1 }, + { "$exp", { .f = math_exp }, 1, 1 }, + { "$fabs", { .f = math_fabs }, 1, 1 }, + { "$floor", { .f = math_floor }, 1, 1 }, + { "$fmod", { .f = math_fmod }, 2, 1 }, + { "$ldexp", { .f = math_ldexp }, 2, 1 }, + { "$log10", { .f = math_log10 }, 1, 1 }, + { "$log", { .f = math_log }, 1, 1 }, + { "$max", { .f = math_max }, 2, 1 }, + { "$min", { .f = math_min }, 2, 1 }, + { "$pow", { .f = math_pow }, 2, 1 }, + { "$round", { .f = math_round }, 1, 1 }, + { "$sin", { .f = math_sin }, 1, 1 }, + { "$sinh", { .f = math_sinh }, 1, 1 }, + { "$sqrt", { .f = math_sqrt }, 1, 1 }, + { "$tan", { .f = math_tan }, 1, 1 }, + { "$tanh", { .f = math_tanh }, 1, 1 }, + { "$trunc", { .f = math_trunc }, 1, 1 }, + { NULL, { NULL }, 0, 0 }, }; void @@ -2967,7 +3014,6 @@ md_begin (void) insn_template *tm; const tic54x_symbol *sym; const subsym_proc_entry *subsym_proc; - const math_proc_entry *math_proc; const char **symname; char *TIC54X_DIR = getenv ("TIC54X_DIR"); char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR"); @@ -3037,23 +3083,41 @@ md_begin (void) /* Only the base substitution table and local label table are initialized; the others (for local macro substitution) get instantiated as needed. */ - local_label_hash[0] = str_htab_create (); - subsym_hash[0] = str_htab_create (); + local_label_hash[0] = local_label_htab_create (); + subsym_hash[0] = subsym_htab_create (); for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++) - str_hash_insert (subsym_hash[0], subsym_proc->name, subsym_proc, 0); - - math_hash = str_htab_create (); - for (math_proc = math_procs; math_proc->name; math_proc++) { - /* Insert into the main subsym hash for recognition; insert into - the math hash to actually store information. */ - str_hash_insert (subsym_hash[0], math_proc->name, math_proc, 0); - str_hash_insert (math_hash, math_proc->name, math_proc, 0); + subsym_ent_t *ent = xmalloc (sizeof (*ent)); + ent->u.p = subsym_proc; + ent->freekey = 0; + ent->freeval = 0; + ent->isproc = 1; + ent->ismath = subsym_proc->type != 0; + str_hash_insert (subsym_hash[0], subsym_proc->name, ent, 0); } subsym_recurse_hash = str_htab_create (); stag_hash = str_htab_create (); } +void +tic54x_md_end (void) +{ + htab_delete (stag_hash); + htab_delete (subsym_recurse_hash); + while (macro_level != -1) + tic54x_macro_end (); + macro_level = 0; + htab_delete (misc_symbol_hash); + htab_delete (sbit_hash); + htab_delete (cc3_hash); + htab_delete (cc2_hash); + htab_delete (cc_hash); + htab_delete (mmreg_hash); + htab_delete (reg_hash); + htab_delete (parop_hash); + htab_delete (op_hash); +} + static int is_accumulator (struct opstruct *operand) { @@ -4295,7 +4359,6 @@ subsym_get_arg (char *line, const char *terminators, char **str, int nosub) else { const char *term = terminators; - char *value = NULL; while (*ptr && *ptr != *term) { @@ -4310,8 +4373,12 @@ subsym_get_arg (char *line, const char *terminators, char **str, int nosub) endp = ptr; *str = xmemdup0 (line, ptr - line); /* Do simple substitution, if available. */ - if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL) - *str = value; + if (!nosub) + { + subsym_ent_t *ent = subsym_lookup (*str, macro_level); + if (ent && !ent->isproc) + *str = ent->u.s; + } } return endp; @@ -4326,24 +4393,30 @@ static void subsym_create_or_replace (char *name, char *value) { int i; + subsym_ent_t *ent = xmalloc (sizeof (*ent)); + ent->u.s = value; + ent->freekey = 0; + ent->freeval = 0; + ent->isproc = 0; + ent->ismath = 0; for (i = macro_level; i > 0; i--) if (str_hash_find (subsym_hash[i], name)) { - str_hash_insert (subsym_hash[i], name, value, 1); + str_hash_insert (subsym_hash[i], name, ent, 1); return; } - str_hash_insert (subsym_hash[0], name, value, 1); + str_hash_insert (subsym_hash[0], name, ent, 1); } /* Look up the substitution string replacement for the given symbol. Start with the innermost macro substitution table given and work outwards. */ -static char * +static subsym_ent_t * subsym_lookup (char *name, int nest_level) { - char *value = str_hash_find (subsym_hash[nest_level], name); + void *value = str_hash_find (subsym_hash[nest_level], name); if (value || nest_level == 0) return value; @@ -4374,11 +4447,7 @@ subsym_substitute (char *line, int forced) int recurse = 1; int line_conditional = 0; char *tmp; - - /* Work with a copy of the input line. */ - replacement = xstrdup (line); - - ptr = head = replacement; + unsigned char current_char; /* Flag lines where we might need to replace a single '=' with two; GAS uses single '=' to assign macro args values, and possibly other @@ -4398,7 +4467,10 @@ subsym_substitute (char *line, int forced) if (strstr (line, ".macro")) return line; - unsigned char current_char; + /* Work with a copy of the input line. */ + replacement = xstrdup (line); + ptr = head = replacement; + while (!is_end_of_line[(current_char = * (unsigned char *) ptr)]) { /* Need to update this since LINE may have been modified. */ @@ -4445,6 +4517,7 @@ subsym_substitute (char *line, int forced) char *name; /* Symbol to be replaced. */ char *savedp = input_line_pointer; int c; + subsym_ent_t *ent = NULL; char *value = NULL; char *tail; /* Rest of line after symbol. */ @@ -4465,7 +4538,11 @@ subsym_substitute (char *line, int forced) /* Avoid infinite recursion; if a symbol shows up a second time for substitution, leave it as is. */ if (str_hash_find (subsym_recurse_hash, name) == NULL) - value = subsym_lookup (name, macro_level); + { + ent = subsym_lookup (name, macro_level); + if (ent && !ent->isproc) + value = ent->u.s; + } else as_warn (_("%s symbol recursion stopped at " "second appearance of '%s'"), @@ -4499,14 +4576,13 @@ subsym_substitute (char *line, int forced) ptr = tail; } /* Check for built-in subsym and math functions. */ - else if (value != NULL && *name == '$') + else if (ent != NULL && *name == '$') { - subsym_proc_entry *entry = (subsym_proc_entry *) value; - math_proc_entry *math_entry = str_hash_find (math_hash, name); + const subsym_proc_entry *entry = ent->u.p; char *arg1, *arg2 = NULL; *ptr = c; - if (entry == NULL) + if (!ent->isproc) { as_bad (_("Unrecognized substitution symbol function")); break; @@ -4517,13 +4593,12 @@ subsym_substitute (char *line, int forced) break; } ++ptr; - if (math_entry != NULL) + if (ent->ismath) { float farg1, farg2 = 0; - volatile float fresult; farg1 = (float) strtod (ptr, &ptr); - if (math_entry->nargs == 2) + if (entry->nargs == 2) { if (*ptr++ != ',') { @@ -4532,12 +4607,17 @@ subsym_substitute (char *line, int forced) } farg2 = (float) strtod (ptr, &ptr); } - fresult = (*math_entry->proc) (farg1, farg2); value = XNEWVEC (char, 128); - if (math_entry->int_return) - sprintf (value, "%d", (int) fresult); + if (entry->type == 2) + { + int result = (*entry->proc.i) (farg1, farg2); + sprintf (value, "%d", result); + } else - sprintf (value, "%f", fresult); + { + float result = (*entry->proc.f) (farg1, farg2); + sprintf (value, "%f", result); + } if (*ptr++ != ')') { as_bad (_("Extra junk in function call, expecting ')'")); @@ -4593,7 +4673,7 @@ subsym_substitute (char *line, int forced) as_bad (_("Extra junk in function call, expecting ')'")); break; } - val = (*entry->proc) (arg1, arg2); + val = (*entry->proc.s) (arg1, arg2); value = XNEWVEC (char, 64); sprintf (value, "%d", val); } @@ -4703,8 +4783,9 @@ subsym_substitute (char *line, int forced) if (changed) return replacement; - else - return line; + + free (replacement); + return line; } /* We use this to handle substitution symbols diff --git a/gas/config/tc-tic54x.h b/gas/config/tc-tic54x.h index d32e0bc095b..431895d1e4e 100644 --- a/gas/config/tc-tic54x.h +++ b/gas/config/tc-tic54x.h @@ -131,4 +131,7 @@ extern void tic54x_convert_frag(bfd *, segT, fragS *); extern void tic54x_global (int); +extern void tic54x_md_end (void); +#define md_end tic54x_md_end + #endif -- 2.30.2