From fcedfddf00b3f994e4f4e40332ac7fc192c63244 Mon Sep 17 00:00:00 2001 From: polwex Date: Sun, 5 Oct 2025 21:56:51 +0700 Subject: claude is gud --- vere/ext/nasm/asm/directiv.c | 567 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 567 insertions(+) create mode 100644 vere/ext/nasm/asm/directiv.c (limited to 'vere/ext/nasm/asm/directiv.c') diff --git a/vere/ext/nasm/asm/directiv.c b/vere/ext/nasm/asm/directiv.c new file mode 100644 index 0000000..a4f54b4 --- /dev/null +++ b/vere/ext/nasm/asm/directiv.c @@ -0,0 +1,567 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2022 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 "nctype.h" + +#include "nasm.h" +#include "nasmlib.h" +#include "ilog2.h" +#include "error.h" +#include "floats.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 void iflag_set_cpu(iflag_t *a, unsigned int lvl) +{ + a->field[0] = 0; /* Not applicable to the CPU type */ + iflag_set_all_features(a); /* All feature masking bits set for now */ + if (lvl >= IF_ANY) { + /* This is a hack for now */ + iflag_set(a, IF_LATEVEX); + } + a->field[IF_CPU_FIELD] &= ~IF_CPU_LEVEL_MASK; + iflag_set(a, lvl); +} + +void set_cpu(const char *value) +{ + const char *p; + char modifier; + const struct cpunames *cpuflag; + static const struct cpunames cpunames[] = { + { "default", IF_DEFAULT }, /* Must be first */ + { "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 }, + { "nehalem", IF_NEHALEM }, + { "westmere", IF_WESTMERE }, + { "sandybridge", IF_SANDYBRIDGE }, + { "ivybridge", IF_FUTURE }, + { "any", IF_ANY }, + { "all", IF_ANY }, + { "latevex", IF_LATEVEX }, + { "evex", IF_EVEX }, + { "vex", IF_VEX }, + { NULL, 0 } + }; + + if (!value) { + iflag_set_cpu(&cpu, cpunames[0].level); + return; + } + + p = value; + modifier = '+'; + while (*p) { + int len = strcspn(p, " ,"); + + while (len && (*p == '+' || *p == '-' || *p == '*')) { + modifier = *p++; + len--; + if (!len && modifier == '*') + cpu = cmd_cpu; + } + + if (len) { + bool invert_flag = false; + + if (len >= 3 && !nasm_memicmp(p, "no", 2)) { + invert_flag = true; + p += 2; + len -= 2; + } + + for (cpuflag = cpunames; cpuflag->name; cpuflag++) + if (!nasm_strnicmp(p, cpuflag->name, len)) + break; + + if (!cpuflag->name) { + nasm_nonfatal("unknown CPU type or flag '%.*s'", len, p); + return; + } + + if (cpuflag->level >= IF_CPU_FIRST && cpuflag->level <= IF_ANY) { + iflag_set_cpu(&cpu, cpuflag->level); + } else { + switch (modifier) { + case '-': + invert_flag = !invert_flag; + break; + case '*': + invert_flag ^= iflag_test(&cmd_cpu, cpuflag->level); + break; + default: + break; + } + + iflag_set(&cpu, cpuflag->level); + if (invert_flag) + iflag_clear(&cpu, cpuflag->level); + } + } + p += len; + if (!*p) + break; + p++; /* Skip separator */ + } +} + +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_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_nonfatal("cannot specify 64-bit segment on processor below an x86-64"); + i = 16; + } + break; + default: + nasm_nonfatal("`%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; + 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_nonfatal("invalid directive line"); + break; + + default: /* It's a backend-specific directive */ + switch (ofmt->directive(d, value)) { + 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_nonfatal("unrecognized directive [%s]", directive); + break; + + case D_SEGMENT: /* [SEGMENT n] */ + case D_SECTION: + { + int sb = globalbits; + int32_t seg = ofmt->section(value, &sb); + + if (seg == NO_SEG) { + nasm_nonfatal("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, true, NULL); + if (e) { + uint64_t align = e->value; + + if (!is_power2(e->value)) { + nasm_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_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_REQUIRED: + type = LBL_REQUIRED; + 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 (!nasm_isidstart(*q)) { + validid = false; + } else { + q++; + while (*q && *q != ':' && !nasm_isspace(*q)) { + if (!nasm_isidchar(*q)) + validid = false; + q++; + } + } + if (!validid) { + nasm_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_nonfatal("%s size specified in common declaration", + sizestr ? "invalid" : "no"); + } else if (sizestr) { + nasm_nonfatal("invalid syntax in %s declaration", directive); + } + + if (!declare_label(value, type, special)) + break; + + if (type == LBL_COMMON || type == LBL_EXTERN || type == LBL_REQUIRED) + 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, true, NULL); + if (e) { + if (!is_reloc(e)) { + nasm_nonfatal("cannot use non-relocatable expression as " + "ABSOLUTE address"); + } else { + absolute.segment = reloc_seg(e); + absolute.offset = reloc_value(e); + } + } else if (pass_first()) { + absolute.offset = 0x100; /* don't go near zero in case of / */ + } else { + nasm_nonfatal("invalid ABSOLUTE address"); + } + 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 (!nasm_isidstart(*p)) { + badid = true; + } else { + while (*p && !nasm_isspace(*p)) { + if (q >= debugid + sizeof debugid - 1) { + overlong = true; + break; + } + if (!nasm_isidchar(*p)) + badid = true; + *q++ = *p++; + } + *q = 0; + } + if (badid) { + nasm_nonfatal("identifier expected after DEBUG"); + break; + } + if (overlong) { + nasm_nonfatal("DEBUG identifier too long"); + break; + } + p = nasm_skip_spaces(p); + if (pass_final()) + dfmt->debug_directive(debugid, p); + break; + } + + case D_WARNING: /* [WARNING {push|pop|{+|-|*}warn-name}] */ + value = nasm_skip_spaces(value); + if ((*value | 0x20) == 'p') { + if (!nasm_stricmp(value, "push")) + push_warnings(); + else if (!nasm_stricmp(value, "pop")) + pop_warnings(); + } + set_warning_status(value); + break; + + case D_CPU: /* [CPU] */ + set_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_nonfatal("unknown 'float' directive: %s", value); + } + break; + + case D_PRAGMA: + process_pragma(value); + break; + } + + + /* A common error message */ + if (bad_param) { + nasm_nonfatal("invalid parameter to [%s] directive", directive); + } + + return d != D_none; +} -- cgit v1.2.3