Mercurial > repo
comparison nasmbuild/nasm-2.13rc9/asm/directiv.c @ 10554:587a0a262d22
<moonythedwarf> ` cd nasmbuild; tar -xf nasm.tar.gz
author | HackBot |
---|---|
date | Thu, 30 Mar 2017 20:58:41 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
10553:93dc2a984de0 | 10554:587a0a262d22 |
---|---|
1 /* ----------------------------------------------------------------------- * | |
2 * | |
3 * Copyright 1996-2017 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 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" | |
47 #include "error.h" | |
48 #include "float.h" | |
49 #include "stdscan.h" | |
50 #include "preproc.h" | |
51 #include "eval.h" | |
52 #include "assemble.h" | |
53 #include "outform.h" | |
54 #include "listing.h" | |
55 #include "labels.h" | |
56 #include "iflag.h" | |
57 | |
58 static iflag_t get_cpu(char *value) | |
59 { | |
60 iflag_t r; | |
61 | |
62 iflag_clear_all(&r); | |
63 | |
64 if (!strcmp(value, "8086")) | |
65 iflag_set(&r, IF_8086); | |
66 else if (!strcmp(value, "186")) | |
67 iflag_set(&r, IF_186); | |
68 else if (!strcmp(value, "286")) | |
69 iflag_set(&r, IF_286); | |
70 else if (!strcmp(value, "386")) | |
71 iflag_set(&r, IF_386); | |
72 else if (!strcmp(value, "486")) | |
73 iflag_set(&r, IF_486); | |
74 else if (!strcmp(value, "586") || | |
75 !nasm_stricmp(value, "pentium")) | |
76 iflag_set(&r, IF_PENT); | |
77 else if (!strcmp(value, "686") || | |
78 !nasm_stricmp(value, "ppro") || | |
79 !nasm_stricmp(value, "pentiumpro") || | |
80 !nasm_stricmp(value, "p2")) | |
81 iflag_set(&r, IF_P6); | |
82 else if (!nasm_stricmp(value, "p3") || | |
83 !nasm_stricmp(value, "katmai")) | |
84 iflag_set(&r, IF_KATMAI); | |
85 else if (!nasm_stricmp(value, "p4") || /* is this right? -- jrc */ | |
86 !nasm_stricmp(value, "willamette")) | |
87 iflag_set(&r, IF_WILLAMETTE); | |
88 else if (!nasm_stricmp(value, "prescott")) | |
89 iflag_set(&r, IF_PRESCOTT); | |
90 else if (!nasm_stricmp(value, "x64") || | |
91 !nasm_stricmp(value, "x86-64")) | |
92 iflag_set(&r, IF_X86_64); | |
93 else if (!nasm_stricmp(value, "ia64") || | |
94 !nasm_stricmp(value, "ia-64") || | |
95 !nasm_stricmp(value, "itanium")|| | |
96 !nasm_stricmp(value, "itanic") || | |
97 !nasm_stricmp(value, "merced")) | |
98 iflag_set(&r, IF_IA64); | |
99 else { | |
100 iflag_set(&r, IF_PLEVEL); | |
101 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL, | |
102 "unknown 'cpu' type"); | |
103 } | |
104 return r; | |
105 } | |
106 | |
107 static int get_bits(char *value) | |
108 { | |
109 int i; | |
110 | |
111 if ((i = atoi(value)) == 16) | |
112 return i; /* set for a 16-bit segment */ | |
113 else if (i == 32) { | |
114 if (iflag_ffs(&cpu) < IF_386) { | |
115 nasm_error(ERR_NONFATAL, | |
116 "cannot specify 32-bit segment on processor below a 386"); | |
117 i = 16; | |
118 } | |
119 } else if (i == 64) { | |
120 if (iflag_ffs(&cpu) < IF_X86_64) { | |
121 nasm_error(ERR_NONFATAL, | |
122 "cannot specify 64-bit segment on processor below an x86-64"); | |
123 i = 16; | |
124 } | |
125 } else { | |
126 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL, | |
127 "`%s' is not a valid segment size; must be 16, 32 or 64", | |
128 value); | |
129 i = 16; | |
130 } | |
131 return i; | |
132 } | |
133 | |
134 static enum directives parse_directive_line(char **directive, char **value) | |
135 { | |
136 char *p, *q, *buf; | |
137 | |
138 buf = nasm_skip_spaces(*directive); | |
139 | |
140 /* | |
141 * It should be enclosed in [ ]. | |
142 * XXX: we don't check there is nothing else on the remainder of the | |
143 * line, except a possible comment. | |
144 */ | |
145 if (*buf != '[') | |
146 return D_none; | |
147 q = strchr(buf, ']'); | |
148 if (!q) | |
149 return D_corrupt; | |
150 | |
151 /* | |
152 * Strip off the comments. XXX: this doesn't account for quoted | |
153 * strings inside a directive. We should really strip the | |
154 * comments in generic code, not here. While we're at it, it | |
155 * would be better to pass the backend a series of tokens instead | |
156 * of a raw string, and actually process quoted strings for it, | |
157 * like of like argv is handled in C. | |
158 */ | |
159 p = strchr(buf, ';'); | |
160 if (p) { | |
161 if (p < q) /* ouch! somewhere inside */ | |
162 return D_corrupt; | |
163 *p = '\0'; | |
164 } | |
165 | |
166 /* no brace, no trailing spaces */ | |
167 *q = '\0'; | |
168 nasm_zap_spaces_rev(--q); | |
169 | |
170 /* directive */ | |
171 p = nasm_skip_spaces(++buf); | |
172 q = nasm_skip_word(p); | |
173 if (!q) | |
174 return D_corrupt; /* sigh... no value there */ | |
175 *q = '\0'; | |
176 *directive = p; | |
177 | |
178 /* and value finally */ | |
179 p = nasm_skip_spaces(++q); | |
180 *value = p; | |
181 | |
182 return find_directive(*directive); | |
183 } | |
184 | |
185 /* | |
186 * Process a line from the assembler and try to handle it if it | |
187 * is a directive. Return true if the line was handled (including | |
188 * if it was an error), false otherwise. | |
189 */ | |
190 bool process_directives(char *directive) | |
191 { | |
192 enum directives d; | |
193 char *value, *p, *q, *special; | |
194 struct tokenval tokval; | |
195 bool bad_param = false; | |
196 int pass2 = passn > 1 ? 2 : 1; | |
197 | |
198 d = parse_directive_line(&directive, &value); | |
199 | |
200 switch (d) { | |
201 case D_none: | |
202 return D_none; /* Not a directive */ | |
203 | |
204 case D_corrupt: | |
205 nasm_error(ERR_NONFATAL, "invalid directive line"); | |
206 break; | |
207 | |
208 default: /* It's a backend-specific directive */ | |
209 switch (ofmt->directive(d, value, pass2)) { | |
210 case DIRR_UNKNOWN: | |
211 goto unknown; | |
212 case DIRR_OK: | |
213 case DIRR_ERROR: | |
214 break; | |
215 case DIRR_BADPARAM: | |
216 bad_param = true; | |
217 break; | |
218 default: | |
219 panic(); | |
220 } | |
221 break; | |
222 | |
223 case D_unknown: | |
224 unknown: | |
225 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC, | |
226 "unrecognised directive [%s]", directive); | |
227 break; | |
228 | |
229 case D_SEGMENT: /* [SEGMENT n] */ | |
230 case D_SECTION: | |
231 { | |
232 int sb; | |
233 int32_t seg = ofmt->section(value, pass2, &sb); | |
234 | |
235 if (seg == NO_SEG) { | |
236 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC, | |
237 "segment name `%s' not recognized", value); | |
238 } else { | |
239 in_absolute = false; | |
240 location.segment = seg; | |
241 } | |
242 break; | |
243 } | |
244 | |
245 case D_SECTALIGN: /* [SECTALIGN n] */ | |
246 { | |
247 expr *e; | |
248 | |
249 if (*value) { | |
250 stdscan_reset(); | |
251 stdscan_set(value); | |
252 tokval.t_type = TOKEN_INVALID; | |
253 e = evaluate(stdscan, NULL, &tokval, NULL, pass2, NULL); | |
254 if (e) { | |
255 uint64_t align = e->value; | |
256 | |
257 if (!is_power2(e->value)) { | |
258 nasm_error(ERR_NONFATAL, | |
259 "segment alignment `%s' is not power of two", | |
260 value); | |
261 } else if (align > UINT64_C(0x7fffffff)) { | |
262 /* | |
263 * FIXME: Please make some sane message here | |
264 * ofmt should have some 'check' method which | |
265 * would report segment alignment bounds. | |
266 */ | |
267 nasm_error(ERR_NONFATAL, | |
268 "absurdly large segment alignment `%s' (2^%d)", | |
269 value, ilog2_64(align)); | |
270 } | |
271 | |
272 /* callee should be able to handle all details */ | |
273 if (location.segment != NO_SEG) | |
274 ofmt->sectalign(location.segment, align); | |
275 } | |
276 } | |
277 break; | |
278 } | |
279 | |
280 case D_EXTERN: /* [EXTERN label:special] */ | |
281 if (*value == '$') | |
282 value++; /* skip initial $ if present */ | |
283 if (pass0 == 2) { | |
284 q = value; | |
285 while (*q && *q != ':') | |
286 q++; | |
287 if (*q == ':') { | |
288 *q++ = '\0'; | |
289 ofmt->symdef(value, 0L, 0L, 3, q); | |
290 } | |
291 } else if (passn == 1) { | |
292 bool validid = true; | |
293 q = value; | |
294 if (!isidstart(*q)) | |
295 validid = false; | |
296 while (*q && *q != ':') { | |
297 if (!isidchar(*q)) | |
298 validid = false; | |
299 q++; | |
300 } | |
301 if (!validid) { | |
302 nasm_error(ERR_NONFATAL, "identifier expected after EXTERN"); | |
303 break; | |
304 } | |
305 if (*q == ':') { | |
306 *q++ = '\0'; | |
307 special = q; | |
308 } else | |
309 special = NULL; | |
310 if (!is_extern(value)) { /* allow re-EXTERN to be ignored */ | |
311 int temp = pass0; | |
312 pass0 = 1; /* fake pass 1 in labels.c */ | |
313 declare_as_global(value, special); | |
314 define_label(value, seg_alloc(), 0L, NULL, | |
315 false, true); | |
316 pass0 = temp; | |
317 } | |
318 } /* else pass0 == 1 */ | |
319 break; | |
320 | |
321 case D_BITS: /* [BITS bits] */ | |
322 globalbits = get_bits(value); | |
323 break; | |
324 | |
325 case D_GLOBAL: /* [GLOBAL symbol:special] */ | |
326 if (*value == '$') | |
327 value++; /* skip initial $ if present */ | |
328 if (pass0 == 2) { /* pass 2 */ | |
329 q = value; | |
330 while (*q && *q != ':') | |
331 q++; | |
332 if (*q == ':') { | |
333 *q++ = '\0'; | |
334 ofmt->symdef(value, 0L, 0L, 3, q); | |
335 } | |
336 } else if (pass2 == 1) { /* pass == 1 */ | |
337 bool validid = true; | |
338 | |
339 q = value; | |
340 if (!isidstart(*q)) | |
341 validid = false; | |
342 while (*q && *q != ':') { | |
343 if (!isidchar(*q)) | |
344 validid = false; | |
345 q++; | |
346 } | |
347 if (!validid) { | |
348 nasm_error(ERR_NONFATAL, | |
349 "identifier expected after GLOBAL"); | |
350 break; | |
351 } | |
352 if (*q == ':') { | |
353 *q++ = '\0'; | |
354 special = q; | |
355 } else | |
356 special = NULL; | |
357 declare_as_global(value, special); | |
358 } /* pass == 1 */ | |
359 break; | |
360 | |
361 case D_COMMON: /* [COMMON symbol size:special] */ | |
362 { | |
363 int64_t size; | |
364 bool rn_error; | |
365 bool validid; | |
366 | |
367 if (*value == '$') | |
368 value++; /* skip initial $ if present */ | |
369 p = value; | |
370 validid = true; | |
371 if (!isidstart(*p)) | |
372 validid = false; | |
373 while (*p && !nasm_isspace(*p)) { | |
374 if (!isidchar(*p)) | |
375 validid = false; | |
376 p++; | |
377 } | |
378 if (!validid) { | |
379 nasm_error(ERR_NONFATAL, "identifier expected after COMMON"); | |
380 break; | |
381 } | |
382 if (*p) { | |
383 p = nasm_zap_spaces_fwd(p); | |
384 q = p; | |
385 while (*q && *q != ':') | |
386 q++; | |
387 if (*q == ':') { | |
388 *q++ = '\0'; | |
389 special = q; | |
390 } else { | |
391 special = NULL; | |
392 } | |
393 size = readnum(p, &rn_error); | |
394 if (rn_error) { | |
395 nasm_error(ERR_NONFATAL, | |
396 "invalid size specified" | |
397 " in COMMON declaration"); | |
398 break; | |
399 } | |
400 } else { | |
401 nasm_error(ERR_NONFATAL, | |
402 "no size specified in" | |
403 " COMMON declaration"); | |
404 break; | |
405 } | |
406 | |
407 if (pass0 < 2) { | |
408 define_common(value, seg_alloc(), size, special); | |
409 } else if (pass0 == 2) { | |
410 if (special) | |
411 ofmt->symdef(value, 0L, 0L, 3, special); | |
412 } | |
413 break; | |
414 } | |
415 | |
416 case D_ABSOLUTE: /* [ABSOLUTE address] */ | |
417 { | |
418 expr *e; | |
419 | |
420 stdscan_reset(); | |
421 stdscan_set(value); | |
422 tokval.t_type = TOKEN_INVALID; | |
423 e = evaluate(stdscan, NULL, &tokval, NULL, pass2, NULL); | |
424 if (e) { | |
425 if (!is_reloc(e)) | |
426 nasm_error(pass0 == | |
427 1 ? ERR_NONFATAL : ERR_PANIC, | |
428 "cannot use non-relocatable expression as " | |
429 "ABSOLUTE address"); | |
430 else { | |
431 absolute.segment = reloc_seg(e); | |
432 absolute.offset = reloc_value(e); | |
433 } | |
434 } else if (passn == 1) | |
435 absolute.offset = 0x100; /* don't go near zero in case of / */ | |
436 else | |
437 nasm_panic(0, "invalid ABSOLUTE address " | |
438 "in pass two"); | |
439 in_absolute = true; | |
440 location.segment = NO_SEG; | |
441 break; | |
442 } | |
443 | |
444 case D_DEBUG: /* [DEBUG] */ | |
445 { | |
446 bool badid, overlong; | |
447 char debugid[128]; | |
448 | |
449 p = value; | |
450 q = debugid; | |
451 badid = overlong = false; | |
452 if (!isidstart(*p)) { | |
453 badid = true; | |
454 } else { | |
455 while (*p && !nasm_isspace(*p)) { | |
456 if (q >= debugid + sizeof debugid - 1) { | |
457 overlong = true; | |
458 break; | |
459 } | |
460 if (!isidchar(*p)) | |
461 badid = true; | |
462 *q++ = *p++; | |
463 } | |
464 *q = 0; | |
465 } | |
466 if (badid) { | |
467 nasm_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC, | |
468 "identifier expected after DEBUG"); | |
469 break; | |
470 } | |
471 if (overlong) { | |
472 nasm_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC, | |
473 "DEBUG identifier too long"); | |
474 break; | |
475 } | |
476 p = nasm_skip_spaces(p); | |
477 if (pass0 == 2) | |
478 dfmt->debug_directive(debugid, p); | |
479 break; | |
480 } | |
481 | |
482 case D_WARNING: /* [WARNING {+|-|*}warn-name] */ | |
483 if (!set_warning_status(value)) { | |
484 nasm_error(ERR_WARNING|ERR_WARN_UNK_WARNING, | |
485 "unknown warning option: %s", value); | |
486 } | |
487 break; | |
488 | |
489 case D_CPU: /* [CPU] */ | |
490 cpu = get_cpu(value); | |
491 break; | |
492 | |
493 case D_LIST: /* [LIST {+|-}] */ | |
494 value = nasm_skip_spaces(value); | |
495 if (*value == '+') { | |
496 user_nolist = false; | |
497 } else { | |
498 if (*value == '-') { | |
499 user_nolist = true; | |
500 } else { | |
501 bad_param = true; | |
502 } | |
503 } | |
504 break; | |
505 | |
506 case D_DEFAULT: /* [DEFAULT] */ | |
507 stdscan_reset(); | |
508 stdscan_set(value); | |
509 tokval.t_type = TOKEN_INVALID; | |
510 if (stdscan(NULL, &tokval) != TOKEN_INVALID) { | |
511 switch (tokval.t_integer) { | |
512 case S_REL: | |
513 globalrel = 1; | |
514 break; | |
515 case S_ABS: | |
516 globalrel = 0; | |
517 break; | |
518 case P_BND: | |
519 globalbnd = 1; | |
520 break; | |
521 case P_NOBND: | |
522 globalbnd = 0; | |
523 break; | |
524 default: | |
525 bad_param = true; | |
526 break; | |
527 } | |
528 } else { | |
529 bad_param = true; | |
530 } | |
531 break; | |
532 | |
533 case D_FLOAT: | |
534 if (float_option(value)) { | |
535 nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC, | |
536 "unknown 'float' directive: %s", value); | |
537 } | |
538 break; | |
539 | |
540 case D_PRAGMA: | |
541 process_pragma(value); | |
542 break; | |
543 } | |
544 | |
545 | |
546 /* A common error message */ | |
547 if (bad_param) { | |
548 nasm_error(ERR_NONFATAL, "invalid parameter to [%s] directive", | |
549 directive); | |
550 } | |
551 | |
552 return d != D_none; | |
553 } |