1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2019 The NASM Authors - All Rights Reserved */
/*
* Parse and handle [pragma] directives. The preprocessor handles
* %pragma preproc directives separately, all other namespaces are
* simply converted to [pragma].
*/
#include "compiler.h"
#include "nctype.h"
#include "nasm.h"
#include "nasmlib.h"
#include "assemble.h"
#include "error.h"
#include "listing.h"
static enum directive_result ignore_pragma(const struct pragma *pragma);
static enum directive_result output_pragma(const struct pragma *pragma);
static enum directive_result debug_pragma(const struct pragma *pragma);
static enum directive_result limit_pragma(const struct pragma *pragma);
/*
* Handle [pragma] directives. [pragma] is generally produced by
* the %pragma preprocessor directive, which simply passes on any
* string that it finds *except* %pragma preproc. The idea is
* that pragmas are of the form:
*
* %pragma <facility> <opname> [<options>...]
*
* ... where "facility" can be either a generic facility or a backend
* name.
*
* The following names are currently reserved for global facilities;
* so far none of these have any defined pragmas at all:
*
* preproc - preprocessor
* limit - limit setting
* asm - assembler
* list - listing generator
* file - generic file handling
* input - input file handling
* output - backend-independent output handling
* debug - backend-independent debug handling
* ignore - dummy pragma (can be used to "comment out")
*
* This function should generally not error out if it doesn't understand
* what a pragma is for, for unknown arguments, etc; the whole point of
* a pragma is that future releases might add new ones that should be
* ignored rather than be an error. Erroring out is acceptable for
* known pragmas suffering from parsing errors and so on.
*
* Adding default-suppressed warnings would, however, be a good idea
* at some point.
*/
static struct pragma_facility global_pragmas[] =
{
{ "asm", NULL },
{ "limit", limit_pragma },
{ "list", list_pragma },
{ "file", NULL },
{ "input", NULL },
{ "output", output_pragma },
{ "debug", debug_pragma },
{ "ignore", ignore_pragma },
/* This will never actually get this far... */
{ "preproc", NULL }, /* Handled in the preprocessor by necessity */
{ NULL, NULL }
};
/*
* Invoke a pragma handler
*/
static enum directive_result
call_pragma(const struct pragma_facility *pf, struct pragma *pragma)
{
if (!pf || !pf->handler)
return DIRR_UNKNOWN;
pragma->facility = pf;
return pf->handler(pragma);
}
/*
* Search a pragma list for a known pragma facility and if so, invoke
* the handler. Return true if processing is complete. The "default
* name", *or def->name*, if set, matches the final NULL entry (used
* for backends, so multiple backends can share the same list under
* some circumstances, and the backends can implement common operations.)
*/
static enum directive_result
search_pragma_list(const struct pragma_facility *list,
const char *defaultname,
const struct pragma_facility *def,
const struct pragma *cpragma)
{
const struct pragma_facility *pf = NULL;
enum directive_result rv;
bool facility_match, is_default;
struct pragma pragma = *cpragma;
const char *facname = pragma.facility_name;
/* Is there a default facility and we match its name? */
is_default = def && def->name && !nasm_stricmp(facname, def->name);
facility_match = is_default;
/*
* Promote def->name to defaultname if both are set. This handles
* e.g. output -> elf32 so that we can handle elf32-specific
* directives in that handler.
*/
if (defaultname) {
if (is_default)
facname = defaultname;
else
facility_match = !nasm_stricmp(facname, defaultname);
}
if (facname && list) {
for (pf = list; pf->name; pf++) {
if (!nasm_stricmp(facname, pf->name)) {
facility_match = true;
rv = call_pragma(pf, &pragma);
if (rv != DIRR_UNKNOWN)
goto found_it;
}
}
if (facility_match) {
/*
* Facility name match but no matching directive; handler in NULL
* entry at end of list?
*/
rv = call_pragma(pf, &pragma);
if (rv != DIRR_UNKNOWN)
goto found_it;
}
}
if (facility_match) {
/*
* Facility match but still nothing: def->handler if it exists
*/
rv = call_pragma(def, &pragma);
} else {
/*
* No facility matched
*/
return DIRR_UNKNOWN;
}
/*
* Otherwise we found the facility but not any supported directive,
* fall through...
*/
found_it:
switch (rv) {
case DIRR_UNKNOWN:
switch (pragma.opcode) {
case D_none:
nasm_warn(ERR_PASS2|WARN_PRAGMA_BAD,
"empty %%pragma %s", pragma.facility_name);
break;
default:
nasm_warn(ERR_PASS2|WARN_PRAGMA_UNKNOWN,
"unknown %%pragma %s %s",
pragma.facility_name, pragma.opname);
break;
}
rv = DIRR_ERROR; /* Already printed an error message */
break;
case DIRR_OK:
case DIRR_ERROR:
break; /* Nothing to do */
case DIRR_BADPARAM:
/*
* This one is an error. Don't use it if forward compatibility
* would be compromised, as opposed to an inherent error.
*/
nasm_error(ERR_NONFATAL, "bad argument to %%pragma %s %s",
pragma.facility_name, pragma.opname);
break;
default:
panic();
}
return rv;
}
/* Naked %pragma */
void process_pragma(char *str)
{
const struct pragma_facility *pf;
struct pragma pragma;
char *p;
nasm_zero(pragma);
pragma.facility_name = nasm_get_word(str, &p);
if (!pragma.facility_name) {
/* Empty %pragma */
nasm_warn(ERR_PASS2|WARN_PRAGMA_EMPTY,
"empty %%pragma directive, ignored");
return;
}
pragma.opname = nasm_get_word(p, &p);
if (!pragma.opname)
pragma.opcode = D_none;
else
pragma.opcode = directive_find(pragma.opname);
/*
* This used to use nasm_trim_spaces, but that assumes a single word.
* Instead, strip spaces at either end of the directive, but allow
* interior spaces.
*/
p = nasm_zap_spaces_fwd(p);
pragma.tail = p;
p += strlen(p);
while (p > pragma.tail && nasm_isspace(p[-1]))
*--p = 0;
/*
* Search the global pragma namespaces. This is done
* as a loop rather than letting search_pragma_list()
* just run, because we don't want to keep searching if
* we have a facility match, thus we want to call
* search_pragma_list() individually for each namespace.
*/
for (pf = global_pragmas; pf->name; pf++) {
if (search_pragma_list(NULL, NULL, pf, &pragma) != DIRR_UNKNOWN)
return;
}
/* Is it an output pragma? */
if (output_pragma(&pragma) != DIRR_UNKNOWN)
return;
/* Is it a debug pragma */
if (debug_pragma(&pragma) != DIRR_UNKNOWN)
return;
/*
* Note: it would be nice to warn for an unknown namespace,
* but in order to do so we need to walk *ALL* the backends
* in order to make sure we aren't dealing with a pragma that
* is for another backend. On the other hand, that could
* also be a warning with a separate warning flag.
*
* Leave this for the future, however, the warning classes are
* already defined for future compatibility.
*/
}
/* %pragma ignore */
static enum directive_result ignore_pragma(const struct pragma *pragma)
{
(void)pragma;
return DIRR_OK; /* Even for D_none! */
}
/*
* Process output and debug pragmas, by either list name or generic
* name. Note that the output/debug format list can hook the default
* names if they so choose.
*/
static enum directive_result output_pragma_common(const struct pragma *);
static enum directive_result output_pragma(const struct pragma *pragma)
{
static const struct pragma_facility
output_pragma_def = { "output", output_pragma_common };
return search_pragma_list(ofmt->pragmas, ofmt->shortname,
&output_pragma_def, pragma);
}
/* Generic pragmas that apply to all output backends */
static enum directive_result output_pragma_common(const struct pragma *pragma)
{
switch (pragma->opcode) {
case D_PREFIX:
case D_GPREFIX:
case D_SUFFIX:
case D_GSUFFIX:
case D_POSTFIX:
case D_GPOSTFIX:
case D_LPREFIX:
case D_LSUFFIX:
case D_LPOSTFIX:
set_label_mangle(pragma->opcode, pragma->tail);
return DIRR_OK;
default:
return DIRR_UNKNOWN;
}
}
static enum directive_result debug_pragma(const struct pragma *pragma)
{
static const struct pragma_facility
debug_pragma_def = { "debug", NULL };
return search_pragma_list(dfmt->pragmas, dfmt->shortname,
&debug_pragma_def, pragma);
}
/*
* %pragma limit to set resource limits
*/
static enum directive_result limit_pragma(const struct pragma *pragma)
{
return nasm_set_limit(pragma->opname, pragma->tail);
}
|