1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 1996-2019 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33 
34 /*
35  * Parse and handle [pragma] directives.  The preprocessor handles
36  * %pragma preproc directives separately, all other namespaces are
37  * simply converted to [pragma].
38  */
39 
40 #include "compiler.h"
41 
42 #include "nctype.h"
43 
44 #include "nasm.h"
45 #include "nasmlib.h"
46 #include "assemble.h"
47 #include "error.h"
48 #include "listing.h"
49 
50 static enum directive_result ignore_pragma(const struct pragma *pragma);
51 static enum directive_result output_pragma(const struct pragma *pragma);
52 static enum directive_result debug_pragma(const struct pragma *pragma);
53 static enum directive_result limit_pragma(const struct pragma *pragma);
54 
55 /*
56  * Handle [pragma] directives.  [pragma] is generally produced by
57  * the %pragma preprocessor directive, which simply passes on any
58  * string that it finds *except* %pragma preproc.  The idea is
59  * that pragmas are of the form:
60  *
61  * %pragma <facility> <opname> [<options>...]
62  *
63  * ... where "facility" can be either a generic facility or a backend
64  * name.
65  *
66  * The following names are currently reserved for global facilities;
67  * so far none of these have any defined pragmas at all:
68  *
69  * preproc	- preprocessor
70  * limit	- limit setting
71  * asm		- assembler
72  * list		- listing generator
73  * file		- generic file handling
74  * input	- input file handling
75  * output	- backend-independent output handling
76  * debug	- backend-independent debug handling
77  * ignore	- dummy pragma (can be used to "comment out")
78  *
79  * This function should generally not error out if it doesn't understand
80  * what a pragma is for, for unknown arguments, etc; the whole point of
81  * a pragma is that future releases might add new ones that should be
82  * ignored rather than be an error.  Erroring out is acceptable for
83  * known pragmas suffering from parsing errors and so on.
84  *
85  * Adding default-suppressed warnings would, however, be a good idea
86  * at some point.
87  */
88 static struct pragma_facility global_pragmas[] =
89 {
90     { "asm",		NULL },
91     { "limit",          limit_pragma },
92     { "list",		list_pragma },
93     { "file",		NULL },
94     { "input",		NULL },
95     { "output",		output_pragma },
96     { "debug",	        debug_pragma },
97     { "ignore",		ignore_pragma },
98 
99     /* This will never actually get this far... */
100     { "preproc",	NULL }, /* Handled in the preprocessor by necessity */
101     { NULL, NULL }
102 };
103 
104 /*
105  * Invoke a pragma handler
106  */
107 static enum directive_result
call_pragma(const struct pragma_facility * pf,struct pragma * pragma)108 call_pragma(const struct pragma_facility *pf, struct pragma *pragma)
109 {
110     if (!pf || !pf->handler)
111         return DIRR_UNKNOWN;
112 
113     pragma->facility = pf;
114     return pf->handler(pragma);
115 }
116 
117 /*
118  * Search a pragma list for a known pragma facility and if so, invoke
119  * the handler.  Return true if processing is complete.  The "default
120  * name", *or def->name*, if set, matches the final NULL entry (used
121  * for backends, so multiple backends can share the same list under
122  * some circumstances, and the backends can implement common operations.)
123  */
124 static enum directive_result
search_pragma_list(const struct pragma_facility * list,const char * defaultname,const struct pragma_facility * def,const struct pragma * cpragma)125 search_pragma_list(const struct pragma_facility *list,
126                    const char *defaultname,
127                    const struct pragma_facility *def,
128                    const struct pragma *cpragma)
129 {
130     const struct pragma_facility *pf = NULL;
131     enum directive_result rv;
132     bool facility_match, is_default;
133     struct pragma pragma = *cpragma;
134     const char *facname = pragma.facility_name;
135 
136     /* Is there a default facility and we match its name? */
137     is_default = def && def->name && !nasm_stricmp(facname, def->name);
138     facility_match = is_default;
139 
140     /*
141      * Promote def->name to defaultname if both are set. This handles
142      * e.g. output -> elf32 so that we can handle elf32-specific
143      * directives in that handler.
144      */
145     if (defaultname) {
146         if (is_default)
147             facname = defaultname;
148         else
149             facility_match = !nasm_stricmp(facname, defaultname);
150     }
151 
152     if (facname && list) {
153         for (pf = list; pf->name; pf++) {
154             if (!nasm_stricmp(facname, pf->name)) {
155                 facility_match = true;
156                 rv = call_pragma(pf, &pragma);
157                 if (rv != DIRR_UNKNOWN)
158                     goto found_it;
159             }
160         }
161 
162         if (facility_match) {
163             /*
164              * Facility name match but no matching directive; handler in NULL
165              * entry at end of list?
166              */
167             rv = call_pragma(pf, &pragma);
168             if (rv != DIRR_UNKNOWN)
169                 goto found_it;
170         }
171     }
172 
173     if (facility_match) {
174         /*
175          * Facility match but still nothing: def->handler if it exists
176          */
177         rv = call_pragma(def, &pragma);
178     } else {
179         /*
180          * No facility matched
181          */
182         return DIRR_UNKNOWN;
183     }
184 
185     /*
186      * Otherwise we found the facility but not any supported directive,
187      * fall through...
188      */
189 
190 found_it:
191     switch (rv) {
192     case DIRR_UNKNOWN:
193         switch (pragma.opcode) {
194         case D_none:
195             /*!
196              *!pragma-bad [off] malformed %pragma
197              *!=bad-pragma
198              *!  warns about a malformed or otherwise unparsable
199              *!  \c{%pragma} directive.
200              */
201             nasm_warn(ERR_PASS2|WARN_PRAGMA_BAD,
202                        "empty %%pragma %s", pragma.facility_name);
203             break;
204         default:
205             /*!
206              *!pragma-unknown [off] unknown %pragma facility or directive
207              *!=unknown-pragma
208              *!  warns about an unknown \c{%pragma} directive.
209              *!  This is not yet implemented for most cases.
210              */
211             nasm_warn(ERR_PASS2|WARN_PRAGMA_UNKNOWN,
212                        "unknown %%pragma %s %s",
213                        pragma.facility_name, pragma.opname);
214             break;
215         }
216         rv = DIRR_ERROR;        /* Already printed an error message */
217         break;
218 
219     case DIRR_OK:
220     case DIRR_ERROR:
221         break;                  /* Nothing to do */
222 
223     case DIRR_BADPARAM:
224         /*
225          * This one is an error.  Don't use it if forward compatibility
226          * would be compromised, as opposed to an inherent error.
227          */
228         nasm_error(ERR_NONFATAL, "bad argument to %%pragma %s %s",
229                    pragma.facility_name, pragma.opname);
230         break;
231 
232     default:
233         panic();
234     }
235     return rv;
236 }
237 
238 /* This warning message is intended for future use */
239 /*!
240  *!pragma-na [off] %pragma not applicable to this compilation
241  *!=not-my-pragma
242  *!  warns about a \c{%pragma} directive which is not applicable to
243  *!  this particular assembly session.  This is not yet implemented.
244  */
245 
246 /* Naked %pragma */
247 /*!
248  *!pragma-empty [off] empty %pragma directive
249  *!  warns about a \c{%pragma} directive containing nothing.
250  *!  This is treated identically to \c{%pragma ignore} except
251  *!  for this optional warning.
252  */
process_pragma(char * str)253 void process_pragma(char *str)
254 {
255     const struct pragma_facility *pf;
256     struct pragma pragma;
257     char *p;
258 
259     nasm_zero(pragma);
260 
261     pragma.facility_name = nasm_get_word(str, &p);
262     if (!pragma.facility_name) {
263         /* Empty %pragma */
264 	nasm_warn(ERR_PASS2|WARN_PRAGMA_EMPTY,
265 		   "empty %%pragma directive, ignored");
266         return;
267     }
268 
269     pragma.opname = nasm_get_word(p, &p);
270     if (!pragma.opname)
271         pragma.opcode = D_none;
272     else
273         pragma.opcode = directive_find(pragma.opname);
274 
275     pragma.tail = nasm_trim_spaces(p);
276 
277     /*
278      * Search the global pragma namespaces. This is done
279      * as a loop rather than than letting search_pragma_list()
280      * just run, because we don't want to keep searching if
281      * we have a facility match, thus we want to call
282      * search_pragma_list() individually for each namespace.
283      */
284     for (pf = global_pragmas; pf->name; pf++) {
285         if (search_pragma_list(NULL, NULL, pf, &pragma) != DIRR_UNKNOWN)
286             return;
287     }
288 
289     /* Is it an output pragma? */
290     if (output_pragma(&pragma) != DIRR_UNKNOWN)
291         return;
292 
293     /* Is it a debug pragma */
294     if (debug_pragma(&pragma) != DIRR_UNKNOWN)
295         return;
296 
297     /*
298      * Note: it would be nice to warn for an unknown namespace,
299      * but in order to do so we need to walk *ALL* the backends
300      * in order to make sure we aren't dealing with a pragma that
301      * is for another backend.  On the other hand, that could
302      * also be a warning with a separate warning flag.
303      *
304      * Leave this for the future, however, the warning classes are
305      * already defined for future compatibility.
306      */
307 }
308 
309 /* %pragma ignore */
ignore_pragma(const struct pragma * pragma)310 static enum directive_result ignore_pragma(const struct pragma *pragma)
311 {
312     (void)pragma;
313     return DIRR_OK;             /* Even for D_none! */
314 }
315 
316 /*
317  * Process output and debug pragmas, by either list name or generic
318  * name. Note that the output/debug format list can hook the default
319  * names if they so choose.
320  */
321 static enum directive_result output_pragma_common(const struct pragma *);
output_pragma(const struct pragma * pragma)322 static enum directive_result output_pragma(const struct pragma *pragma)
323 {
324     static const struct pragma_facility
325         output_pragma_def = { "output", output_pragma_common };
326 
327     return search_pragma_list(ofmt->pragmas, ofmt->shortname,
328                               &output_pragma_def, pragma);
329 }
330 
331 /* Generic pragmas that apply to all output backends */
output_pragma_common(const struct pragma * pragma)332 static enum directive_result output_pragma_common(const struct pragma *pragma)
333 {
334     switch (pragma->opcode) {
335     case D_PREFIX:
336     case D_GPREFIX:
337         set_label_mangle(LM_GPREFIX, pragma->tail);
338         return DIRR_OK;
339     case D_SUFFIX:
340     case D_GSUFFIX:
341         set_label_mangle(LM_GSUFFIX, pragma->tail);
342         return DIRR_OK;
343     case D_LPREFIX:
344         set_label_mangle(LM_LPREFIX, pragma->tail);
345         return DIRR_OK;
346     case D_LSUFFIX:
347         set_label_mangle(LM_LSUFFIX, pragma->tail);
348         return DIRR_OK;
349     default:
350         return DIRR_UNKNOWN;
351     }
352 }
353 
debug_pragma(const struct pragma * pragma)354 static enum directive_result debug_pragma(const struct pragma *pragma)
355 {
356     static const struct pragma_facility
357         debug_pragma_def = { "debug", NULL };
358 
359     return search_pragma_list(dfmt->pragmas, dfmt->shortname,
360                               &debug_pragma_def, pragma);
361 }
362 
363 /*
364  * %pragma limit to set resource limits
365  */
limit_pragma(const struct pragma * pragma)366 static enum directive_result limit_pragma(const struct pragma *pragma)
367 {
368     return nasm_set_limit(pragma->opname, pragma->tail);
369 }
370