blob: 46ff784242c5cdc7d295f4701381b18656d6bd3f [file] [log] [blame]
H. Peter Anvinb20bc732017-03-07 19:23:03 -08001/* ----------------------------------------------------------------------- *
2 *
H. Peter Anvina7ecf262018-02-06 14:43:07 -08003 * Copyright 1996-2018 The NASM Authors - All Rights Reserved
H. Peter Anvinb20bc732017-03-07 19:23:03 -08004 * 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 assembler directives
36 */
37
38#include "compiler.h"
39
40#include <stdlib.h>
41#include <string.h>
42#include <ctype.h>
43#include <limits.h>
44
45#include "nasm.h"
46#include "nasmlib.h"
H. Peter Anvin0a126062017-09-27 13:34:42 -070047#include "ilog2.h"
H. Peter Anvinb20bc732017-03-07 19:23:03 -080048#include "error.h"
49#include "float.h"
50#include "stdscan.h"
51#include "preproc.h"
H. Peter Anvinb20bc732017-03-07 19:23:03 -080052#include "eval.h"
53#include "assemble.h"
54#include "outform.h"
55#include "listing.h"
56#include "labels.h"
57#include "iflag.h"
58
H. Peter Anvina7ecf262018-02-06 14:43:07 -080059struct cpunames {
60 const char *name;
61 unsigned int level;
62 /* Eventually a table of features */
63};
64
65static iflag_t get_cpu(const char *value)
H. Peter Anvinb20bc732017-03-07 19:23:03 -080066{
67 iflag_t r;
H. Peter Anvina7ecf262018-02-06 14:43:07 -080068 const struct cpunames *cpu;
69 static const struct cpunames cpunames[] = {
70 { "8086", IF_8086 },
71 { "186", IF_186 },
72 { "286", IF_286 },
73 { "386", IF_386 },
74 { "486", IF_486 },
75 { "586", IF_PENT },
76 { "pentium", IF_PENT },
77 { "pentiummmx", IF_PENT },
78 { "686", IF_P6 },
79 { "p6", IF_P6 },
80 { "ppro", IF_P6 },
81 { "pentiumpro", IF_P6 },
82 { "p2", IF_P6 }, /* +MMX */
83 { "pentiumii", IF_P6 },
84 { "p3", IF_KATMAI },
85 { "katmai", IF_KATMAI },
86 { "p4", IF_WILLAMETTE },
87 { "willamette", IF_WILLAMETTE },
88 { "prescott", IF_PRESCOTT },
89 { "x64", IF_X86_64 },
90 { "x86-64", IF_X86_64 },
91 { "ia64", IF_IA64 },
92 { "ia-64", IF_IA64 },
93 { "itanium", IF_IA64 },
94 { "itanic", IF_IA64 },
95 { "merced", IF_IA64 },
96 { "any", IF_PLEVEL },
97 { "default", IF_PLEVEL },
98 { "all", IF_PLEVEL },
99 { NULL, IF_PLEVEL } /* Error and final default entry */
100 };
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800101
Cyrill Gorcunov8a231082018-02-25 13:25:19 +0300102 iflag_clear_all(&r);
103
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800104 for (cpu = cpunames; cpu->name; cpu++) {
Cyrill Gorcunova7f318c2018-06-07 00:06:58 +0300105 if (!nasm_stricmp(value, cpu->name))
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800106 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800107 }
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800108
109 if (!cpu->name) {
110 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
111 "unknown 'cpu' type '%s'", value);
112 }
113
114 iflag_set_cpu(&r, cpu->level);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800115 return r;
116}
117
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800118static int get_bits(const char *value)
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800119{
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800120 int i = atoi(value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800121
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800122 switch (i) {
123 case 16:
124 break; /* Always safe */
125 case 32:
126 if (!iflag_cpu_level_ok(&cpu, IF_386)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300127 nasm_nonfatal("cannot specify 32-bit segment on processor below a 386");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800128 i = 16;
129 }
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800130 break;
131 case 64:
132 if (!iflag_cpu_level_ok(&cpu, IF_X86_64)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300133 nasm_nonfatal("cannot specify 64-bit segment on processor below an x86-64");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800134 i = 16;
135 }
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800136 break;
137 default:
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800138 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800139 "`%s' is not a valid segment size; must be 16, 32 or 64",
140 value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800141 i = 16;
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800142 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800143 }
144 return i;
145}
146
H. Peter Anvin5253f582017-04-03 00:09:58 -0700147static enum directive parse_directive_line(char **directive, char **value)
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800148{
149 char *p, *q, *buf;
150
151 buf = nasm_skip_spaces(*directive);
152
153 /*
154 * It should be enclosed in [ ].
155 * XXX: we don't check there is nothing else on the remainder of the
156 * line, except a possible comment.
157 */
158 if (*buf != '[')
159 return D_none;
160 q = strchr(buf, ']');
161 if (!q)
162 return D_corrupt;
163
164 /*
165 * Strip off the comments. XXX: this doesn't account for quoted
166 * strings inside a directive. We should really strip the
167 * comments in generic code, not here. While we're at it, it
168 * would be better to pass the backend a series of tokens instead
169 * of a raw string, and actually process quoted strings for it,
170 * like of like argv is handled in C.
171 */
172 p = strchr(buf, ';');
173 if (p) {
174 if (p < q) /* ouch! somewhere inside */
175 return D_corrupt;
176 *p = '\0';
177 }
178
179 /* no brace, no trailing spaces */
180 *q = '\0';
181 nasm_zap_spaces_rev(--q);
182
183 /* directive */
184 p = nasm_skip_spaces(++buf);
185 q = nasm_skip_word(p);
186 if (!q)
187 return D_corrupt; /* sigh... no value there */
188 *q = '\0';
189 *directive = p;
190
191 /* and value finally */
192 p = nasm_skip_spaces(++q);
193 *value = p;
194
H. Peter Anvin5253f582017-04-03 00:09:58 -0700195 return directive_find(*directive);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800196}
197
H. Peter Anvina6e26d92017-03-07 21:32:37 -0800198/*
199 * Process a line from the assembler and try to handle it if it
200 * is a directive. Return true if the line was handled (including
201 * if it was an error), false otherwise.
202 */
203bool process_directives(char *directive)
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800204{
H. Peter Anvin5253f582017-04-03 00:09:58 -0700205 enum directive d;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800206 char *value, *p, *q, *special;
207 struct tokenval tokval;
208 bool bad_param = false;
209 int pass2 = passn > 1 ? 2 : 1;
H. Peter Anvin98578072018-06-01 18:02:54 -0700210 enum label_type type;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800211
212 d = parse_directive_line(&directive, &value);
213
214 switch (d) {
215 case D_none:
216 return D_none; /* Not a directive */
217
218 case D_corrupt:
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300219 nasm_nonfatal("invalid directive line");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800220 break;
221
222 default: /* It's a backend-specific directive */
H. Peter Anvine562b702017-03-07 22:40:00 -0800223 switch (ofmt->directive(d, value, pass2)) {
224 case DIRR_UNKNOWN:
225 goto unknown;
226 case DIRR_OK:
227 case DIRR_ERROR:
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800228 break;
H. Peter Anvine562b702017-03-07 22:40:00 -0800229 case DIRR_BADPARAM:
230 bad_param = true;
231 break;
232 default:
233 panic();
234 }
235 break;
236
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800237 case D_unknown:
H. Peter Anvine562b702017-03-07 22:40:00 -0800238 unknown:
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800239 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC,
240 "unrecognised directive [%s]", directive);
241 break;
242
243 case D_SEGMENT: /* [SEGMENT n] */
244 case D_SECTION:
245 {
H. Peter Anvine8001272017-09-27 14:22:16 -0700246 int sb = globalbits;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800247 int32_t seg = ofmt->section(value, pass2, &sb);
248
249 if (seg == NO_SEG) {
250 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC,
251 "segment name `%s' not recognized", value);
252 } else {
H. Peter Anvine8001272017-09-27 14:22:16 -0700253 globalbits = sb;
H. Peter Anvin892c4812018-05-30 14:43:46 -0700254 switch_segment(seg);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800255 }
256 break;
257 }
258
259 case D_SECTALIGN: /* [SECTALIGN n] */
260 {
261 expr *e;
262
263 if (*value) {
264 stdscan_reset();
265 stdscan_set(value);
266 tokval.t_type = TOKEN_INVALID;
267 e = evaluate(stdscan, NULL, &tokval, NULL, pass2, NULL);
268 if (e) {
269 uint64_t align = e->value;
270
271 if (!is_power2(e->value)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300272 nasm_nonfatal("segment alignment `%s' is not power of two",
273 value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800274 } else if (align > UINT64_C(0x7fffffff)) {
275 /*
276 * FIXME: Please make some sane message here
277 * ofmt should have some 'check' method which
278 * would report segment alignment bounds.
279 */
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300280 nasm_nonfatal("absurdly large segment alignment `%s' (2^%d)",
281 value, ilog2_64(align));
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800282 }
283
284 /* callee should be able to handle all details */
285 if (location.segment != NO_SEG)
286 ofmt->sectalign(location.segment, align);
287 }
288 }
289 break;
290 }
291
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800292 case D_BITS: /* [BITS bits] */
293 globalbits = get_bits(value);
294 break;
295
H. Peter Anvin98578072018-06-01 18:02:54 -0700296 case D_GLOBAL: /* [GLOBAL|STATIC|EXTERN|COMMON symbol:special] */
297 type = LBL_GLOBAL;
298 goto symdef;
299 case D_STATIC:
300 type = LBL_STATIC;
301 goto symdef;
302 case D_EXTERN:
303 type = LBL_EXTERN;
304 goto symdef;
305 case D_COMMON:
306 type = LBL_COMMON;
307 goto symdef;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800308
H. Peter Anvin98578072018-06-01 18:02:54 -0700309 symdef:
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800310 {
H. Peter Anvin98578072018-06-01 18:02:54 -0700311 bool validid = true;
312 int64_t size = 0;
313 char *sizestr;
314 bool rn_error;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800315
H. Peter Anvin73482482018-06-11 14:54:14 -0700316 if (*value == '$')
317 value++; /* skip initial $ if present */
318
H. Peter Anvin98578072018-06-01 18:02:54 -0700319 q = value;
H. Peter Anvin13506202018-11-28 14:55:58 -0800320 if (!nasm_isidstart(*q)) {
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800321 validid = false;
H. Peter Anvin73482482018-06-11 14:54:14 -0700322 } else {
H. Peter Anvin98578072018-06-01 18:02:54 -0700323 q++;
H. Peter Anvin73482482018-06-11 14:54:14 -0700324 while (*q && *q != ':' && !nasm_isspace(*q)) {
H. Peter Anvin13506202018-11-28 14:55:58 -0800325 if (!nasm_isidchar(*q))
H. Peter Anvin73482482018-06-11 14:54:14 -0700326 validid = false;
327 q++;
328 }
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800329 }
330 if (!validid) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300331 nasm_nonfatal("identifier expected after %s, got `%s'",
332 directive, value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800333 break;
334 }
335
H. Peter Anvin98578072018-06-01 18:02:54 -0700336 if (nasm_isspace(*q)) {
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700337 *q++ = '\0';
338 sizestr = q = nasm_skip_spaces(q);
H. Peter Anvin98578072018-06-01 18:02:54 -0700339 q = strchr(q, ':');
340 } else {
341 sizestr = NULL;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800342 }
H. Peter Anvin98578072018-06-01 18:02:54 -0700343
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700344 if (q && *q == ':') {
H. Peter Anvin98578072018-06-01 18:02:54 -0700345 *q++ = '\0';
346 special = q;
347 } else {
348 special = NULL;
349 }
350
351 if (type == LBL_COMMON) {
352 if (sizestr)
353 size = readnum(sizestr, &rn_error);
354 if (!sizestr || rn_error)
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300355 nasm_nonfatal("%s size specified in common declaration",
356 sizestr ? "invalid" : "no");
H. Peter Anvin98578072018-06-01 18:02:54 -0700357 } else if (sizestr) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300358 nasm_nonfatal("invalid syntax in %s declaration", directive);
H. Peter Anvin98578072018-06-01 18:02:54 -0700359 }
360
H. Peter Anvin98578072018-06-01 18:02:54 -0700361 if (!declare_label(value, type, special))
362 break;
363
364 if (type == LBL_COMMON || type == LBL_EXTERN)
H. Peter Anvinaf5f9182018-06-14 19:53:45 -0700365 define_label(value, 0, size, false);
H. Peter Anvin98578072018-06-01 18:02:54 -0700366
367 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800368 }
369
370 case D_ABSOLUTE: /* [ABSOLUTE address] */
371 {
372 expr *e;
373
374 stdscan_reset();
375 stdscan_set(value);
376 tokval.t_type = TOKEN_INVALID;
377 e = evaluate(stdscan, NULL, &tokval, NULL, pass2, NULL);
378 if (e) {
379 if (!is_reloc(e))
380 nasm_error(pass0 ==
381 1 ? ERR_NONFATAL : ERR_PANIC,
382 "cannot use non-relocatable expression as "
383 "ABSOLUTE address");
384 else {
385 absolute.segment = reloc_seg(e);
386 absolute.offset = reloc_value(e);
387 }
388 } else if (passn == 1)
389 absolute.offset = 0x100; /* don't go near zero in case of / */
390 else
H. Peter Anvinc5136902018-06-15 18:20:17 -0700391 nasm_panic("invalid ABSOLUTE address "
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800392 "in pass two");
393 in_absolute = true;
394 location.segment = NO_SEG;
H. Peter Anvin (Intel)415b6b32018-06-25 14:09:52 -0700395 location.offset = absolute.offset;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800396 break;
397 }
398
399 case D_DEBUG: /* [DEBUG] */
400 {
401 bool badid, overlong;
402 char debugid[128];
403
404 p = value;
405 q = debugid;
406 badid = overlong = false;
H. Peter Anvin13506202018-11-28 14:55:58 -0800407 if (!nasm_isidstart(*p)) {
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800408 badid = true;
409 } else {
410 while (*p && !nasm_isspace(*p)) {
411 if (q >= debugid + sizeof debugid - 1) {
412 overlong = true;
413 break;
414 }
H. Peter Anvin13506202018-11-28 14:55:58 -0800415 if (!nasm_isidchar(*p))
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800416 badid = true;
417 *q++ = *p++;
418 }
419 *q = 0;
420 }
421 if (badid) {
422 nasm_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC,
423 "identifier expected after DEBUG");
424 break;
425 }
426 if (overlong) {
427 nasm_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC,
428 "DEBUG identifier too long");
429 break;
430 }
431 p = nasm_skip_spaces(p);
432 if (pass0 == 2)
433 dfmt->debug_directive(debugid, p);
434 break;
435 }
436
437 case D_WARNING: /* [WARNING {+|-|*}warn-name] */
H. Peter Anvinb2047cb2017-03-08 01:26:40 -0800438 if (!set_warning_status(value)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300439 nasm_warnf(ERR_WARN_UNK_WARNING, "unknown warning option: %s", value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800440 }
H. Peter Anvinb2047cb2017-03-08 01:26:40 -0800441 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800442
443 case D_CPU: /* [CPU] */
444 cpu = get_cpu(value);
445 break;
446
447 case D_LIST: /* [LIST {+|-}] */
448 value = nasm_skip_spaces(value);
449 if (*value == '+') {
450 user_nolist = false;
451 } else {
452 if (*value == '-') {
453 user_nolist = true;
454 } else {
455 bad_param = true;
456 }
457 }
458 break;
459
460 case D_DEFAULT: /* [DEFAULT] */
461 stdscan_reset();
462 stdscan_set(value);
463 tokval.t_type = TOKEN_INVALID;
464 if (stdscan(NULL, &tokval) != TOKEN_INVALID) {
465 switch (tokval.t_integer) {
466 case S_REL:
467 globalrel = 1;
468 break;
469 case S_ABS:
470 globalrel = 0;
471 break;
472 case P_BND:
473 globalbnd = 1;
474 break;
475 case P_NOBND:
476 globalbnd = 0;
477 break;
478 default:
479 bad_param = true;
480 break;
481 }
482 } else {
483 bad_param = true;
484 }
485 break;
486
487 case D_FLOAT:
488 if (float_option(value)) {
489 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC,
490 "unknown 'float' directive: %s", value);
491 }
492 break;
493
494 case D_PRAGMA:
495 process_pragma(value);
496 break;
497 }
498
499
500 /* A common error message */
501 if (bad_param) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300502 nasm_nonfatal("invalid parameter to [%s] directive", directive);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800503 }
504
H. Peter Anvina6e26d92017-03-07 21:32:37 -0800505 return d != D_none;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800506}