gas: Revert PR 32391 related commits to fix 3 regressions

9f2e3c21f6 Fix the handling or arguments and macro pseudo-variables inside nested assembler macros.

introduced 3 regressions of PR gas/32484, PR gas/32486 and PR gas/32487.
Revert all PR 32391 related commits and add tests for PR gas/32484,
PR gas/32486, PR gas/32487.

	PR gas/32484
	PR gas/32486
	PR gas/32487
	* testsuite/gas/macros/macros.exp: Run nesting1, nesting2 and
	nesting3.
	* testsuite/gas/macros/nesting1.d: New file.
	* testsuite/gas/macros/nesting1.s: Likewise.
	* testsuite/gas/macros/nesting2.d: Likewise.
	* testsuite/gas/macros/nesting2.s: Likewise.
	* testsuite/gas/macros/nesting3.d: Likewise.
	* testsuite/gas/macros/nesting3.s: Likewise.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
H.J. Lu
2025-01-02 06:09:30 +08:00
parent 434deed44d
commit f087e2e3f6
15 changed files with 126 additions and 445 deletions

View File

@@ -44,24 +44,11 @@
/* The macro hash table. */
/* Macro nesting depth. Similar to macro_nest defined in sb.c, but this
counter is specific to macros, whereas macro_nest also counts repeated
string blocks. */
static unsigned int macro_nesting_depth;
htab_t macro_hash;
/* Maximum nesting depth. Ideally the same as the value of max_macro_nest
as defined in as.c (ie 100). But there is one test in the assembler
testsuite (bfin/allinsn16.s) that nests macros to a depth of 8192. So
we have a ridiculously large number here. */
#define MAX_MACRO_DEPTH 8193
/* Whether any macros have been defined. */
static htab_t macro_hash[MAX_MACRO_DEPTH];
/* Whether any macros have been defined.
FIXME: This could be a counter that is incremented
with .macro and decremented with .purgem. */
static bool macros_defined = false;
int macro_defined;
/* Whether we should strip '@' characters. */
@@ -73,18 +60,6 @@ static unsigned int macro_number;
static void free_macro (macro_entry *);
bool
add_macro (macro_entry * macro, bool replace)
{
if (str_hash_insert (macro_hash [macro_nesting_depth],
macro->name, macro, replace) == NULL)
{
macros_defined = true;
return true;
}
return false;
}
static void
macro_del_f (void *ent)
{
@@ -97,23 +72,15 @@ macro_del_f (void *ent)
void
macro_init (void)
{
int i;
for (i = 0; i < MAX_MACRO_DEPTH; i++)
macro_hash[i] = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
macro_del_f, notes_calloc, NULL);
macros_defined = false;
macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
macro_del_f, notes_calloc, NULL);
macro_defined = 0;
}
void
macro_end (void)
{
int i;
for (i = MAX_MACRO_DEPTH; i--;)
htab_delete (macro_hash[i]);
macros_defined = false;
htab_delete (macro_hash);
}
/* Read input lines till we get to a TO string.
@@ -688,13 +655,6 @@ free_macro (macro_entry *macro)
free (macro);
}
static macro_entry * last_recorded_macro = NULL;
void
macro_record_invocation (macro_entry * macro)
{
last_recorded_macro = macro;
}
/* Define a new macro. */
macro_entry *
@@ -758,19 +718,15 @@ define_macro (sb *in, sb *label, size_t (*get_line) (sb *))
/* And stick it in the macro hash table. */
for (idx = 0; idx < name.len; idx++)
name.ptr[idx] = TOLOWER (name.ptr[idx]);
if (macro_nesting_depth > 0)
macro->parent = last_recorded_macro;
else
macro->parent = NULL;
if (!error)
{
if (! add_macro (macro, false))
if (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL)
error = _("Macro `%s' was already defined");
}
if (error != NULL)
if (!error)
macro_defined = 1;
else
{
as_bad_where (macro->file, macro->line, error, macro->name);
free_macro (macro);
@@ -794,25 +750,11 @@ get_apost_token (size_t idx, sb *in, sb *name, int kind)
return idx;
}
static const char *
macro_expand_body (sb *, sb *, formal_entry *, struct htab *,
const macro_entry *, unsigned int);
/* Find the actual value for a formal parameter starting at START inside IN.
Appends the value of parameter onto OUT.
The hash table of formal parameters is provided by FORMAL_HASH.
The character that indicated the presense of a formal parameter is passed
in KIND.
If COPYIFNOTTHERE is true and the parameter is not found in the hash table
then it is appended as plain text onto OUT.
The macro containing the formal parameters is passed in MACRO.
This can be empty.
Returns the offset inside IN after advanceing past the parameter.
Also stores the parameter's name into T. */
/* Substitute the actual value for a formal parameter. */
static size_t
sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
int kind, sb *out, int copyifnotthere, const macro_entry * macro)
int kind, sb *out, int copyifnotthere)
{
size_t src;
formal_entry *ptr;
@@ -826,12 +768,16 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
ptr = NULL;
else
ptr = str_hash_find (formal_hash, sb_terminate (t));
if (ptr)
{
sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
sb_add_sb (out, add);
if (ptr->actual.len)
{
sb_add_sb (out, &ptr->actual);
}
else
{
sb_add_sb (out, &ptr->def);
}
}
else if (kind == '&')
{
@@ -845,56 +791,6 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
{
sb_add_sb (out, t);
}
else if (!macro_strip_at
&& macro_nesting_depth > 0
&& macro != NULL
&& macro->parent != NULL)
{
const macro_entry * orig_macro = macro;
bool success = false;
/* We have failed to find T, but we are inside nested macros. So check
the parent macros so see if they have a FORMAL that matches T. */
while (macro->parent != NULL)
{
macro = macro->parent;
ptr = str_hash_find (macro->formal_hash, t->ptr);
if (ptr == NULL)
continue;
sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
/* The parent's FORMALs might contain parameters that need further
substitution. See gas/testsuite/gas/arm/macro-vld1.s for an
example of this. */
if (memchr (add->ptr, '\\', add->len))
{
sb newadd;
sb_new (&newadd);
/* FIXME: Should we do something if the call to
macro_expand_body returns an error message ? */
(void) macro_expand_body (add, &newadd, NULL, NULL,
orig_macro, orig_macro->count);
sb_add_sb (out, &newadd);
sb_kill (&newadd);
}
else
{
sb_add_sb (out, add);
}
success = true;
break;
}
if (! success)
{
/* We reached the outermost macro and failed to find T, so
just copy the entire parameter as is. */
sb_add_char (out, '\\');
sb_add_sb (out, t);
}
}
else
{
sb_add_char (out, '\\');
@@ -903,12 +799,7 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
return src;
}
/* Expands the body of a macro / block of text IN, copying it into OUT.
Parameters for substitution are found in FORMALS and FORMAL_HASH or
MACRO.
The number of times that this macro / block of text have already been
copied into the output is held in INSTANCE.
Returns NULL upon success or an error message otherwise. */
/* Expand the body of a macro. */
static const char *
macro_expand_body (sb *in, sb *out, formal_entry *formals,
@@ -920,38 +811,18 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
int inquote = 0, macro_line = 0;
formal_entry *loclist = NULL;
const char *err = NULL;
int nesting = 0;
if (formals == NULL && macro != NULL)
formals = macro->formals;
if (formal_hash == NULL && macro != NULL)
formal_hash = macro->formal_hash;
sb_new (&t);
while (src < in->len && !err)
{
if (in->ptr[src] == '.')
{
/* Check to see if we have encountered ".macro" or ".endm" */
if (in->len > src + 5
&& strncmp (in->ptr + src, ".macro", 6) == 0)
++ nesting;
else if (in->len > src + 4
&& strncmp (in->ptr + src, ".endm", 5) == 0)
-- nesting;
}
if (in->ptr[src] == '&')
{
sb_reset (&t);
if (flag_mri)
{
if (src + 1 < in->len && in->ptr[src + 1] == '&')
src = sub_actual (src + 2, in, &t, formal_hash,
'\'', out, 1, macro);
src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
else
sb_add_char (out, in->ptr[src++]);
}
@@ -959,8 +830,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
{
/* Permit macro parameter substitution delineated with
an '&' prefix and optional '&' suffix. */
src = sub_actual (src + 1, in, &t, formal_hash,
'&', out, 0, macro);
src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
}
}
else if (in->ptr[src] == '\\')
@@ -981,12 +851,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
else
as_bad_where (macro->file, macro->line + macro_line, _("missing `)'"));
}
else if (src < in->len
&& in->ptr[src] == '@'
/* PR 32391: Do not perform the substition inside nested
macros. Instead wait until they are re-evaluated and
perform the substition then. */
&& ! nesting)
else if (src < in->len && in->ptr[src] == '@')
{
/* Sub in the total macro invocation number. */
@@ -995,12 +860,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
sprintf (buffer, "%u", macro_number);
sb_add_string (out, buffer);
}
else if (src < in->len
&& in->ptr[src] == '+'
/* PR 32391: Do not perform the substition inside nested
macros. Instead wait until they are re-evaluated and
perform the substition then. */
&& ! nesting)
else if (src < in->len && in->ptr[src] == '+')
{
/* Sub in the current macro invocation number. */
@@ -1044,18 +904,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
else
{
sb_reset (&t);
if (nesting)
{
src = get_apost_token (src, in, &t, '\'');
sb_add_char (out, '\\');
sb_add_sb (out, &t);
}
else
{
src = sub_actual (src, in, &t, formal_hash,
'\'', out, 0, macro);
}
src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
}
}
else if ((flag_macro_alternate || flag_mri)
@@ -1074,7 +923,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
sb_reset (&t);
src = sub_actual (src, in, &t, formal_hash,
(macro_strip_at && inquote) ? '@' : '\'',
out, 1, macro);
out, 1);
}
else
{
@@ -1186,7 +1035,6 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
if (!err && (out->len == 0 || out->ptr[out->len - 1] != '\n'))
sb_add_char (out, '\n');
return err;
}
@@ -1371,7 +1219,8 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
}
}
err = macro_expand_body (&m->sub, out, NULL, NULL, m, m->count);
err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m,
m->count);
}
/* Discard any unnamed formal arguments. */
@@ -1404,22 +1253,20 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
}
/* Check for a macro. If one is found, put the expansion into
*EXPAND. Return TRUE if a macro is found, FALSE otherwise. */
*EXPAND. Return 1 if a macro is found, 0 otherwise. */
bool
int
check_macro (const char *line, sb *expand,
const char **error, macro_entry **info)
{
const char *s;
char *copy, *cls;
macro_entry *macro;
sb line_sb;
if (! macros_defined)
return false;
if (! is_name_beginner (*line)
&& (! flag_mri || *line != '.'))
return false;
return 0;
s = line + 1;
while (is_part_of_name (*s))
@@ -1431,17 +1278,11 @@ check_macro (const char *line, sb *expand,
for (cls = copy; *cls != '\0'; cls ++)
*cls = TOLOWER (*cls);
macro_entry *macro = NULL;
for (int i = macro_nesting_depth; i >= 0; i--)
{
macro = str_hash_find (macro_hash[i], copy);
if (macro != NULL)
break;
}
macro = str_hash_find (macro_hash, copy);
free (copy);
if (macro == NULL)
return false;
return 0;
/* Wrap the line up in an sb. */
sb_new (&line_sb);
@@ -1457,7 +1298,7 @@ check_macro (const char *line, sb *expand,
if (info)
*info = macro;
return true;
return 1;
}
/* Delete a macro. */
@@ -1475,20 +1316,11 @@ delete_macro (const char *name)
copy[i] = TOLOWER (name[i]);
copy[i] = '\0';
int j;
for (j = macro_nesting_depth; j >= 0; j--)
{
macro = str_hash_find (macro_hash [j], copy);
if (macro != NULL)
{
str_hash_delete (macro_hash[j], copy);
break;
}
}
if (j < 0)
macro = str_hash_find (macro_hash, copy);
if (macro != NULL)
str_hash_delete (macro_hash, copy);
else
as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
free (copy);
}
@@ -1590,25 +1422,3 @@ expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
return err;
}
void
increment_macro_nesting_depth (void)
{
if (macro_nesting_depth >= (MAX_MACRO_DEPTH - 1))
as_fatal (_("macros nested too deeply"));
else
++macro_nesting_depth;
}
void
decrement_macro_nesting_depth (void)
{
if (macro_nesting_depth == 0)
as_fatal (_("too much macro un-nesting"));
else
{
/* FIXME: Potential memory leak here. */
htab_empty (macro_hash [macro_nesting_depth]);
--macro_nesting_depth;
}
}