blob: 8be5e2c5a2a5e3d0daa5dbb9a6f6f1d03cd9394a [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>
H. Peter Anvinc2f3f262018-12-27 12:37:25 -080041#include "nctype.h"
H. Peter Anvinb20bc732017-03-07 19:23:03 -080042#include <limits.h>
43
44#include "nasm.h"
45#include "nasmlib.h"
H. Peter Anvin0a126062017-09-27 13:34:42 -070046#include "ilog2.h"
H. Peter Anvinb20bc732017-03-07 19:23:03 -080047#include "error.h"
48#include "float.h"
49#include "stdscan.h"
50#include "preproc.h"
H. Peter Anvinb20bc732017-03-07 19:23:03 -080051#include "eval.h"
52#include "assemble.h"
53#include "outform.h"
54#include "listing.h"
55#include "labels.h"
56#include "iflag.h"
57
H. Peter Anvina7ecf262018-02-06 14:43:07 -080058struct cpunames {
59 const char *name;
60 unsigned int level;
61 /* Eventually a table of features */
62};
63
64static iflag_t get_cpu(const char *value)
H. Peter Anvinb20bc732017-03-07 19:23:03 -080065{
66 iflag_t r;
H. Peter Anvina7ecf262018-02-06 14:43:07 -080067 const struct cpunames *cpu;
68 static const struct cpunames cpunames[] = {
69 { "8086", IF_8086 },
70 { "186", IF_186 },
71 { "286", IF_286 },
72 { "386", IF_386 },
73 { "486", IF_486 },
74 { "586", IF_PENT },
75 { "pentium", IF_PENT },
76 { "pentiummmx", IF_PENT },
77 { "686", IF_P6 },
78 { "p6", IF_P6 },
79 { "ppro", IF_P6 },
80 { "pentiumpro", IF_P6 },
81 { "p2", IF_P6 }, /* +MMX */
82 { "pentiumii", IF_P6 },
83 { "p3", IF_KATMAI },
84 { "katmai", IF_KATMAI },
85 { "p4", IF_WILLAMETTE },
86 { "willamette", IF_WILLAMETTE },
87 { "prescott", IF_PRESCOTT },
88 { "x64", IF_X86_64 },
89 { "x86-64", IF_X86_64 },
90 { "ia64", IF_IA64 },
91 { "ia-64", IF_IA64 },
92 { "itanium", IF_IA64 },
93 { "itanic", IF_IA64 },
94 { "merced", IF_IA64 },
95 { "any", IF_PLEVEL },
96 { "default", IF_PLEVEL },
97 { "all", IF_PLEVEL },
98 { NULL, IF_PLEVEL } /* Error and final default entry */
99 };
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800100
Cyrill Gorcunov8a231082018-02-25 13:25:19 +0300101 iflag_clear_all(&r);
102
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800103 for (cpu = cpunames; cpu->name; cpu++) {
Cyrill Gorcunova7f318c2018-06-07 00:06:58 +0300104 if (!nasm_stricmp(value, cpu->name))
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800105 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800106 }
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800107
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800108 if (!cpu->name)
109 nasm_nonfatal("unknown 'cpu' type '%s'", value);
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800110
111 iflag_set_cpu(&r, cpu->level);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800112 return r;
113}
114
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800115static int get_bits(const char *value)
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800116{
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800117 int i = atoi(value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800118
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800119 switch (i) {
120 case 16:
121 break; /* Always safe */
122 case 32:
123 if (!iflag_cpu_level_ok(&cpu, IF_386)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300124 nasm_nonfatal("cannot specify 32-bit segment on processor below a 386");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800125 i = 16;
126 }
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800127 break;
128 case 64:
129 if (!iflag_cpu_level_ok(&cpu, IF_X86_64)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300130 nasm_nonfatal("cannot specify 64-bit segment on processor below an x86-64");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800131 i = 16;
132 }
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800133 break;
134 default:
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800135 nasm_nonfatal("`%s' is not a valid segment size; must be 16, 32 or 64",
136 value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800137 i = 16;
H. Peter Anvina7ecf262018-02-06 14:43:07 -0800138 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800139 }
140 return i;
141}
142
H. Peter Anvin5253f582017-04-03 00:09:58 -0700143static enum directive parse_directive_line(char **directive, char **value)
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800144{
145 char *p, *q, *buf;
146
147 buf = nasm_skip_spaces(*directive);
148
149 /*
150 * It should be enclosed in [ ].
151 * XXX: we don't check there is nothing else on the remainder of the
152 * line, except a possible comment.
153 */
154 if (*buf != '[')
155 return D_none;
156 q = strchr(buf, ']');
157 if (!q)
158 return D_corrupt;
159
160 /*
161 * Strip off the comments. XXX: this doesn't account for quoted
162 * strings inside a directive. We should really strip the
163 * comments in generic code, not here. While we're at it, it
164 * would be better to pass the backend a series of tokens instead
165 * of a raw string, and actually process quoted strings for it,
166 * like of like argv is handled in C.
167 */
168 p = strchr(buf, ';');
169 if (p) {
170 if (p < q) /* ouch! somewhere inside */
171 return D_corrupt;
172 *p = '\0';
173 }
174
175 /* no brace, no trailing spaces */
176 *q = '\0';
177 nasm_zap_spaces_rev(--q);
178
179 /* directive */
180 p = nasm_skip_spaces(++buf);
181 q = nasm_skip_word(p);
182 if (!q)
183 return D_corrupt; /* sigh... no value there */
184 *q = '\0';
185 *directive = p;
186
187 /* and value finally */
188 p = nasm_skip_spaces(++q);
189 *value = p;
190
H. Peter Anvin5253f582017-04-03 00:09:58 -0700191 return directive_find(*directive);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800192}
193
H. Peter Anvina6e26d92017-03-07 21:32:37 -0800194/*
195 * Process a line from the assembler and try to handle it if it
196 * is a directive. Return true if the line was handled (including
197 * if it was an error), false otherwise.
198 */
199bool process_directives(char *directive)
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800200{
H. Peter Anvin5253f582017-04-03 00:09:58 -0700201 enum directive d;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800202 char *value, *p, *q, *special;
203 struct tokenval tokval;
204 bool bad_param = false;
H. Peter Anvin98578072018-06-01 18:02:54 -0700205 enum label_type type;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800206
207 d = parse_directive_line(&directive, &value);
208
209 switch (d) {
210 case D_none:
211 return D_none; /* Not a directive */
212
213 case D_corrupt:
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300214 nasm_nonfatal("invalid directive line");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800215 break;
216
217 default: /* It's a backend-specific directive */
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800218 switch (ofmt->directive(d, value)) {
H. Peter Anvine562b702017-03-07 22:40:00 -0800219 case DIRR_UNKNOWN:
220 goto unknown;
221 case DIRR_OK:
222 case DIRR_ERROR:
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800223 break;
H. Peter Anvine562b702017-03-07 22:40:00 -0800224 case DIRR_BADPARAM:
225 bad_param = true;
226 break;
227 default:
228 panic();
229 }
230 break;
231
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800232 case D_unknown:
H. Peter Anvine562b702017-03-07 22:40:00 -0800233 unknown:
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800234 nasm_nonfatal("unrecognized directive [%s]", directive);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800235 break;
236
237 case D_SEGMENT: /* [SEGMENT n] */
238 case D_SECTION:
239 {
H. Peter Anvine8001272017-09-27 14:22:16 -0700240 int sb = globalbits;
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800241 int32_t seg = ofmt->section(value, &sb);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800242
243 if (seg == NO_SEG) {
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800244 nasm_nonfatal("segment name `%s' not recognized", value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800245 } else {
H. Peter Anvine8001272017-09-27 14:22:16 -0700246 globalbits = sb;
H. Peter Anvin892c4812018-05-30 14:43:46 -0700247 switch_segment(seg);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800248 }
249 break;
250 }
251
252 case D_SECTALIGN: /* [SECTALIGN n] */
253 {
254 expr *e;
255
256 if (*value) {
257 stdscan_reset();
258 stdscan_set(value);
259 tokval.t_type = TOKEN_INVALID;
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800260 e = evaluate(stdscan, NULL, &tokval, NULL, true, NULL);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800261 if (e) {
262 uint64_t align = e->value;
263
264 if (!is_power2(e->value)) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300265 nasm_nonfatal("segment alignment `%s' is not power of two",
266 value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800267 } else if (align > UINT64_C(0x7fffffff)) {
268 /*
269 * FIXME: Please make some sane message here
270 * ofmt should have some 'check' method which
271 * would report segment alignment bounds.
272 */
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300273 nasm_nonfatal("absurdly large segment alignment `%s' (2^%d)",
274 value, ilog2_64(align));
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800275 }
276
277 /* callee should be able to handle all details */
278 if (location.segment != NO_SEG)
279 ofmt->sectalign(location.segment, align);
280 }
281 }
282 break;
283 }
284
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800285 case D_BITS: /* [BITS bits] */
286 globalbits = get_bits(value);
287 break;
288
H. Peter Anvin98578072018-06-01 18:02:54 -0700289 case D_GLOBAL: /* [GLOBAL|STATIC|EXTERN|COMMON symbol:special] */
290 type = LBL_GLOBAL;
291 goto symdef;
292 case D_STATIC:
293 type = LBL_STATIC;
294 goto symdef;
295 case D_EXTERN:
296 type = LBL_EXTERN;
297 goto symdef;
298 case D_COMMON:
299 type = LBL_COMMON;
300 goto symdef;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800301
H. Peter Anvin98578072018-06-01 18:02:54 -0700302 symdef:
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800303 {
H. Peter Anvin98578072018-06-01 18:02:54 -0700304 bool validid = true;
305 int64_t size = 0;
306 char *sizestr;
307 bool rn_error;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800308
H. Peter Anvin73482482018-06-11 14:54:14 -0700309 if (*value == '$')
310 value++; /* skip initial $ if present */
311
H. Peter Anvin98578072018-06-01 18:02:54 -0700312 q = value;
H. Peter Anvin13506202018-11-28 14:55:58 -0800313 if (!nasm_isidstart(*q)) {
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800314 validid = false;
H. Peter Anvin73482482018-06-11 14:54:14 -0700315 } else {
H. Peter Anvin98578072018-06-01 18:02:54 -0700316 q++;
H. Peter Anvin73482482018-06-11 14:54:14 -0700317 while (*q && *q != ':' && !nasm_isspace(*q)) {
H. Peter Anvin13506202018-11-28 14:55:58 -0800318 if (!nasm_isidchar(*q))
H. Peter Anvin73482482018-06-11 14:54:14 -0700319 validid = false;
320 q++;
321 }
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800322 }
323 if (!validid) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300324 nasm_nonfatal("identifier expected after %s, got `%s'",
325 directive, value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800326 break;
327 }
328
H. Peter Anvin98578072018-06-01 18:02:54 -0700329 if (nasm_isspace(*q)) {
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700330 *q++ = '\0';
331 sizestr = q = nasm_skip_spaces(q);
H. Peter Anvin98578072018-06-01 18:02:54 -0700332 q = strchr(q, ':');
333 } else {
334 sizestr = NULL;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800335 }
H. Peter Anvin98578072018-06-01 18:02:54 -0700336
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700337 if (q && *q == ':') {
H. Peter Anvin98578072018-06-01 18:02:54 -0700338 *q++ = '\0';
339 special = q;
340 } else {
341 special = NULL;
342 }
343
344 if (type == LBL_COMMON) {
345 if (sizestr)
346 size = readnum(sizestr, &rn_error);
347 if (!sizestr || rn_error)
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300348 nasm_nonfatal("%s size specified in common declaration",
349 sizestr ? "invalid" : "no");
H. Peter Anvin98578072018-06-01 18:02:54 -0700350 } else if (sizestr) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300351 nasm_nonfatal("invalid syntax in %s declaration", directive);
H. Peter Anvin98578072018-06-01 18:02:54 -0700352 }
353
H. Peter Anvin98578072018-06-01 18:02:54 -0700354 if (!declare_label(value, type, special))
355 break;
356
357 if (type == LBL_COMMON || type == LBL_EXTERN)
H. Peter Anvinaf5f9182018-06-14 19:53:45 -0700358 define_label(value, 0, size, false);
H. Peter Anvin98578072018-06-01 18:02:54 -0700359
360 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800361 }
362
363 case D_ABSOLUTE: /* [ABSOLUTE address] */
364 {
365 expr *e;
366
367 stdscan_reset();
368 stdscan_set(value);
369 tokval.t_type = TOKEN_INVALID;
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800370 e = evaluate(stdscan, NULL, &tokval, NULL, true, NULL);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800371 if (e) {
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800372 if (!is_reloc(e)) {
373 nasm_nonfatal("cannot use non-relocatable expression as "
374 "ABSOLUTE address");
375 } else {
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800376 absolute.segment = reloc_seg(e);
377 absolute.offset = reloc_value(e);
378 }
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800379 } else if (pass_first()) {
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800380 absolute.offset = 0x100; /* don't go near zero in case of / */
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800381 } else {
382 nasm_nonfatal("invalid ABSOLUTE address");
383 }
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800384 in_absolute = true;
385 location.segment = NO_SEG;
H. Peter Anvin (Intel)415b6b32018-06-25 14:09:52 -0700386 location.offset = absolute.offset;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800387 break;
388 }
389
390 case D_DEBUG: /* [DEBUG] */
391 {
392 bool badid, overlong;
393 char debugid[128];
394
395 p = value;
396 q = debugid;
397 badid = overlong = false;
H. Peter Anvin13506202018-11-28 14:55:58 -0800398 if (!nasm_isidstart(*p)) {
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800399 badid = true;
400 } else {
401 while (*p && !nasm_isspace(*p)) {
402 if (q >= debugid + sizeof debugid - 1) {
403 overlong = true;
404 break;
405 }
H. Peter Anvin13506202018-11-28 14:55:58 -0800406 if (!nasm_isidchar(*p))
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800407 badid = true;
408 *q++ = *p++;
409 }
410 *q = 0;
411 }
412 if (badid) {
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800413 nasm_nonfatal("identifier expected after DEBUG");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800414 break;
415 }
416 if (overlong) {
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800417 nasm_nonfatal("DEBUG identifier too long");
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800418 break;
419 }
420 p = nasm_skip_spaces(p);
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800421 if (pass_final())
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800422 dfmt->debug_directive(debugid, p);
423 break;
424 }
425
426 case D_WARNING: /* [WARNING {+|-|*}warn-name] */
H. Peter Anvin (Intel)723ab482018-12-13 21:53:31 -0800427 set_warning_status(value);
H. Peter Anvinb2047cb2017-03-08 01:26:40 -0800428 break;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800429
430 case D_CPU: /* [CPU] */
431 cpu = get_cpu(value);
432 break;
433
434 case D_LIST: /* [LIST {+|-}] */
435 value = nasm_skip_spaces(value);
436 if (*value == '+') {
437 user_nolist = false;
438 } else {
439 if (*value == '-') {
440 user_nolist = true;
441 } else {
442 bad_param = true;
443 }
444 }
445 break;
446
447 case D_DEFAULT: /* [DEFAULT] */
448 stdscan_reset();
449 stdscan_set(value);
450 tokval.t_type = TOKEN_INVALID;
451 if (stdscan(NULL, &tokval) != TOKEN_INVALID) {
452 switch (tokval.t_integer) {
453 case S_REL:
454 globalrel = 1;
455 break;
456 case S_ABS:
457 globalrel = 0;
458 break;
459 case P_BND:
460 globalbnd = 1;
461 break;
462 case P_NOBND:
463 globalbnd = 0;
464 break;
465 default:
466 bad_param = true;
467 break;
468 }
469 } else {
470 bad_param = true;
471 }
472 break;
473
474 case D_FLOAT:
475 if (float_option(value)) {
H. Peter Anvin (Intel)e55d03d2018-12-18 11:12:46 -0800476 nasm_nonfatal("unknown 'float' directive: %s", value);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800477 }
478 break;
479
480 case D_PRAGMA:
481 process_pragma(value);
482 break;
483 }
484
485
486 /* A common error message */
487 if (bad_param) {
Cyrill Gorcunov7c5de5b2018-12-01 14:17:40 +0300488 nasm_nonfatal("invalid parameter to [%s] directive", directive);
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800489 }
490
H. Peter Anvina6e26d92017-03-07 21:32:37 -0800491 return d != D_none;
H. Peter Anvinb20bc732017-03-07 19:23:03 -0800492}