| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- /* ----------------------------------------------------------------------- *
- *
- * Copyright 1996-2018 The NASM Authors - All Rights Reserved
- * See the file AUTHORS included with the NASM distribution for
- * the specific copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ----------------------------------------------------------------------- */
- /*
- * Parse and handle assembler directives
- */
- #include "compiler.h"
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <limits.h>
- #include "nasm.h"
- #include "nasmlib.h"
- #include "ilog2.h"
- #include "error.h"
- #include "float.h"
- #include "stdscan.h"
- #include "preproc.h"
- #include "eval.h"
- #include "assemble.h"
- #include "outform.h"
- #include "listing.h"
- #include "labels.h"
- #include "iflag.h"
- struct cpunames {
- const char *name;
- unsigned int level;
- /* Eventually a table of features */
- };
- static iflag_t get_cpu(const char *value)
- {
- iflag_t r;
- const struct cpunames *cpu;
- static const struct cpunames cpunames[] = {
- { "8086", IF_8086 },
- { "186", IF_186 },
- { "286", IF_286 },
- { "386", IF_386 },
- { "486", IF_486 },
- { "586", IF_PENT },
- { "pentium", IF_PENT },
- { "pentiummmx", IF_PENT },
- { "686", IF_P6 },
- { "p6", IF_P6 },
- { "ppro", IF_P6 },
- { "pentiumpro", IF_P6 },
- { "p2", IF_P6 }, /* +MMX */
- { "pentiumii", IF_P6 },
- { "p3", IF_KATMAI },
- { "katmai", IF_KATMAI },
- { "p4", IF_WILLAMETTE },
- { "willamette", IF_WILLAMETTE },
- { "prescott", IF_PRESCOTT },
- { "x64", IF_X86_64 },
- { "x86-64", IF_X86_64 },
- { "ia64", IF_IA64 },
- { "ia-64", IF_IA64 },
- { "itanium", IF_IA64 },
- { "itanic", IF_IA64 },
- { "merced", IF_IA64 },
- { "any", IF_PLEVEL },
- { "default", IF_PLEVEL },
- { "all", IF_PLEVEL },
- { NULL, IF_PLEVEL } /* Error and final default entry */
- };
- iflag_clear_all(&r);
- for (cpu = cpunames; cpu->name; cpu++) {
- if (!nasm_stricmp(value, cpu->name))
- break;
- }
- if (!cpu->name) {
- nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
- "unknown 'cpu' type '%s'", value);
- }
- iflag_set_cpu(&r, cpu->level);
- return r;
- }
- static int get_bits(const char *value)
- {
- int i = atoi(value);
- switch (i) {
- case 16:
- break; /* Always safe */
- case 32:
- if (!iflag_cpu_level_ok(&cpu, IF_386)) {
- nasm_error(ERR_NONFATAL,
- "cannot specify 32-bit segment on processor below a 386");
- i = 16;
- }
- break;
- case 64:
- if (!iflag_cpu_level_ok(&cpu, IF_X86_64)) {
- nasm_error(ERR_NONFATAL,
- "cannot specify 64-bit segment on processor below an x86-64");
- i = 16;
- }
- break;
- default:
- nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
- "`%s' is not a valid segment size; must be 16, 32 or 64",
- value);
- i = 16;
- break;
- }
- return i;
- }
- static enum directive parse_directive_line(char **directive, char **value)
- {
- char *p, *q, *buf;
- buf = nasm_skip_spaces(*directive);
- /*
- * It should be enclosed in [ ].
- * XXX: we don't check there is nothing else on the remainder of the
- * line, except a possible comment.
- */
- if (*buf != '[')
- return D_none;
- q = strchr(buf, ']');
- if (!q)
- return D_corrupt;
- /*
- * Strip off the comments. XXX: this doesn't account for quoted
- * strings inside a directive. We should really strip the
- * comments in generic code, not here. While we're at it, it
- * would be better to pass the backend a series of tokens instead
- * of a raw string, and actually process quoted strings for it,
- * like of like argv is handled in C.
- */
- p = strchr(buf, ';');
- if (p) {
- if (p < q) /* ouch! somewhere inside */
- return D_corrupt;
- *p = '\0';
- }
- /* no brace, no trailing spaces */
- *q = '\0';
- nasm_zap_spaces_rev(--q);
- /* directive */
- p = nasm_skip_spaces(++buf);
- q = nasm_skip_word(p);
- if (!q)
- return D_corrupt; /* sigh... no value there */
- *q = '\0';
- *directive = p;
- /* and value finally */
- p = nasm_skip_spaces(++q);
- *value = p;
- return directive_find(*directive);
- }
- /*
- * Process a line from the assembler and try to handle it if it
- * is a directive. Return true if the line was handled (including
- * if it was an error), false otherwise.
- */
- bool process_directives(char *directive)
- {
- enum directive d;
- char *value, *p, *q, *special;
- struct tokenval tokval;
- bool bad_param = false;
- int pass2 = passn > 1 ? 2 : 1;
- enum label_type type;
- d = parse_directive_line(&directive, &value);
- switch (d) {
- case D_none:
- return D_none; /* Not a directive */
- case D_corrupt:
- nasm_error(ERR_NONFATAL, "invalid directive line");
- break;
- default: /* It's a backend-specific directive */
- switch (ofmt->directive(d, value, pass2)) {
- case DIRR_UNKNOWN:
- goto unknown;
- case DIRR_OK:
- case DIRR_ERROR:
- break;
- case DIRR_BADPARAM:
- bad_param = true;
- break;
- default:
- panic();
- }
- break;
- case D_unknown:
- unknown:
- nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC,
- "unrecognised directive [%s]", directive);
- break;
- case D_SEGMENT: /* [SEGMENT n] */
- case D_SECTION:
- {
- int sb = globalbits;
- int32_t seg = ofmt->section(value, pass2, &sb);
- if (seg == NO_SEG) {
- nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC,
- "segment name `%s' not recognized", value);
- } else {
- globalbits = sb;
- switch_segment(seg);
- }
- break;
- }
- case D_SECTALIGN: /* [SECTALIGN n] */
- {
- expr *e;
- if (*value) {
- stdscan_reset();
- stdscan_set(value);
- tokval.t_type = TOKEN_INVALID;
- e = evaluate(stdscan, NULL, &tokval, NULL, pass2, NULL);
- if (e) {
- uint64_t align = e->value;
- if (!is_power2(e->value)) {
- nasm_error(ERR_NONFATAL,
- "segment alignment `%s' is not power of two",
- value);
- } else if (align > UINT64_C(0x7fffffff)) {
- /*
- * FIXME: Please make some sane message here
- * ofmt should have some 'check' method which
- * would report segment alignment bounds.
- */
- nasm_error(ERR_NONFATAL,
- "absurdly large segment alignment `%s' (2^%d)",
- value, ilog2_64(align));
- }
- /* callee should be able to handle all details */
- if (location.segment != NO_SEG)
- ofmt->sectalign(location.segment, align);
- }
- }
- break;
- }
- case D_BITS: /* [BITS bits] */
- globalbits = get_bits(value);
- break;
- case D_GLOBAL: /* [GLOBAL|STATIC|EXTERN|COMMON symbol:special] */
- type = LBL_GLOBAL;
- goto symdef;
- case D_STATIC:
- type = LBL_STATIC;
- goto symdef;
- case D_EXTERN:
- type = LBL_EXTERN;
- goto symdef;
- case D_COMMON:
- type = LBL_COMMON;
- goto symdef;
- symdef:
- {
- bool validid = true;
- int64_t size = 0;
- char *sizestr;
- bool rn_error;
- if (*value == '$')
- value++; /* skip initial $ if present */
- q = value;
- if (!isidstart(*q)) {
- validid = false;
- } else {
- q++;
- while (*q && *q != ':' && !nasm_isspace(*q)) {
- if (!isidchar(*q))
- validid = false;
- q++;
- }
- }
- if (!validid) {
- nasm_error(ERR_NONFATAL,
- "identifier expected after %s, got `%s'",
- directive, value);
- break;
- }
- if (nasm_isspace(*q)) {
- *q++ = '\0';
- sizestr = q = nasm_skip_spaces(q);
- q = strchr(q, ':');
- } else {
- sizestr = NULL;
- }
- if (q && *q == ':') {
- *q++ = '\0';
- special = q;
- } else {
- special = NULL;
- }
- if (type == LBL_COMMON) {
- if (sizestr)
- size = readnum(sizestr, &rn_error);
- if (!sizestr || rn_error)
- nasm_error(ERR_NONFATAL,
- "%s size specified in common declaration",
- sizestr ? "invalid" : "no");
- } else if (sizestr) {
- nasm_error(ERR_NONFATAL, "invalid syntax in %s declaration",
- directive);
- }
- if (!declare_label(value, type, special))
- break;
-
- if (type == LBL_COMMON || type == LBL_EXTERN)
- define_label(value, 0, size, false);
- break;
- }
- case D_ABSOLUTE: /* [ABSOLUTE address] */
- {
- expr *e;
- stdscan_reset();
- stdscan_set(value);
- tokval.t_type = TOKEN_INVALID;
- e = evaluate(stdscan, NULL, &tokval, NULL, pass2, NULL);
- if (e) {
- if (!is_reloc(e))
- nasm_error(pass0 ==
- 1 ? ERR_NONFATAL : ERR_PANIC,
- "cannot use non-relocatable expression as "
- "ABSOLUTE address");
- else {
- absolute.segment = reloc_seg(e);
- absolute.offset = reloc_value(e);
- }
- } else if (passn == 1)
- absolute.offset = 0x100; /* don't go near zero in case of / */
- else
- nasm_panic(0, "invalid ABSOLUTE address "
- "in pass two");
- in_absolute = true;
- location.segment = NO_SEG;
- location.offset = absolute.offset;
- break;
- }
- case D_DEBUG: /* [DEBUG] */
- {
- bool badid, overlong;
- char debugid[128];
- p = value;
- q = debugid;
- badid = overlong = false;
- if (!isidstart(*p)) {
- badid = true;
- } else {
- while (*p && !nasm_isspace(*p)) {
- if (q >= debugid + sizeof debugid - 1) {
- overlong = true;
- break;
- }
- if (!isidchar(*p))
- badid = true;
- *q++ = *p++;
- }
- *q = 0;
- }
- if (badid) {
- nasm_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC,
- "identifier expected after DEBUG");
- break;
- }
- if (overlong) {
- nasm_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC,
- "DEBUG identifier too long");
- break;
- }
- p = nasm_skip_spaces(p);
- if (pass0 == 2)
- dfmt->debug_directive(debugid, p);
- break;
- }
- case D_WARNING: /* [WARNING {+|-|*}warn-name] */
- if (!set_warning_status(value)) {
- nasm_error(ERR_WARNING|WARN_UNK_WARNING,
- "unknown warning option: %s", value);
- }
- break;
- case D_CPU: /* [CPU] */
- cpu = get_cpu(value);
- break;
- case D_LIST: /* [LIST {+|-}] */
- value = nasm_skip_spaces(value);
- if (*value == '+') {
- user_nolist = false;
- } else {
- if (*value == '-') {
- user_nolist = true;
- } else {
- bad_param = true;
- }
- }
- break;
- case D_DEFAULT: /* [DEFAULT] */
- stdscan_reset();
- stdscan_set(value);
- tokval.t_type = TOKEN_INVALID;
- if (stdscan(NULL, &tokval) != TOKEN_INVALID) {
- switch (tokval.t_integer) {
- case S_REL:
- globalrel = 1;
- break;
- case S_ABS:
- globalrel = 0;
- break;
- case P_BND:
- globalbnd = 1;
- break;
- case P_NOBND:
- globalbnd = 0;
- break;
- default:
- bad_param = true;
- break;
- }
- } else {
- bad_param = true;
- }
- break;
- case D_FLOAT:
- if (float_option(value)) {
- nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC,
- "unknown 'float' directive: %s", value);
- }
- break;
- case D_PRAGMA:
- process_pragma(value);
- break;
- }
- /* A common error message */
- if (bad_param) {
- nasm_error(ERR_NONFATAL, "invalid parameter to [%s] directive",
- directive);
- }
- return d != D_none;
- }
|